美文网首页
自定义HandlerMethodArgumentResolver

自定义HandlerMethodArgumentResolver

作者: StephenRo | 来源:发表于2018-07-18 20:40 被阅读982次

    前言

    今天在做一个后台的管理列表,猛然发现有8~9个查询参数,心里一想:又 TMD 要想一坨子 @RequestParam了。突然就想:妈的不想这样了。想着用一个对象来封装这些查询参数。但我们公司是有要求 前端给的参数都是以下划线,而后端用的都是驼峰命名。如何转换成了问题。以下是在请教大佬之后,大佬给的方案,感谢大佬,特记下学习一下。

    代码

    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PropertyNaming {
    
    }
    
    public class PropertyNamingStrategyArgumentResolver implements HandlerMethodArgumentResolver {
    
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return parameter.hasParameterAnnotation(PropertyNaming.class);
        }
    
        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            String name = ModelFactory.getNameForParameter(parameter);
            Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
                    createAttribute(parameter));
    
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            if (binder.getTarget() != null) {
                if (!mavContainer.isBindingDisabled(name)) {
                    bindRequestParameters(binder, webRequest);
                }
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new BindException(binder.getBindingResult());
                }
            }
    
            // Add resolved attribute and BindingResult at the end of the model
            Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
            mavContainer.removeAttributes(bindingResultModel);
            mavContainer.addAllAttributes(bindingResultModel);
    
            return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
        }
    
        /**
         * Whether to raise a fatal bind exception on validation errors.
         * @param binder the data binder used to perform data binding
         * @param methodParam the method argument
         * @return {@code true} if the next method argument is not of type {@link Errors}
         */
        protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) {
            int i = methodParam.getParameterIndex();
            Class<?>[] paramTypes = methodParam.getMethod().getParameterTypes();
            boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
            return !hasBindingResult;
        }
    
        protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) {
            Annotation[] annotations = methodParam.getParameterAnnotations();
            for (Annotation ann : annotations) {
                Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
                if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
                    Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
                    Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
                    binder.validate(validationHints);
                    break;
                }
            }
        }
    
        protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
            Map<String, String[]> result = new HashMap<>();
            Map<String, String[]> parameterMap = request.getParameterMap();
            if(!parameterMap.isEmpty()) {
                Set<String> keys = parameterMap.keySet();
                for (String key : keys) {
                    result.put(key, parameterMap.get(key));
                    String translate = SnakeCaseStrategy.translate(key);
                    if(translate.equals(key)){
                        continue;
                    }
                    result.put(translate, parameterMap.get(key));
                }
            }
            MutablePropertyValues mpvs = new MutablePropertyValues(result);
            binder.bind(mpvs);
        }
    
        protected Object createAttribute(MethodParameter methodParam) throws Exception {
    
            return BeanUtils.instantiateClass(methodParam.getParameterType());
        }
    
        public static class SnakeCaseStrategy {
    
            public static String translate(String input)
            {
                // garbage in, garbage out
                if (input == null) return input;
                int length = input.length();
                StringBuilder result = new StringBuilder(length * 2);
                boolean wasPrevTranslated = false;
                for (int i = 0; i < length; i++)
                {
                    // skip first starting underscore
                    char c = input.charAt(i);
                    if (i > 0 && c == '_')
                    {
                        wasPrevTranslated = true;
                    } else if (Character.isLowerCase(c) && wasPrevTranslated) {
                        result.append(Character.toUpperCase(c));
                        wasPrevTranslated = false;
                    } else {
                        result.append(c);
                    }
                }
                return result.toString();
            }
        }
    }
    
    @Configuration
    public class WebConfiguration extends WebMvcConfigurationSupport {
    
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            argumentResolvers.add(new PropertyNamingStrategyArgumentResolver());
        }
    
    
    

    使用

    @RestController
    @RequestMapping("/test")
    public class TestController {
    
        @GetMapping
        public String test(@PropertyNaming Test test){
            return test.userName;
        }
    }
    

    相关文章

      网友评论

          本文标题:自定义HandlerMethodArgumentResolver

          本文链接:https://www.haomeiwen.com/subject/mzuapftx.html