yeskery

SpringMVC 中的参数组装:HandlerMethodArgumentResolver

SpringMVC3.1 引入了 HandlerMethodArgumentResolver 接口,Spring 调用该接口实现 Controller 的参数装配。HandlerMethodArgumentResolver 实现类中会调用 DataBinderConverter 等。

由于之前用 @RequestParam 无法接受 request payload 正文格式为 json 格式的字符串,只能使用 @RequestBody 整个接收,觉得麻烦,但是 Spring 自带的参数解析器不具有这种功能,只能尝试着用自定义参数解析器去解决。

常用的该接口实现类有:

ServletModelAttributeMethodProcessor:实体类的组装用它实现。

RequestParamMethodArgumentResolver:基本数据类型如 String 用它实现。

自定义解析器需要实现 HandlerMethodArgumentResolver 接口,HandlerMethodArgumentResolver接口包含两个方法:

  • supportsParameter:用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument。

  • resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。

自定义注解

  1. package com.manqian.crm.resolver;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Target(ElementType.PARAMETER)
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface JsonParam {
  9. String value();
  10. boolean required() default true;
  11. String defaultValue() default "";
  12. }

若不想自定义注解,可以直接在实现 HandlerMethodArgumentResolversupportsParameter 直接返回 true。

自定义参数解析器

实现 HandlerMethodArgumentResolver 接口

  1. import com.jayway.jsonpath.JsonPath;
  2. import com.jayway.jsonpath.PathNotFoundException;
  3. import com.manqian.crm.api.exception.ParamCheckException;
  4. import org.apache.commons.io.IOUtils;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.core.MethodParameter;
  7. import org.springframework.web.bind.support.WebDataBinderFactory;
  8. import org.springframework.web.context.request.NativeWebRequest;
  9. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  10. import org.springframework.web.method.support.ModelAndViewContainer;
  11. import javax.servlet.http.HttpServletRequest;
  12. import java.io.IOException;
  13. public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver {
  14. private static final String JSON_REQUEST_BODY = "JSON_REQUEST_BODY";
  15. //判断是否支持要转换的参数类型
  16. @Override
  17. public boolean supportsParameter(MethodParameter parameter) {
  18. return parameter.hasParameterAnnotation(JsonParam.class);
  19. }
  20. //当支持后进行相应的转换
  21. @Override
  22. public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
  23. String body = getRequestBody(webRequest);
  24. Object val = null;
  25. try {
  26. val = JsonPath.read(body, parameter.getParameterAnnotation(JsonParam.class).value());
  27. if (parameter.getParameterAnnotation(JsonParam.class).required() && val == null) {
  28. throw new ParamCheckException(parameter.getParameterAnnotation(JsonParam.class).value() + "不能为空");
  29. }
  30. } catch (PathNotFoundException exception) {
  31. System.out.println(exception.getStackTrace());
  32. if (parameter.getParameterAnnotation(JsonParam.class).required()) {
  33. // throw new ParamCheckException(parameter.getParameterAnnotation(JsonParam.class).value() + "不能为空");
  34. throw exception;
  35. }
  36. }
  37. return val;
  38. }
  39. private String getRequestBody(NativeWebRequest webRequest) {
  40. HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
  41. String jsonBody = (String) servletRequest.getAttribute(JSON_REQUEST_BODY);
  42. if (jsonBody == null) {
  43. try {
  44. jsonBody = IOUtils.toString(servletRequest.getInputStream());
  45. servletRequest.setAttribute(JSON_REQUEST_BODY, jsonBody);
  46. } catch (IOException e) {
  47. throw new RuntimeException(e);
  48. }
  49. }
  50. return jsonBody;
  51. }
  52. }

注册自定义参数解析器

springboot方式

方式一:

  1. import java.util.List;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  4. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
  5. import com.demo.mvc.component.MultiPersonArgumentResolver;
  6. import com.demo.mvc.component.PersonArgumentResolver;
  7. @SpringBootApplication
  8. public class WebMvcConfiguration extends WebMvcConfigurationSupport {
  9. @Override
  10. protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  11. // 注册JsonPathArgumentResolver的参数分解器
  12. argumentResolvers.add(new JsonPathArgumentResolver());
  13. }
  14. }

方式二:

  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  3. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  4. import java.util.List;
  5. @Configuration
  6. public class ClientResourcesConfig extends WebMvcConfigurerAdapter {
  7. @Override
  8. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  9. // super.addArgumentResolvers(argumentResolvers);
  10. argumentResolvers.add(new JsonPathArgumentResolver());
  11. }
  12. }

在新版 Spring Boot 中已经将 WebMvcConfigurerAdapter 标记为过时,可参考方式三。也可以查看Spring Boot WebMvcConfigurerAdapte 方法已经过时解决方法

方式三:

  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  3. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  4. import java.util.List;
  5. @Configuration
  6. public class ClientResourcesConfig implements WebMvcConfigurer {
  7. @Override
  8. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  9. argumentResolvers.add(new JsonPathArgumentResolver());
  10. }
  11. }

传统XML格式

方式一:

  1. <mvc:annotation-driven>
  2. <mvc:argument-resolvers>
  3. <bean class="com.manqian.crm.resolver.JsonPathArgumentResolver"/>
  4. </mvc:argument-resolvers>
  5. </mvc:annotation-driven>

方式二:

  1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
  2. <property name="jsonPathArgumentResolver">
  3. <bean class="com.manqian.crm.resolver.JsonPathArgumentResolver"/>
  4. </property>
  5. </bean>

依赖

com.jayway.jsonpath
json-path

拓展实例:获取用户信息

  1. import org.springframework.core.MethodParameter;
  2. import org.springframework.lang.Nullable;
  3. import org.springframework.stereotype.Component;
  4. import org.springframework.web.bind.support.WebDataBinderFactory;
  5. import org.springframework.web.context.request.NativeWebRequest;
  6. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  7. import org.springframework.web.method.support.ModelAndViewContainer;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpSession;
  10. /**
  11. * @author yeskery
  12. * @date 2018/06/02
  13. */
  14. @Component
  15. public class UserArgumentResolver implements HandlerMethodArgumentResolver {
  16. @Override
  17. public boolean supportsParameter(MethodParameter methodParameter) {
  18. if (methodParameter.getParameterType() == User.class) {
  19. return true;
  20. }
  21. return false;
  22. }
  23. @Nullable
  24. @Override
  25. public Object resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, @Nullable WebDataBinderFactory webDataBinderFactory) throws Exception {
  26. HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
  27. HttpSession session = request.getSession();
  28. Object user = session.getAttribute("user");
  29. return user;
  30. }
  31. }

本文部分内容来自:https://blog.csdn.net/u010187242/article/details/73647670

评论

发表评论 点击刷新验证码

提示

该功能暂未开放