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 参数解析绑定

  • 相关阅读:
    T-SQL语句操作数据库——基本操作
    HTML——CSS基础
    HTML基础——表格的应用
    HTML基础——基础标签
    AJAX
    aspnetcore-developer-roadmap
    【.Net Core】DotNet CLI command (使用命令创建Controller、View等)
    Unrecognized header format %
    【C#】学习笔记(3) 关于Events使用的小Demo
    数组常用方法(一)
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/8618364.html
Copyright © 2011-2022 走看看