SpringMVC 中的参数组装:HandlerMethodArgumentResolver
SpringMVC3.1 引入了 HandlerMethodArgumentResolver 接口,Spring 调用该接口实现 Controller 的参数装配。HandlerMethodArgumentResolver 实现类中会调用 DataBinder,Converter 等。
由于之前用 @RequestParam 无法接受 request payload 正文格式为 json 格式的字符串,只能使用 @RequestBody 整个接收,觉得麻烦,但是 Spring 自带的参数解析器不具有这种功能,只能尝试着用自定义参数解析器去解决。
常用的该接口实现类有:
ServletModelAttributeMethodProcessor:实体类的组装用它实现。
RequestParamMethodArgumentResolver:基本数据类型如 String 用它实现。
自定义解析器需要实现 HandlerMethodArgumentResolver 接口,HandlerMethodArgumentResolver接口包含两个方法:
supportsParameter:用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument。resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。
自定义注解
package com.manqian.crm.resolver;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)public @interface JsonParam {String value();boolean required() default true;String defaultValue() default "";}
若不想自定义注解,可以直接在实现 HandlerMethodArgumentResolver 的 supportsParameter 直接返回 true。
自定义参数解析器
实现 HandlerMethodArgumentResolver 接口
import com.jayway.jsonpath.JsonPath;import com.jayway.jsonpath.PathNotFoundException;import com.manqian.crm.api.exception.ParamCheckException;import org.apache.commons.io.IOUtils;import org.springframework.context.annotation.Configuration;import org.springframework.core.MethodParameter;import org.springframework.web.bind.support.WebDataBinderFactory;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.method.support.ModelAndViewContainer;import javax.servlet.http.HttpServletRequest;import java.io.IOException;public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver {private static final String JSON_REQUEST_BODY = "JSON_REQUEST_BODY";//判断是否支持要转换的参数类型@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(JsonParam.class);}//当支持后进行相应的转换@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {String body = getRequestBody(webRequest);Object val = null;try {val = JsonPath.read(body, parameter.getParameterAnnotation(JsonParam.class).value());if (parameter.getParameterAnnotation(JsonParam.class).required() && val == null) {throw new ParamCheckException(parameter.getParameterAnnotation(JsonParam.class).value() + "不能为空");}} catch (PathNotFoundException exception) {System.out.println(exception.getStackTrace());if (parameter.getParameterAnnotation(JsonParam.class).required()) {// throw new ParamCheckException(parameter.getParameterAnnotation(JsonParam.class).value() + "不能为空");throw exception;}}return val;}private String getRequestBody(NativeWebRequest webRequest) {HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);String jsonBody = (String) servletRequest.getAttribute(JSON_REQUEST_BODY);if (jsonBody == null) {try {jsonBody = IOUtils.toString(servletRequest.getInputStream());servletRequest.setAttribute(JSON_REQUEST_BODY, jsonBody);} catch (IOException e) {throw new RuntimeException(e);}}return jsonBody;}}
注册自定义参数解析器
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;import com.demo.mvc.component.MultiPersonArgumentResolver;import com.demo.mvc.component.PersonArgumentResolver;@SpringBootApplicationpublic class WebMvcConfiguration extends WebMvcConfigurationSupport {@Overrideprotected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// 注册JsonPathArgumentResolver的参数分解器argumentResolvers.add(new JsonPathArgumentResolver());}}
方式二:
import org.springframework.context.annotation.Configuration;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import java.util.List;@Configurationpublic class ClientResourcesConfig extends WebMvcConfigurerAdapter {@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// super.addArgumentResolvers(argumentResolvers);argumentResolvers.add(new JsonPathArgumentResolver());}}
在新版 Spring Boot 中已经将 WebMvcConfigurerAdapter 标记为过时,可参考方式三。也可以查看Spring Boot WebMvcConfigurerAdapte 方法已经过时解决方法。
方式三:
import org.springframework.context.annotation.Configuration;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configurationpublic class ClientResourcesConfig implements WebMvcConfigurer {@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {argumentResolvers.add(new JsonPathArgumentResolver());}}
传统XML格式
方式一:
<mvc:annotation-driven><mvc:argument-resolvers><bean class="com.manqian.crm.resolver.JsonPathArgumentResolver"/></mvc:argument-resolvers></mvc:annotation-driven>
方式二:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="jsonPathArgumentResolver"><bean class="com.manqian.crm.resolver.JsonPathArgumentResolver"/></property></bean>
依赖
com.jayway.jsonpath
json-path
拓展实例:获取用户信息
import org.springframework.core.MethodParameter;import org.springframework.lang.Nullable;import org.springframework.stereotype.Component;import org.springframework.web.bind.support.WebDataBinderFactory;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.method.support.ModelAndViewContainer;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;/*** @author yeskery* @date 2018/06/02*/@Componentpublic class UserArgumentResolver implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {if (methodParameter.getParameterType() == User.class) {return true;}return false;}@Nullable@Overridepublic Object resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, @Nullable WebDataBinderFactory webDataBinderFactory) throws Exception {HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);HttpSession session = request.getSession();Object user = session.getAttribute("user");return user;}}
本文部分内容来自:https://blog.csdn.net/u010187242/article/details/73647670
评论