• 从零搭建开发脚手架 自定义HandlerMethodArgumentResolver-注解@JsonArg和实体CurrentUser


    前言

    参数绑定时springmvc会对从前端传来的参数自动转化成方法定义的参数的类型,我们可自己定义此接口来实现自己的类型的转换。

    HandlerMethodArgumentResolver是什么?它是springmvc提供的入参解析器,像平常应用的注解@RequestParam @PathVariable @ModelAttribute …等等修饰在@RequestMapping下的参数上都可以用HandlerMethodArgumentResolver来解析。

    public interface HandlerMethodArgumentResolver {
    	// 参数是否符合条件,反回true会调用下面的方法
    	boolean supportsParameter(MethodParameter parameter);
    	// 对修饰的参数解析赋值等
    	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    有很多内置实现,我们可以去参考,例如:RequestParamMethodArgumentResolver.java

    场景1 自定义参数映射注解JsonArg

    1.创建自定义注解

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface JsonArg {
        String value() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.创建自定义HandlerMethodArgumentResolver

    public class JsonArgumentResolver implements HandlerMethodArgumentResolver {
    
        private static final String JSON_BODY_ATTRIBUTE = "JSON_REQUEST_BODY";
    
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return parameter.hasParameterAnnotation(JsonArg.class);
        }
    
        @Override
        public Object resolveArgument(
          MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
          WebDataBinderFactory binderFactory) 
          throws Exception {
            String body = getRequestBody(webRequest);
            String jsonPath = Objects.requireNonNull(
              Objects.requireNonNull(parameter.getParameterAnnotation(JsonArg.class)).value());
            Class<?> parameterType = parameter.getParameterType();
            return JsonPath.parse(body).read(jsonPath, parameterType);
        }
    
        private String getRequestBody(NativeWebRequest webRequest) {
            HttpServletRequest servletRequest = Objects.requireNonNull(
              webRequest.getNativeRequest(HttpServletRequest.class));
            String jsonBody = (String) servletRequest.getAttribute(JSON_BODY_ATTRIBUTE);
            if (jsonBody == null) {
                try {
                    jsonBody = IOUtils.toString(servletRequest.getInputStream());
                    servletRequest.setAttribute(JSON_BODY_ATTRIBUTE, jsonBody);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return jsonBody;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3.注册自定义HandlerMethodArgumentResolver

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            JsonArgumentResolver jsonArgumentResolver = new JsonArgumentResolver();
            argumentResolvers.add(jsonArgumentResolver);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.使用示例

    @PostMapping("/process/custompojo")
    public ResponseEntity process(
      @JsonArg("firstName") String firstName, 
      @JsonArg("lastName") String lastName,
      @JsonArg("address") AddressDto address) {
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    该节来自:https://www.baeldung.com/spring-mvc-json-param-mapping

    场景2 自定义类型接收分页参数

    参考:PageableHandlerMethodArgumentResolver.java

    1.创建自定义类型

    public class PageRequest {
    	private int page;
    	private int size;
        private List<Order> orders;
        public static class Order {
            private String property;
            private String direction;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.创建自定义HandlerMethodArgumentResolver

    public class PageRequestArgumentResolver implements HandlerMethodArgumentResolver {
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return PageRequest.class.equals(parameter.getParameterType());
        }
    
        @Override
        public Object resolveArgument(
                MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
                WebDataBinderFactory binderFactory)
                throws Exception {
            PageRequest.PageRequestBuilder builder = PageRequest.builder();
            String page = webRequest.getParameter("page");
            String pageSize = webRequest.getParameter("size");
            String[] directionParameter = webRequest.getParameterValues("sort");
            List<PageRequest.Order> allOrders = new ArrayList<>();
            builder.page(Integer.valueOf(page))
                    .size(Integer.valueOf(pageSize))
                    .orders(allOrders);
            if (ArrayUtil.isNotEmpty(directionParameter)) {
                for (String part : directionParameter) {
                    if (part == null) {
                        continue;
                    }
                    String[] elements = Arrays.stream(part.split(",")) //
                            .toArray(String[]::new);
                    allOrders.add(PageRequest.Order.builder()
                            .property(elements[0])
                            .direction(elements.length > 1 ? elements[1] : "asc")
                            .build());
                }
            }
            return builder.build();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.注册自定义HandlerMethodArgumentResolver

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            argumentResolvers.add(new PageRequestArgumentResolver());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.使用示例

    /api/v1/users?page=1&size=2&sort=name,email,asc
    /api/v1/users?page=1&size=2&sort=name,desc&sort=email,asc&sort=jack,asc
    
    • 1
    • 2
    @GetMapping
    public void get(PageRequest page) {
        log.info(page);
    }
    
    • 1
    • 2
    • 3
    • 4

    结果日志

    PageRequest(page=1, size=2, 
                orders=[PageRequest.Order(property=name, direction=desc),
                        PageRequest.Order(property=email, direction=asc), 
                        PageRequest.Order(property=jack, direction=asc)])
    
    • 1
    • 2
    • 3
    • 4

    场景3 自定义注解+类型接收当前登陆人

    1.创建自定义类型和自定义注解

    public class CurrentUser {
        private String id;
        private String username;
        private String displayName;
    }
    
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Auth {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.创建自定义HandlerMethodArgumentResolver

    public class AuthInfoArgumentResolver implements HandlerMethodArgumentResolver {
     		@Override
            public boolean supportsParameter(MethodParameter parameter) {
                return CurrentUser.class.equals(parameter.getParameterType()) &&
                    	parameter.hasParameterAnnotation(Auth.class);
            }
    
            @Override
            public Object resolveArgument(
                        MethodParameter parameter,
                        ModelAndViewContainer mvContainer,
                        NativeWebRequest nativeWebRequest,
                        WebDataBinderFactory webDataBinderFactory) throws Exception {
                HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
                if (request == null) {
                    return null;
                }
                    // CurrentUser  = from request
                return CurrentUser.builder().id(StpUtil.getLoginId().toString()).build();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.注册自定义HandlerMethodArgumentResolver

    同上

    4.使用示例

    /api/v1/users
    -hearder token
    
    • 1
    • 2
    @RestController
    public class HelloController {
        @PostMapping
        public void test(@RequestBody City city, @Auth CurrentUser user) {
            ...
    
    • 1
    • 2
    • 3
    • 4
    • 5

    参数类型转换总结

  • 相关阅读:
    156 - Ananagrams (UVA)
    Python邮件发送接收实战
    【Spring Cloud】CentOS 安装 DockerCE
    PYQT制作动态时钟
    Java学习笔记(二)——变量
    “2024深圳数字能源展”共同探讨数字能源未来发展方向和挑战
    在DFMEA实施过程中,如何区分预防措施和探测措施?
    PyTorch中的CUDA操作
    MySQL创建只读用户并授权
    征服BAT精选《Spring 源码分析》核心,欢迎围观
  • 原文地址:https://blog.csdn.net/abu935009066/article/details/128083852