绑定Spring MVC命令对象时如何自定义参数名称?
Posted
技术标签:
【中文标题】绑定Spring MVC命令对象时如何自定义参数名称?【英文标题】:How to customize parameter names when binding Spring MVC command objects? 【发布时间】:2012-02-17 16:27:12 【问题描述】:我有一个命令对象:
public class Job
private String jobType;
private String location;
哪个是spring-mvc绑定的:
@RequestMapping("/foo")
public String doSomethingWithJob(Job job)
...
这适用于http://example.com/foo?jobType=permanent&location=Stockholm
。但现在我需要让它适用于以下网址:
http://example.com/foo?jt=permanent&loc=Stockholm
显然,我不想更改我的命令对象,因为字段名称必须保持很长(因为它们在代码中使用)。我该如何定制呢?有没有办法做这样的事情:
public class Job
@RequestParam("jt")
private String jobType;
@RequestParam("loc")
private String location;
这不起作用(@RequestParam
不能应用于字段)。
我正在考虑的是一个类似于FormHttpMessageConverter
的自定义消息转换器并读取目标对象上的自定义注释
【问题讨论】:
Spring 4 中没有一些“原生”解决方案吗? 请帮忙解决我的类似问题***.com/questions/38171022/… 【参考方案1】:这个解决方案更简洁,但需要使用 RequestMappingHandlerAdapter,Spring 在启用<mvc:annotation-driven />
时使用它。
希望它会帮助某人。
这个想法是像这样扩展 ServletRequestDataBinder:
/**
* ServletRequestDataBinder which supports fields renaming using @link ParamName
*
* @author jkee
*/
public class ParamNameDataBinder extends ExtendedServletRequestDataBinder
private final Map<String, String> renameMapping;
public ParamNameDataBinder(Object target, String objectName, Map<String, String> renameMapping)
super(target, objectName);
this.renameMapping = renameMapping;
@Override
protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request)
super.addBindValues(mpvs, request);
for (Map.Entry<String, String> entry : renameMapping.entrySet())
String from = entry.getKey();
String to = entry.getValue();
if (mpvs.contains(from))
mpvs.add(to, mpvs.getPropertyValue(from).getValue());
适当的处理器:
/**
* Method processor supports @link ParamName parameters renaming
*
* @author jkee
*/
public class RenamingProcessor extends ServletModelAttributeMethodProcessor
@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
//Rename cache
private final Map<Class<?>, Map<String, String>> replaceMap = new ConcurrentHashMap<Class<?>, Map<String, String>>();
public RenamingProcessor(boolean annotationNotRequired)
super(annotationNotRequired);
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest nativeWebRequest)
Object target = binder.getTarget();
Class<?> targetClass = target.getClass();
if (!replaceMap.containsKey(targetClass))
Map<String, String> mapping = analyzeClass(targetClass);
replaceMap.put(targetClass, mapping);
Map<String, String> mapping = replaceMap.get(targetClass);
ParamNameDataBinder paramNameDataBinder = new ParamNameDataBinder(target, binder.getObjectName(), mapping);
requestMappingHandlerAdapter.getWebBindingInitializer().initBinder(paramNameDataBinder, nativeWebRequest);
super.bindRequestParameters(paramNameDataBinder, nativeWebRequest);
private static Map<String, String> analyzeClass(Class<?> targetClass)
Field[] fields = targetClass.getDeclaredFields();
Map<String, String> renameMap = new HashMap<String, String>();
for (Field field : fields)
ParamName paramNameAnnotation = field.getAnnotation(ParamName.class);
if (paramNameAnnotation != null && !paramNameAnnotation.value().isEmpty())
renameMap.put(paramNameAnnotation.value(), field.getName());
if (renameMap.isEmpty()) return Collections.emptyMap();
return renameMap;
注释:
/**
* Overrides parameter name
* @author jkee
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ParamName
/**
* The name of the request parameter to bind to.
*/
String value();
弹簧配置:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="ru.yandex.metrika.util.params.RenamingProcessor">
<constructor-arg name="annotationNotRequired" value="true"/>
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
最后,用法(如 Bozho 解决方案):
public class Job
@ParamName("job-type")
private String jobType;
@ParamName("loc")
private String location;
【讨论】:
非常感谢您的解决方案!注意:这保留了DateTimeFormat
注释的功能,即@ParamName
带注释的Date
字段可以另外用@DateTimeFormat(pattern = "yyyy-MM-dd")
注释。
对于所有 Java 配置爱好者来说,Java 中的 Spring 上下文配置如下所示:@Configuration public class WebContextConfiguration extends WebMvcConfigurationSupport @Override protected void addArgumentResolvers( List<HandlerMethodArgumentResolver> argumentResolvers) argumentResolvers.add(renamingProcessor()); @Bean protected RenamingProcessor renamingProcessor() return new RenamingProcessor(true);
请注意,extends WebMvcConfigurationSupport
替换了 @EnableWebMvc
和 <mvc:annotation-driven />
。
请帮忙解决我的类似问题***.com/questions/38171022/…
从 spring 4.2 开始有什么可以帮助使这更容易吗?
我已经通过将addArgumentResolvers
替换为 bean 后处理器:pastebin.com/07ws0uUZ【参考方案2】:
这是我的工作:
一、参数解析器:
/**
* This resolver handles command objects annotated with @SupportsAnnotationParameterResolution
* that are passed as parameters to controller methods.
*
* It parses @CommandPerameter annotations on command objects to
* populate the Binder with the appropriate values (that is, the filed names
* corresponding to the GET parameters)
*
* In order to achieve this, small pieces of code are copied from spring-mvc
* classes (indicated in-place). The alternative to the copied lines would be to
* have a decorator around the Binder, but that would be more tedious, and still
* some methods would need to be copied.
*
* @author bozho
*
*/
public class AnnotationServletModelAttributeResolver extends ServletModelAttributeMethodProcessor
/**
* A map caching annotation definitions of command objects (@CommandParameter-to-fieldname mappings)
*/
private ConcurrentMap<Class<?>, Map<String, String>> definitionsCache = Maps.newConcurrentMap();
public AnnotationServletModelAttributeResolver(boolean annotationNotRequired)
super(annotationNotRequired);
@Override
public boolean supportsParameter(MethodParameter parameter)
if (parameter.getParameterType().isAnnotationPresent(SupportsAnnotationParameterResolution.class))
return true;
return false;
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request)
ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
bind(servletRequest, servletBinder);
@SuppressWarnings("unchecked")
public void bind(ServletRequest request, ServletRequestDataBinder binder)
Map<String, ?> propertyValues = parsePropertyValues(request, binder);
MutablePropertyValues mpvs = new MutablePropertyValues(propertyValues);
MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
if (multipartRequest != null)
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
// two lines copied from ExtendedServletRequestDataBinder
String attr = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
mpvs.addPropertyValues((Map<String, String>) request.getAttribute(attr));
binder.bind(mpvs);
private Map<String, ?> parsePropertyValues(ServletRequest request, ServletRequestDataBinder binder)
// similar to WebUtils.getParametersStartingWith(..) (prefixes not supported)
Map<String, Object> params = Maps.newTreeMap();
Assert.notNull(request, "Request must not be null");
Enumeration<?> paramNames = request.getParameterNames();
Map<String, String> parameterMappings = getParameterMappings(binder);
while (paramNames != null && paramNames.hasMoreElements())
String paramName = (String) paramNames.nextElement();
String[] values = request.getParameterValues(paramName);
String fieldName = parameterMappings.get(paramName);
// no annotation exists, use the default - the param name=field name
if (fieldName == null)
fieldName = paramName;
if (values == null || values.length == 0)
// Do nothing, no values found at all.
else if (values.length > 1)
params.put(fieldName, values);
else
params.put(fieldName, values[0]);
return params;
/**
* Gets a mapping between request parameter names and field names.
* If no annotation is specified, no entry is added
* @return
*/
private Map<String, String> getParameterMappings(ServletRequestDataBinder binder)
Class<?> targetClass = binder.getTarget().getClass();
Map<String, String> map = definitionsCache.get(targetClass);
if (map == null)
Field[] fields = targetClass.getDeclaredFields();
map = Maps.newHashMapWithExpectedSize(fields.length);
for (Field field : fields)
CommandParameter annotation = field.getAnnotation(CommandParameter.class);
if (annotation != null && !annotation.value().isEmpty())
map.put(annotation.value(), field.getName());
definitionsCache.putIfAbsent(targetClass, map);
return map;
else
return map;
/**
* Copied from WebDataBinder.
*
* @param multipartFiles
* @param mpvs
*/
protected void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, MutablePropertyValues mpvs)
for (Map.Entry<String, List<MultipartFile>> entry : multipartFiles.entrySet())
String key = entry.getKey();
List<MultipartFile> values = entry.getValue();
if (values.size() == 1)
MultipartFile value = values.get(0);
if (!value.isEmpty())
mpvs.add(key, value);
else
mpvs.add(key, values);
然后使用后处理器注册参数解析器。应该注册为<bean>
:
/**
* Post-processor to be used if any modifications to the handler adapter need to be made
*
* @author bozho
*
*/
public class AnnotationHandlerMappingPostProcessor implements BeanPostProcessor
@Override
public Object postProcessAfterInitialization(Object bean, String arg1)
throws BeansException
return bean;
@Override
public Object postProcessBeforeInitialization(Object bean, String arg1)
throws BeansException
if (bean instanceof RequestMappingHandlerAdapter)
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodArgumentResolver> resolvers = adapter.getCustomArgumentResolvers();
if (resolvers == null)
resolvers = Lists.newArrayList();
resolvers.add(new AnnotationServletModelAttributeResolver(false));
adapter.setCustomArgumentResolvers(resolvers);
return bean;
【讨论】:
如果有一个完整的例子会很有帮助,因为我无法构建上面的例子。 请帮忙解决我的类似问题***.com/questions/38171022/… 这个不完整的代码怎么会是公认的答案?它缺少几个类,如SupportsAnnotationParameterResolution
、@CommandPattern
和 @SupportsCustomizedBinding
,以及 Maps.*
和 Lists.*
的导入
好的,SupportsAnnotationParameterResolution 改成SupportsCustomizedBinding
。因此,在创建两个注释时,该方法有效!【参考方案3】:
在 Spring 3.1 中,ServletRequestDataBinder 为附加绑定值提供了一个钩子:
protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request)
ExtendedServletRequestDataBinder 子类使用它来添加 URI 模板变量作为绑定值。您可以进一步扩展它以添加特定于命令的字段别名。
您可以覆盖 RequestMappingHandlerAdapter.createDataBinderFactory(..) 以提供自定义 WebDataBinder 实例。从控制器的角度来看,它可能如下所示:
@InitBinder
public void initBinder(MyWebDataBinder binder)
binder.addFieldAlias("jobType", "jt");
// ...
【讨论】:
谢谢,但是如果我需要重写.createDtaBinderFactory,这意味着我应该替换RequestMappingHandlerAdapter,也就是说我不能使用<mvc:annotation-driven />
,对吧?
不客气。是的,使用 你不能插入自定义的 RequestMappingHandlerMapping。但是,您可以使用 MVC Java 配置轻松完成。
@RossenStoyanchev:你能解释一下如何用@EnableWebMvc
插入自定义MyWebDataBinder
吗?我看到我必须继承 ExtendedServletRequestDataBinder
并通过继承 ServletRequestDataBinderFactory
来返回它。现在我可以通过继承RequestMappingHandlerAdapter
并覆盖createDataBinderFactory()
来返回这个新工厂。但是如何强制 Spring MVC 使用我的子类RequestMappingHandlerAdapter
?它创建于WebMvcConfigurationSupport
...
@TomaszNurkiewicz,也许你已经明白了,但如果没有看到参考文档中关于基于 XML 的 Spring MVC 配置的高级 Java 部分.. static.springsource.org/spring/docs/3.1.x/…
@RossenStoyanchev:实际上并不紧急,但感谢您的建议,它终于奏效了,+1!【参考方案4】:
感谢@jkee 的回答。 这是我的解决方案。 一、自定义注解:
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamName
/**
* The name of the request parameter to bind to.
*/
String value();
客户DataBinder:
public class ParamNameDataBinder extends ExtendedServletRequestDataBinder
private final Map<String, String> paramMappings;
public ParamNameDataBinder(Object target, String objectName, Map<String, String> paramMappings)
super(target, objectName);
this.paramMappings = paramMappings;
@Override
protected void addBindValues(MutablePropertyValues mutablePropertyValues, ServletRequest request)
super.addBindValues(mutablePropertyValues, request);
for (Map.Entry<String, String> entry : paramMappings.entrySet())
String paramName = entry.getKey();
String fieldName = entry.getValue();
if (mutablePropertyValues.contains(paramName))
mutablePropertyValues.add(fieldName, mutablePropertyValues.getPropertyValue(paramName).getValue());
参数解析器:
public class ParamNameProcessor extends ServletModelAttributeMethodProcessor
@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
private static final Map<Class<?>, Map<String, String>> PARAM_MAPPINGS_CACHE = new ConcurrentHashMap<>(256);
public ParamNameProcessor()
super(false);
@Override
public boolean supportsParameter(MethodParameter parameter)
return parameter.hasParameterAnnotation(RequestParam.class)
&& !BeanUtils.isSimpleProperty(parameter.getParameterType())
&& Arrays.stream(parameter.getParameterType().getDeclaredFields())
.anyMatch(field -> field.getAnnotation(ParamName.class) != null);
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest nativeWebRequest)
Object target = binder.getTarget();
Map<String, String> paramMappings = this.getParamMappings(target.getClass());
ParamNameDataBinder paramNameDataBinder = new ParamNameDataBinder(target, binder.getObjectName(), paramMappings);
requestMappingHandlerAdapter.getWebBindingInitializer().initBinder(paramNameDataBinder, nativeWebRequest);
super.bindRequestParameters(paramNameDataBinder, nativeWebRequest);
/**
* Get param mappings.
* Cache param mappings in memory.
*
* @param targetClass
* @return @link Map<String, String>
*/
private Map<String, String> getParamMappings(Class<?> targetClass)
if (PARAM_MAPPINGS_CACHE.containsKey(targetClass))
return PARAM_MAPPINGS_CACHE.get(targetClass);
Field[] fields = targetClass.getDeclaredFields();
Map<String, String> paramMappings = new HashMap<>(32);
for (Field field : fields)
ParamName paramName = field.getAnnotation(ParamName.class);
if (paramName != null && !paramName.value().isEmpty())
paramMappings.put(paramName.value(), field.getName());
PARAM_MAPPINGS_CACHE.put(targetClass, paramMappings);
return paramMappings;
最后,将 ParamNameProcessor 添加到第一个参数解析器中的 bean 配置:
@Configuration
public class WebConfig
/**
* Processor for annotation @link ParamName.
*
* @return ParamNameProcessor
*/
@Bean
protected ParamNameProcessor paramNameProcessor()
return new ParamNameProcessor();
/**
* Custom @link BeanPostProcessor for adding @link ParamNameProcessor into the first of
* @link RequestMappingHandlerAdapter#argumentResolvers.
*
* @return BeanPostProcessor
*/
@Bean
public BeanPostProcessor beanPostProcessor()
return new BeanPostProcessor()
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
return bean;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
if (bean instanceof RequestMappingHandlerAdapter)
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(adapter.getArgumentResolvers());
argumentResolvers.add(0, paramNameProcessor());
adapter.setArgumentResolvers(argumentResolvers);
return bean;
;
参数 pojo:
@Data
public class Foo
private Integer id;
@ParamName("first_name")
private String firstName;
@ParamName("last_name")
private String lastName;
@ParamName("created_at")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createdAt;
控制器方法:
@GetMapping("/foos")
public ResponseEntity<List<Foo>> listFoos(@RequestParam Foo foo, @PageableDefault(sort = "id") Pageable pageable)
List<Foo> foos = fooService.listFoos(foo, pageable);
return ResponseEntity.ok(foos);
就是这样。
【讨论】:
这与@jkee 贡献的内容有何不同?【参考方案5】:有一个简单的方法,你可以多加一个setter方法,比如“setLoc,setJt”。
【讨论】:
带连字符的参数怎么样? Spring 如何自动转换这些?【参考方案6】:没有很好的内置方法可以做到这一点,您只能选择您应用的解决方法。处理的区别
@RequestMapping("/foo")
public String doSomethingWithJob(Job job)
和
@RequestMapping("/foo")
public String doSomethingWithJob(String stringjob)
那个job是一个bean而stringjob不是(到目前为止并不奇怪)。真正的区别在于,bean 是使用标准 Spring bean 解析器机制解析的,而字符串参数是由知道 @RequestParam 注释概念的 Spring MVC 解析的。长话短说,标准 Spring bean 解析(即使用 PropertyValues、PropertyValue、GenericTypeAwarePropertyDescriptor 等类)无法将“jt”解析为名为“jobType”的属性,或者至少我不知道它。
解决方法可以像其他人建议的那样添加自定义 PropertyEditor 或过滤器,但我认为它只会弄乱代码。在我看来,最干净的解决方案是声明一个这样的类:
public class JobParam extends Job
public String getJt()
return super.job;
public void setJt(String jt)
super.job = jt;
然后在你的控制器中使用它
@RequestMapping("/foo")
public String doSomethingWithJob(JobParam job)
...
更新:
一个稍微简单的选项是不扩展,只需将额外的getter,setter添加到原始类中
public class Job
private String jobType;
private String location;
public String getJt()
return jobType;
public void setJt(String jt)
jobType = jt;
【讨论】:
@Bozho 是的,它不是太复杂,但至少易于阅读:)(我用简化的解决方案更新了原始帖子) 保持简单,是啊.. 可惜spring不支持任何开箱即用的东西=( 那并没有解决原来的问题。即使用 Spring 将包含连字符“job-type”的参数自动转换为 DTO【参考方案7】:我想为您指出另一个方向。 但我不知道它是否有效。
我会尝试操纵绑定本身。
它由WebDataBinder
完成,将从HandlerMethodInvoker
方法Object[] resolveHandlerArguments(Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception
调用
我对 Spring 3.1 没有深入了解,但是我看到的是 Spring 的这部分已经发生了很大的变化。所以有可能交换WebDataBinder。在 Spring 3.0 中,如果不覆盖 HandlerMethodInvoker
,就不可能接缝。
【讨论】:
是的,这就是我现在正在调查的地方。我想我有一个可行的解决方案,我将在明天进行测试【参考方案8】:您可以使用 Jackson com.fasterxml.jackson.databind.ObjectMapper 将任何地图转换为具有嵌套道具的 DTO/POJO 类。您需要在嵌套对象上使用 @JsonUnwrapped 注释您的 POJO。像这样:
public class MyRequest
@JsonUnwrapped
private NestedObject nested;
public NestedObject getNested()
return nested;
比这样使用它:
@RequestMapping(method = RequestMethod.GET, value = "/myMethod")
@ResponseBody
public Object myMethod(@RequestParam Map<String, Object> allRequestParams)
MyRequest request = new ObjectMapper().convertValue(allRequestParams, MyRequest.class);
...
就是这样。一点编码。此外,您可以为您的道具命名使用@JsonProperty。
【讨论】:
【参考方案9】:尝试使用InterceptorAdaptor
拦截请求,然后使用简单的检查机制决定是否将请求转发给控制器处理程序。还要将 HttpServletRequestWrapper
包裹在请求周围,以使您能够覆盖请求 getParameter()
。
通过这种方式,您可以将实际参数名称及其值重新传递回请求以供控制器查看。
示例选项:
public class JobInterceptor extends HandlerInterceptorAdapter
private static final String requestLocations[]="rt", "jobType";
private boolean isEmpty(String arg)
return (arg !=null && arg.length() > 0);
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception
//Maybe something like this
if(!isEmpty(request.getParameter(requestLocations[0]))|| !isEmpty(request.getParameter(requestLocations[1]))
final String value =
!isEmpty(request.getParameter(requestLocations[0])) ? request.getParameter(requestLocations[0]) : !isEmpty(request
.getParameter(requestLocations[1])) ? request.getParameter(requestLocations[1]) : null;
HttpServletRequest wrapper = new HttpServletRequestWrapper(request)
public String getParameter(String name)
super.getParameterMap().put("JobType", value);
return super.getParameter(name);
;
//Accepted request - Handler should carry on.
return super.preHandle(request, response, handler);
//Ignore request if above condition was false
return false;
最后将HandlerInterceptorAdaptor
包裹在您的控制器处理程序周围,如下所示。 SelectedAnnotationHandlerMapping
允许您指定将接收哪个处理程序。
<bean id="jobInterceptor" class="mypackage.JobInterceptor"/>
<bean id="publicMapper" class="org.springplugins.web.SelectedAnnotationHandlerMapping">
<property name="urls">
<list>
<value>/foo</value>
</list>
</property>
<property name="interceptors">
<list>
<ref bean="jobInterceptor"/>
</list>
</property>
</bean>
已编辑。
【讨论】:
目标方法只是1,它接受一个Job对象作为参数。这些字符串是参数,而不是位置 handler 方法采用 Job 对象,该对象与preHandle
方法持有的对象相同。因此,如上所示检查您的请求参数并返回 true 将导致控制器处理程序继续处理请求。
我已经编辑了帖子以展示如何拦截您的作业处理程序。
仍然,如何在 Job 对象上设置正确的参数?
查看已编辑的答案 - 这可能会有所帮助。将“HttpServletRequestWrapper”包裹在请求周围,使您能够重新传递参数名称和与其关联的值。【参考方案10】:
jkee 的回答有一点改进。
为了支持继承,您还应该分析父类。
/**
* ServletRequestDataBinder which supports fields renaming using @link ParamName
*
* @author jkee
* @author Yauhen Parmon
*/
public class ParamRenamingProcessor extends ServletModelAttributeMethodProcessor
@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
//Rename cache
private final Map<Class<?>, Map<String, String>> replaceMap = new ConcurrentHashMap<>();
public ParamRenamingProcessor(boolean annotationNotRequired)
super(annotationNotRequired);
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest nativeWebRequest)
Object target = binder.getTarget();
Class<?> targetClass = Objects.requireNonNull(target).getClass();
if (!replaceMap.containsKey(targetClass))
replaceMap.put(targetClass, analyzeClass(targetClass));
Map<String, String> mapping = replaceMap.get(targetClass);
ParamNameDataBinder paramNameDataBinder = new ParamNameDataBinder(target, binder.getObjectName(), mapping);
Objects.requireNonNull(requestMappingHandlerAdapter.getWebBindingInitializer())
.initBinder(paramNameDataBinder);
super.bindRequestParameters(paramNameDataBinder, nativeWebRequest);
private Map<String, String> analyzeClass(Class<?> targetClass)
Map<String, String> renameMap = new HashMap<>();
for (Field field : targetClass.getDeclaredFields())
ParamName paramNameAnnotation = field.getAnnotation(ParamName.class);
if (paramNameAnnotation != null && !paramNameAnnotation.value().isEmpty())
renameMap.put(paramNameAnnotation.value(), field.getName());
if (targetClass.getSuperclass() != Object.class)
renameMap.putAll(analyzeClass(targetClass.getSuperclass()));
return renameMap;
此处理器将分析带有@ParamName 注释的超类字段。它也不使用带有 2 个参数的 initBinder
方法,从 Spring 5.0 开始不推荐使用。 jkee的答案中的所有其余部分都可以。
【讨论】:
以上是关于绑定Spring MVC命令对象时如何自定义参数名称?的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC 学习笔记 2.1《自定参数解析 HandlerMethodArgumentResolver》
Spring MVC 学习笔记 2.1《自定参数解析 HandlerMethodArgumentResolver》
Spring MVC自定义类型转换器Converter参数解析器HandlerMethodArgumentResolver