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. JetBrains IDE全新UI预览版来了,要做简洁与强大兼顾的IDE

    5月23日,JetBrains发布了一篇博文,透露他们正在实现一套全新的界面界面. 他们认为目前行业中的用户界面趋势已经发生了演变,很多新用户认为JetBrains IDE的界面过于笨重,而且过时.所 ...

  2. 直观比较 popcount 的效率差异

    问题 求 \(\sum\limits_{i=1}^{3\times 10^8} popcount(i)\) . 仅考虑在暴力做法下的效率. 枚举位 __builtin_popcount #includ ...

  3. 10分钟学会 API 测试 !

    本文面向对象主要是后端开发人员   API 开发好之后,我们需要对 API 进行简单的调试,确保 API 可以跑通再提交给前端人员进行对接或者是测试人员对 API 进行测试:   在测试过程中我们关注 ...

  4. 从零开始构建并编写神经网络---Keras【学习笔记】[1/2]

    Keras简介:   Keras是由纯python编写的基于theano/tensorflow的深度学习框架.   Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果, ...

  5. 物联网无线数传应用中的Modbus通信网关协议到底是什么?

    什么是物联网 通信Modbus网关 Modbus协议无线通信网关就是将一种Modbus协议帧转换为其他物联网无线数传协议帧. 比如将Modbus RTU的数据与Modbus TCP数据进行相互转换:也 ...

  6. 【Redis】ziplist压缩列表

    压缩列表 压缩列表是列表和哈希表的底层实现之一: 如果一个列表只有少量数据,并且数据类型是整数或者比较短的字符串,redis底层就会使用压缩列表实现. 如果一个哈希表只有少量键值对,并且每个键值对的键 ...

  7. 重学ES系列之新增的几个循环方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 用python做个计算器不是轻轻松松吗~

    计算器 Kivy是一个免费的开源Python库,可以快速轻松地开发高度交互的跨平台应用程序. 这里我将使用Python中的Kivy包来构建一个计算器GUI.(https://jq.qq.com/?_w ...

  9. 单片机 MCU 固件打包脚本软件

    ​ 1 前言 开发完 MCU 软件后,通常都会生成 hex 文件或者 bin 文件,用来做固件烧录或者升级,如果用来做产品开发,就涉及到固件版本的问题,初学者通常采用固件文件重命名来区分版本. 如果需 ...

  10. iOS OC纯代码企业级项目实战之我的云音乐(持续更新))

    简介 这是一个使用OC语言,从0使用纯代码方式开发一个iOS平台,接近企业级商业级的项目(我的云音乐),课程包含了基础内容,高级内容,项目封装,项目重构等知识:主要是讲解如何使用系统功能,流行的第三方 ...