需求: 为 @RequestBody 添加 application/x-www-form-urlencoded 解析
    根据源码得到
    HandlerMethodArgumentResolverComposite 类中做循环判断,解析指定数据类型。
    所有解析类型都实现自接口 HandlerMethodArgumentResolver
    系统中默认共有38中数据解析类,我们添加自己的解析类即可
    根据源码所得:
    解析 application/json 的类为 RequestResponseBodyMethodProcessor
    解析 application/x-www-form-urlencoded 的类为 RequestParamMapMethodArgumentResolver

    解析类 RequestBodyHandlerMethodArgumentResolver.java

    1. package top.luoqiz.common.web.resolver;
    2. import cn.hutool.http.ContentType;
    3. import org.springframework.core.MethodParameter;
    4. import org.springframework.web.bind.annotation.RequestBody;
    5. import org.springframework.web.bind.support.WebDataBinderFactory;
    6. import org.springframework.web.context.request.NativeWebRequest;
    7. import org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver;
    8. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    9. import org.springframework.web.method.support.ModelAndViewContainer;
    10. import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
    11. import javax.servlet.http.HttpServletRequest;
    12. /**
    13. * 描述: @RequestBody 注解默认只处理 content-type=application/json 的参数,其解析器为 {@link org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor}
    14. * 在此重写,使其支持 content-type=application/x-www-form-urlencoded 的参数 ,其默认解析器为 {@link org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver}
    15. * <p>
    16. * 思路 : 通过判断 content-type ,调用其相对应的默认解析器
    17. *
    18. * @author luoqiz
    19. */
    20. public class RequestBodyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    21. final String formUrlencoded = ContentType.FORM_URLENCODED.getValue();
    22. /**
    23. * 解析 content-type=application/json 的默认解析器是RequestResponseBodyMethodProcessor
    24. */
    25. private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor;
    26. /**
    27. * 解析 content-type=application/x-www-form-urlencoded 的默认解析器是 RequestParamMapMethodArgumentResolver
    28. */
    29. private RequestParamMapMethodArgumentResolver requestParamMapMethodArgumentResolver;
    30. /**
    31. * 全参构造
    32. */
    33. public RequestBodyHandlerMethodArgumentResolver(RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor,
    34. RequestParamMapMethodArgumentResolver requestParamMapMethodArgumentResolver) {
    35. this.requestResponseBodyMethodProcessor = requestResponseBodyMethodProcessor;
    36. this.requestParamMapMethodArgumentResolver = requestParamMapMethodArgumentResolver;
    37. }
    38. /**
    39. * 当参数前有 @RequestBody 注解时, 解析该参数 会使用此 解析器
    40. * <p>
    41. * 注:此方法的返回值将决定:是否使用此解析器解析该参数
    42. */
    43. @Override
    44. public boolean supportsParameter(MethodParameter methodParameter) {
    45. return methodParameter.hasParameterAnnotation(RequestBody.class);
    46. }
    47. /**
    48. * 解析参数
    49. */
    50. @Override
    51. public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
    52. NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory)
    53. throws Exception {
    54. HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
    55. if (request == null) {
    56. throw new RuntimeException(" request must not be null!");
    57. }
    58. String contentType = request.getContentType();
    59. /*
    60. * 如果ContentType是application/x-www-form-urlencoded,那么使用ServletModelAttributeMethodProcessor解析器
    61. *
    62. * 注:其实默认的,当系统识别到参数前有@RequestBody注解时,就会走RequestResponseBodyMethodProcessor解析器;这里就
    63. * 相当于在走默认的解析器前走了个判断而已。
    64. */
    65. if (formUrlencoded.equals(contentType)) {
    66. return requestParamMapMethodArgumentResolver.resolveArgument(methodParameter,
    67. modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
    68. }
    69. return requestResponseBodyMethodProcessor.resolveArgument(methodParameter,
    70. modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
    71. }
    72. }

    配置解析类 HandlerMethodArgumentResolverConfig.java

    1. package top.luoqiz.common.web.resolver;
    2. import org.springframework.context.annotation.Configuration;
    3. import org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver;
    4. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    5. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
    6. import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
    7. import javax.annotation.PostConstruct;
    8. import java.util.ArrayList;
    9. import java.util.List;
    10. /**
    11. * 参数解析配置
    12. *
    13. * @author luoqiz
    14. */
    15. @Configuration
    16. public class HandlerMethodArgumentResolverConfig {
    17. private final RequestMappingHandlerAdapter requestMappingHandlerAdapter;
    18. public HandlerMethodArgumentResolverConfig(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
    19. this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;
    20. }
    21. @PostConstruct
    22. private void addArgumentResolvers() {
    23. // 获取到的是不可变的集合
    24. List<HandlerMethodArgumentResolver> argumentResolvers =
    25. requestMappingHandlerAdapter.getArgumentResolvers();
    26. RequestBodyHandlerMethodArgumentResolver requestBodyHandlerMethodArgumentResolver =
    27. requestBodyHandlerMethodArgumentResolver(argumentResolvers);
    28. // ha.getArgumentResolvers()获取到的是不可变的集合,所以我们需要新建一个集合来放置参数解析器
    29. List<HandlerMethodArgumentResolver> myArgumentResolvers =
    30. new ArrayList<>(argumentResolvers.size() + 1);
    31. // 将自定义的解析器,放置在第一个,并保留原来的解析器
    32. myArgumentResolvers.add(requestBodyHandlerMethodArgumentResolver);
    33. myArgumentResolvers.addAll(argumentResolvers);
    34. requestMappingHandlerAdapter.setArgumentResolvers(myArgumentResolvers);
    35. }
    36. public RequestBodyHandlerMethodArgumentResolver requestBodyHandlerMethodArgumentResolver(
    37. List<HandlerMethodArgumentResolver> resolvers) {
    38. // 解析 content-type=application/json 的默认解析器
    39. RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = null;
    40. // 解析 content-type=application/x-www-form-urlencoded 的默认解析器
    41. RequestParamMapMethodArgumentResolver requestParamMapMethodArgumentResolver = null;
    42. if (resolvers == null) {
    43. throw new RuntimeException("argumentResolverList must not be null!");
    44. }
    45. for (HandlerMethodArgumentResolver argumentResolver : resolvers) {
    46. if (requestResponseBodyMethodProcessor != null && requestParamMapMethodArgumentResolver != null) {
    47. break;
    48. }
    49. if (argumentResolver instanceof RequestResponseBodyMethodProcessor) {
    50. requestResponseBodyMethodProcessor = (RequestResponseBodyMethodProcessor) argumentResolver;
    51. continue;
    52. }
    53. if (argumentResolver instanceof RequestParamMapMethodArgumentResolver) {
    54. requestParamMapMethodArgumentResolver = (RequestParamMapMethodArgumentResolver) argumentResolver;
    55. }
    56. }
    57. if (requestResponseBodyMethodProcessor == null || requestParamMapMethodArgumentResolver == null) {
    58. throw new RuntimeException("requestResponseBodyMethodProcessor and "
    59. + " requestParamMapMethodArgumentResolver must not be null!");
    60. }
    61. return new RequestBodyHandlerMethodArgumentResolver(requestResponseBodyMethodProcessor,
    62. requestParamMapMethodArgumentResolver);
    63. }
    64. }

    备注:

    RequestResponseBodyMethodProcessor (RequestBody—-map) application/json
    RequestParamMapMethodArgumentResolver (RequestParam—-map) application/x-www-form-urlencoded
    MapMethodProcessor (no annotion —- map)
    RequestParamMethodArgumentResolver (no annotion —-string)

    image.png