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测试

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

spring实体类(POJO)参数的赋值(form表单)原理的更多相关文章

  1. js 取值&赋值-form表单

      form表单元素介绍 CreateTime--2016年9月22日10:25:54 Author:Marydon <form> 表单元素. 表单中的元素: <input>表 ...

  2. 1113 form表单与css选择器

    目录 1.form表单 form元素 特点 参数 form元素内的控件 1.input的使用 2.select标签 3.textarea元素 4.autofocus属性 2.CSS 1.基础语法 cs ...

  3. Java如何实现form表单提交的数据自动对应实体类(源码)

    原文出自:https://blog.csdn.net/seesun2012 原生Java+JQuery form表单serializeArray提交自动对应java实体,这是一个实际的例子: html ...

  4. @NamedEntityGraphs --JPA按实体类对象参数中的字段排序问题得解决方法

    JPA按实体类对象参数中的字段排序问题得解决方法@Entity @Table(name="complaints") @NamedEntityGraphs({ @NamedEntit ...

  5. c# 实体类怎么给LIST赋值,table转LIST

    /// <summary> /// 缓存客服集合信息 /// </summary> public class model { /// <summary> /// 客 ...

  6. 实体类相同属性间赋值与如何判断实体类中是否所有的字段都为null

    1,实体类相同属性间赋值 /// <summary> /// 将实体2的值动态赋值给实体1(名称一样的属性进行赋值) /// </summary> /// <param ...

  7. SpringMVC中使用bean来接收form表单提交的参数时的注意点

    这是前辈们对于SpringMVC接收表单数据记录下来的总结经验: SpringMVC接收页面表单参数 springmvc请求参数获取的几种方法 下面是我自己在使用时发现的,前辈们没有记录的细节和注意点 ...

  8. JsonResponse类的使用、form表单上传文件补充、CBV和FBV、HTML的模板语法之传值与过滤器

    昨日内容回顾 Django请求生命周期 # 1.浏览器发起请求 到达Django的socket服务端(web服务网关接口) 01 wsgiref 02 uwsgi + nginx 03 WSGI协议 ...

  9. Form 表单提交参数

    今天因为要额外提交参数数组性的参数给form传到后台而苦恼了半天,结果发现,只需要在form表单对应的字段html空间中定义name = 后台参数名 的属性就ok了. 后台本来是只有模型参数的,但是后 ...

随机推荐

  1. df-查看磁盘目录空间大小

    查看磁盘分区挂载情况. 语法 df [option] 选项 -T 显示文件系统类型. -h 带单位显示. 示例 [root@localhost ~]# df -Th Filesystem Type S ...

  2. RabitMQ 简介

    每日一句 The secret of being miserable is to have leisure to bother about whether you are happy or not. ...

  3. 面试突击51:为什么单例一定要加 volatile?

    单例模式的实现方法有很多种,如饿汉模式.懒汉模式.静态内部类和枚举等,当面试官问到"为什么单例模式一定要加 volatile?"时,那么他指的是为什么懒汉模式中的私有变量要加 vo ...

  4. 使用kubeseal加密和管理k8s集群的secret

    使用kubeseal加密和管理k8s集群的secret 在k8s的管理过程中,像secret这种资源并不好维护,kubeseal提供了一种相对简单的方式来对原始secret资源进行加密,并通过控制器进 ...

  5. go-zero微服务实战系列(四、CRUD热热身)

    上一篇文章我们把整个项目的架子搭建完成,服务在本地也已经能运行起来了,顺利成章的接下来我们就应该开始写业务逻辑代码了,但是单纯的写业务逻辑代码是比较枯燥的,业务逻辑的代码我会不断地补充到 lerbon ...

  6. JuiceFS V1.0 RC1 发布,大幅优化 dump/load 命令性能, 深度用户不容错过

    各位社区的伙伴, JuiceFS v1.0 RC1 今天正式发布了!这个版本中,最值得关注的是对元数据迁移备份工具 dump/load 的优化. 这个优化需求来自于某个社区重度用户,这个用户在将亿级数 ...

  7. 《Java基础——IO流》

    Java基础--IO流       一.字节流:   1.输入流 (InputStream) 规则: 此处用于读取txt文件中的内容.   代码: import java.io.*; public c ...

  8. 简单实现python接口自动化(一)

    目的:excel中维护接口用例数据,通过python中requests库进行读取用例,并把运行结果与excel中的预期结果对比,最后把执行情况写入到excel中去. excel维护数据: 具体的接口名 ...

  9. 【摸鱼神器】UI库秒变低代码工具——表单篇(一)设计

    前面说了列表的低代码化的方法,本篇介绍一下表单的低代码化. 内容摘要 需求分析. 定义 interface. 定义表单控件的 props. 定义 json 文件. 基于 el-form 封装,实现依赖 ...

  10. centos7解决无法上网的问题

    问题:centos7出现无法进行联网,如下图所示,执行该命令: ping qq.com 出现如下情况: 解决方法: 首先cd到需要修改文件的所在目录下: [root@localhost ~]# cd ...