三、将自定义参数解析器设置到spring的参数解析器集合中
XML配置1
<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="com.luxsuen.requestjson.resolver.RequestJsonHandlerMethodArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
或XML配置2
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="customArgumentResolvers"> <bean class="com.luxsuen.requestjson.resolver.RequestJsonHandlerMethodArgumentResolver"/> </property> </bean>
或SpringBoot配置
import java.util.List; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; @SpringBootApplication public class WebMvcConfiguration extends WebMvcConfigurationSupport { @Override protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { // 注册自定义的参数分解器 argumentResolvers.add(new RequestJsonHandlerMethodArgumentResolver()); } }
通过上述这种方式,我们就将自定义的RequestJsonHandlerMethodArgumentResolver解析器添加到了spring的自定义参数解析器集合中。
此时,一个自定义的参数注解就可以基本使用在我们的项目中了。
四、指定参数解析器的“优先级”
通过前边的步骤,一个自定义的参数注解就“基本”可以使用了,但是还有一个问题。看这个例子。
@RequestMapping(value = "/map", method = RequestMethod.POST) public Map<String, Book> testMap(@RequestJson(value = "title2Book") Map<String, Book> title2Book) { return title2Book; }
在RequestJsonHandlerMethodArgumentResolver#supportsParameter方法中打断点来debug一下,发现上边这个例子根本不会走进去,也就是说此时我们自定义的RequestJsonHandlerMethodArgumentResolver不再起作用了。
原因:在springmvc的解析器容器中,自定义解析器是放在内置解析器之后的,这个顺序也是解析器的优先级,也就是说假设有一个参数同时满足两个解析器,只有第一个解析器会生效。而springmvc对Map是专门有一个内置解析器的,这个解析器位于我们的RequestJsonHandlerMethodArgumentResolver之前,所以springmvc会使用Map解析器进行解析,而不再使用RequestJsonHandlerMethodArgumentResolver。
具体源码我们再翻回头看一下“一”中的getDefaultArgumentResolvers:
/** * Return the list of argument resolvers to use including built-in resolvers * and custom resolvers provided via {@link #setCustomArgumentResolvers}. */ private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); ... //Map解析器 resolvers.add(new MapMethodProcessor()); ... // 自定义解析器 if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } return resolvers; }
再看一下MapMethodProcessor#supportsParameter。
@Override public boolean supportsParameter(MethodParameter parameter) { return Map.class.isAssignableFrom(parameter.getParameterType()); }
原因明了了以后,就要去想解决方案。(如果spring可以提供为参数解析器设置order的能力,那么就好了,但是spring没有提供,这也就是为什么在这“优先级”这里打了个引号的原因)。