SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(三)

简介: SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(三)

四、理解 @PathVariable

说到这了,顺便说一下 @PathVariable 注解,其用来获取请求路径(url )中的动态参数。如果@RequestMapping中表示为”item/{id}”,id和形参名称一致,@PathVariable不用指定名称。


页面发出请求:

function login() {
    var url = "${pageContext.request.contextPath}/person/login/";
    var query = $('#id').val() + '/' + $('#name').val() + '/' + $('#status').val();
    url += query;
    $.get(url, function(data) {
        alert("id: " + data.id + "name: " + data.name + "status: "
                + data.status);
    });
}
/**
* @RequestMapping(value = "user/login/{id}/{name}/{status}") 中的 {id}/{name}/{status}
* 与 @PathVariable int id、@PathVariable String name、@PathVariable boolean status
* 一一对应,按名匹配。
*/
@RequestMapping(value = "user/login/{id}/{name}/{status}")
@ResponseBody
//@PathVariable注解下的数据类型均可用
public User login(@PathVariable int id, @PathVariable String name, @PathVariable boolean status) {
//返回一个User对象响应ajax的请求
    return new User(id, name, status);
}

五、理解 HandlerMethodArgumentResolver

在初学springmvc框架时,我就一直有一个疑问,为什么controller方法上竟然可以放这么多的参数,而且都能得到想要的对象,比如HttpServletRequest或HttpServletResponse,各种注解@RequestParam、@RequestHeader、@RequestBody、@PathVariable、@ModelAttribute等。


org.springframework.web.method.support.HandlerMethodArgumentResolver接口


springmvc自带的一些实现:


ServletRequestMethodArgumentResolver和ServletResponseMethodArgumentResolver处理了自动绑定HttpServletRequest和HttpServletResponse

RequestParamMapMethodArgumentResolver处理了@RequestParam

RequestHeaderMapMethodArgumentResolver处理了@RequestHeader

PathVariableMapMethodArgumentResolver处理了@PathVariable

ModelAttributeMethodProcessor处理了@ModelAttribute

RequestResponseBodyMethodProcessor处理了@RequestBody

……

springmvc具有一个参数解析器容器RequestMappingHandlerAdapter.argumentResolvers,该参数的初始化在RequestMappingHandlerAdapter#afterPropertiesSet()。


public void afterPropertiesSet() {
    ......
    if (this.argumentResolvers == null) {
        List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    ......
}
/**
 * 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>();
    // Annotation-based argument resolution
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    resolvers.add(new PathVariableMethodArgumentResolver());
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new SessionAttributeMethodArgumentResolver());
    resolvers.add(new RequestAttributeMethodArgumentResolver());
    // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    resolvers.add(new ModelMethodProcessor());
    resolvers.add(new MapMethodProcessor());
    resolvers.add(new ErrorsMethodArgumentResolver());
    resolvers.add(new SessionStatusMethodArgumentResolver());
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }
    // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));
    return resolvers;
}

可以看出springmvc的参数解析器容器中存放着内置的参数解析器 + 自定义解析器,这里边就包括@RequestBody的解析器RequestResponseBodyMethodProcessor,来看一下这个解析器的主要方法:

@Override
public boolean supportsParameter(MethodParameter parameter) {
    return parameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
             // 这里使用MappingJackson2HttpMessageConverter将输入流body体中的转化为Book对象
}

相关API:

image.png


作用:


SpringMVC解析器用于解析request请求参数并绑定数据到Controller的入参上。


自定义一个参数解析器需要实现HandlerMethodArgumentResolver接口,重写supportsParameter和resolveArgument方法,配置文件中加入resolver配置。


如果需要多个解析器同时生效需要在一个解析器中对其他解析器做兼容。


由来:


如果前端对某个不要入参做了加密操作,后端接收到该参数后,都需要进行解密操作。


针对这种需求,首先想到的是filter或者interceptor实现,但是由于HttpServletRequest对象本身是不提供setParameter()方法的,因此想要修改request中的参数值为decode后的值是不易达到的。


SpringMVC的HandlerMethodArgumentResolver,解析器;其功能就是解析request请求参数并绑定数据到Controller的入参上。


注意:


1、一个参数解析器最重要的方法有两个:

(1)supportsParameter 指定哪些参数使用该解析器进行解析,用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument。

(2)resolveArgument 对参数进行真正的解析操作,真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。


这也是自定义参数解析器需要去实现的两个方法。


2、在解析器容器中,自定义解析器是位于内置解析器之后,这个顺序也是解析器的优先级,也就是说假设有一个参数同时满足两个解析器,只有第一个解析器会生效,那么怎么去调整这个解析器的顺序呢?


好,现在,我们已经大致了解了springmvc的参数解析器,以及@RequestBody的解析过程。那么来看一下这个例子:


@RequestMapping(value = "/two-body", method = RequestMethod.POST)
public Book testCommon(@RequestBody Book book1, @RequestBody Book book2) {
    Book book = new Book();
    book.setId(Optional.ofNullable(book1).orElse(book2).getId());
    book.setName(Optional.ofNullable(book1).orElse(book2).getName());
    return book;
}
目录
相关文章
|
4月前
SpringMVC常见组件之HandlerMethodArgumentResolver解析-2
SpringMVC常见组件之HandlerMethodArgumentResolver解析-2
28 0
|
4月前
|
算法 Java API
SpringMVC常见组件之HandlerMethodArgumentResolver解析-1
SpringMVC常见组件之HandlerMethodArgumentResolver解析-1
46 0
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(七)
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(七)
105 0
|
XML Java 数据格式
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(六)
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(六)
90 0
|
XML Java 数据格式
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(五)
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(五)
129 0
|
JSON Dubbo Java
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(四)
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(四)
265 0
|
XML JSON Java
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(二)
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(二)
108 0
|
JSON 前端开发 JavaScript
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(一)
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(一)
249 0
SpringMVC - @RequestJson之HandlerMethodArgumentResolver 从入门到青铜(一)
|
缓存 数据格式 Java
SpringMVC之分析HandlerMethodArgumentResolver请求对应处理器方法参数的解析过程(一)
在我们做Web开发的时候,会提交各种数据格式的请求,而我们的后台也会有相应的参数处理方式。SpringMVC就为我们提供了一系列的参数解析器,不管你是要获取Cookie中的值,Header中的值,JSON格式的数据,URI中的值。
2365 0
SpringMVC之分析HandlerMethodArgumentResolver请求对应处理器方法参数的解析过程(二)
在上一篇文章中我们分析了SpringMVC对简单对象和@RequestParam注解的解析过程,这一章中我们继续分析其他形式的参数解析过程。 ServletRequestMethodArgumentResolver 下面来看一下我们的第一个请...
1388 0