其他分享
首页 > 其他分享> > spring实体类(POJO)参数的赋值(form表单)原理

spring实体类(POJO)参数的赋值(form表单)原理

作者:互联网

10、实体类(POJO)参数的赋值(form表单)原理

10.1、原理解析

  1. 测试用例

    • 准备好两个实体类
    public class Person {
        private String name;
        private Integer age;
        private Pet pet;
    }
    
    public class Pet {
        private String name;
        private Integer age;
    }
    
    • html的form表单

      注意这个 宠物Pet对象的name不能乱写 必须要和 person中定义的名称一样 才可以

    <form action="/person" method="post">
        <input type="text" name="name" value="水三丫">
        <input type="text" name="age" value="18">
        <input type="text" name="pet.name" value="阿猫">
        <input type="text" name="pet.age" value="10">
        <input type="submit" value="Person">
    </form>
    
    • Controller请求代码
    @PostMapping("/person")
    public Map person(Person person){
        Map<String, Person> map = new HashMap<>();
        map.put("person",person);
        return map;
    }
    
  2. 源码Debug

    • 从DispatchServlet 的 doDispatch方法开始

      DispatchServlet类中的 
          doDispatch方法
          	//RequestMappingHandlerAdapter这个处理器
          	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      
    • 获取请求参数的处理器

      HandlerMethodArgumentResolverComposite类中的
          getArgumentResolver方法
          	//总共27个处理器
          	ServletModelAttributeMethodProcessor这个处理Pojo实体类的参数
      
    • 创建实体类构造器和赋值

      • 创造构造器
      ModelAttributeMethodProcessor类中的
      	resolveArgument方法
              // Create attribute instance
              try {
                  attribute = createAttribute(name, parameter, 
                                              binderFactory, webRequest);
              }
      	createAttribute方法  //反射获取空参构造器
              Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
      		Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
      		Object attribute = constructAttribute(ctor, attributeName, parameter, 
                                                    binderFactory, webRequest);
      

      • 属性绑定和验证
      ModelAttributeMethodProcessor类中的
      	resolveArgument方法
          // Bean property binding and validation;
          // skipped in case of binding failure on construction.
          WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, 
                                                            name);
      

      • 获取请求的参数
      ServletModelAttributeMethodProcessor类中订单
          bindRequestParameters方法
          	servletBinder.bind(servletRequest);
      ServletRequestDataBinder类中的
          bind方法
           	MutablePropertyValues mpvs = new 
          							ServletRequestParameterPropertyValues(request);
      WebUtils方法类中
          getParametersStartingWith方法
          	Enumeration<String> paramNames = request.getParameterNames();
      		Map<String, Object> params = new TreeMap<>();  
      

      • 准备开始数据绑定

        ServletRequestDataBinder类中的
            bind方法
            	doBind(mpvs);
        WebDataBinder类中的
            doBind方法
            	super.doBind(mpvs);
        DataBinder类中的
        	doBind方法
                applyPropertyValues(mpvs);
        AbstractPropertyAccessor类中的
            setPropertyValues方法
                try {
                    setPropertyValue(pv);
                }
        

        第一步获取数据的绑定格式转换的处理器(因为浏览器以JSOn穿过了的都是字符串)需要格式转换

        TypeConverterDelegate类中的
            convertIfNecessary方法
                try {
                    //传入的是请求的参数值   参数类型  需要转换的类型
                    return (T) conversionService.convert(newValue, sourceTypeDesc, 
                                                         typeDescriptor);
                }
        GenericConversionService类中的
            convert方法
           	 	GenericConverter converter = getConverter(sourceType, targetType);
        	getConverter方法
        		ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
        		GenericConverter converter = this.converterCache.get(key);
        

        需要124个类型转换中寻找这次需要的

        需要的是:

        获取的转换器

        第二步转换数据

        GenericConversionService类中的
            convert方法
        		Object result = ConversionUtils.invokeConverter(converter, source, 
                                                                sourceType,targetType);
        

        第三步开始赋值

        AbstractNestablePropertyAccessor类中的
            processLocalProperty方法
                    ph.setValue(valueToApply);
        

        获取set方法

        BeanWrapperImpl类中的
        	setValue方法
            	Method writeMethod = (this.pd instanceof 
                                      GenericTypeAwarePropertyDescriptor ?
        					((GenericTypeAwarePropertyDescriptor) 	
                             this.pd).getWriteMethodForActualAccess() :
        					this.pd.getWriteMethod());
        

        开始反射赋值

        BeanWrapperImpl类中的
        	setValue方法
        		writeMethod.invoke(getWrappedInstance(), value);
        

        赋值完成

10.2、定制化属性转换器

  1. 编写自定义配置转换规则

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addFormatters(FormatterRegistry registry) {
                registry.addConverter(new Converter<String, Pet>() {//增加一个转换器
                    @Override
                    public Pet convert(String source) {//实现这个接口的方法
                        if(!StringUtils.isEmpty(source)){
                            Pet pet = new Pet();
                            String[] split = source.split(",");//以逗号为分隔符
                            pet.setName(split[0]);
                            pet.setAge(Integer.parseInt(split[1]));
                            return pet;
                        }
                        return null;
                    }
                });
            }
        };
    }
    

    lambda表达式写法

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(String.class,Pet.class, source -> {
    
                if(!StringUtils.isEmpty(source)){
                    Pet pet = new Pet();
                    String[] split = source.split(",");
                    pet.setName(split[0]);
                    pet.setAge(Integer.parseInt(split[1]));
                    return pet;
                }
                return null;
            });
        }
    };
    }
    
  2. 测试用例

    html页面form表单代码

    <form action="/person1" method="post">
        <input type="text" name="name" value="水三丫">
        <input type="text" name="age" value="18">
        <input type="text" name="pet" value="阿猫,10">
        <input type="submit" value="Person1">
    </form>
    
  3. Debug测试

    测试的时候就会在全部转换器中找到我们定制的哪一个

标签:实体类,form,Pet,spring,pet,split,new,方法,类中
来源: https://www.cnblogs.com/shuisanya/p/16385349.html