zoukankan      html  css  js  c++  java
  • SpringMVC(三):参数绑定、输入输出转换

    一、参数解析绑定 

    1. 自定义绑定:不绑定某些项

       @InitBinder
        private void initBinder(WebDataBinder dataBinder) {
            dataBinder.setDisallowedFields("company", "dateCreated", "lastUpdated");
        }

    2. 什么时候使用DataBinder

    RequestMappingHandlerAdapter 的 invokeHandlerMethod 方法
        protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
         //获取WebDataBinderFactory 
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    
            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                if (logger.isDebugEnabled()) {
                    logger.debug("Found concurrent result value [" + result + "]");
                }
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
    
         //注入方法参数 invocableMethod.invokeAndHandle(webRequest, mavContainer);
    if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); }

    3.  RequestMappingHandlerAdapter 


    1. RequestMappingHandlerAdapter中两个和参数解析器相关的成员变量
        private List<HandlerMethodArgumentResolver> customArgumentResolvers;
    
        private HandlerMethodArgumentResolverComposite argumentResolvers;

    2. RequestMappingHandlerAdapter实例化后,会调用afterPropertiesSet(),在这里把系统默认的解析器和我们写的自定义解析器汇总
        @Override
        public void afterPropertiesSet() {
            // Do this first, it may add ResponseBody advice beans
            initControllerAdviceCache();
    
            if (this.argumentResolvers == null) {
                List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
                this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
            }
            if (this.initBinderArgumentResolvers == null) {
                List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
                this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
            }
            if (this.returnValueHandlers == null) {
                List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
                this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
            }
        }

      3. 调用匹配的methodArgumentResolver解析数据

    参数解析绑定总结

    1. SpringMVC初始化时,RequestMappingHandlerAdapter类会把一些默认的参数解析器添加到argumentResolvers中。当SpringMVC接收到请求后首先根据url查找对应的HandlerMethod。
    2. 遍历HandlerMethod的MethodParameter数组
    3. 根据MethodParameter的类型来查找确认使用哪个HandlerMethodArgumentResolver,遍历所有的argumentResolvers的supportsParameter(MethodParameter parameter)方法。如果返回true,则表示查找成功,当前MethodParameter,使用该HandlerMethodArgumentResolver。这里确认大多都是根据参数的注解已经参数的Type来确认。
    4. 解析参数,从request中解析出MethodParameter对应的参数,这里解析出来的结果都是String类型。
    5. 转换参数,把对应String转换成具体方法所需要的类型,这里就包括了基本类型、对象、List、Set、Map。

     二、输入输出转换

    1.

    public interface ConverterFactory<S, R> {
    
        /**
         * Get the converter to convert from S to target type T, where T is also an instance of R.
         * @param <T> the target type
         * @param targetType the target type to convert to
         * @return A converter from S to T
         */
        <T extends R> Converter<S, T> getConverter(Class<T> targetType);
    
    }

    Spring实现ConvertFactory示例

    final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
    
        @Override
        public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
            Class<?> enumType = targetType;
            while (enumType != null && !enumType.isEnum()) {
                enumType = enumType.getSuperclass();
            }
            if (enumType == null) {
                throw new IllegalArgumentException "The target type " + targetType.getName() + " does not refer to an enum");
            }
            return new StringToEnum(enumType);
        }
    
    
        private class StringToEnum<T extends Enum> implements Converter<String, T> {
    
            private final Class<T> enumType;
    
            public StringToEnum(Class<T> enumType) {
                this.enumType = enumType;
            }
    
            @Override
            public T convert(String source) {
                if (source.length() == 0) {
                    // It's an empty enum identifier: reset the enum value to null.
                    return null;
                }
                return (T) Enum.valueOf(this.enumType, source.trim());
            }
        }
    
    }

     上面的示例不支持基数转换为枚举,改进如下:

    public class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
    
        public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
            return new StringToEnumConverter(targetType);
        }
    
        private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
    
            private Class<T> enumType;
    
    
            public StringToEnumConverter(Class<T> enumType) {
                this.enumType = enumType;
            }
    
            public T convert(String source) {
    
                try {
                    Integer ordinal = Integer.parseInt(source);
              //Enum的values是编译器加的 T[] values
    = (T[]) enumType.getDeclaredMethod("values", new Class[0]).invoke(null, new Object[0]); return values[ordinal]; } catch (Exception e) { } try { Method valueOf = enumType.getDeclaredMethod("valueOf", String.class); return (T) valueOf.invoke(null, source); } catch (Exception e) { } throw new IllegalStateException("非法参数值:" + source); } } }

    二、json输出转换:  ObjectMapper

    spring提供三种不同级别的自定义方式

    参考:

    spring reference: how to customer ObjectMapper

     spring 参数解析绑定

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 高精度乘法
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    Java实现 蓝桥杯VIP 算法提高 现代诗如蚯蚓
    ddd
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/8618364.html
Copyright © 2011-2022 走看看