ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-06-17 13:06:35  阅读:148  来源: 互联网

标签:实体类 form Pet spring pet split new 方法 类中


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有