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. 一文看懂 ZooKeeper ,面试再也不用背八股(文末送PDF)

    ZooKeeper知识点总结 一.ZooKeeper 的工作机制 二.ZooKeeper 中的 ZAB 协议 三.数据模型与监听器 四.ZooKeeper 的选举机制和流程 本文将以如下内容为主线讲解 ...

  2. Python技法:浮点数取整、格式化和NaN处理

    1. 取整的三种方法 1.1 强转int类型 这种方法会直接对浮点数的小数部分进行截断(无论是正还是负). print(int(2.7)) # 2 print(int(-2.7)) # -2 1.2 ...

  3. 将Abp移植进.NET MAUI项目(一):搭建项目

    ​ 前言 去年12月份做了MAUI混合开发框架的调研,想起来文章里给自己挖了个坑,要教大家如何把Abp移植进Maui项目,由于篇幅限制,将分为三个章节. 将Abp移植进.NET MAUI项目(一):搭 ...

  4. JDK1.7HashMap源码分析

       1.1首先HashMap中的Hash(哈希)是什么? Hash也称散列,哈希,对应的英文都是Hash.基本原理就是把任意长度的输入通过Hash算法变成固定长度的输出,这个映射的规则就是对应的Ha ...

  5. Java实用类-Enum(枚举)

    1. 历史 ​ 在 JDK 1.5 之前没有枚举类型,那时候一般用接口常量来替代(例如,public static final String male ).JKD1.5之后使用 Java 枚举类型 e ...

  6. 【RocketMQ】MQ消息发送

    消息发送 首先来看一个RcoketMQ发送消息的例子: @Service public class MQService { @Autowired DefaultMQProducer defaultMQ ...

  7. 【Redis】客观下线

    在sentinelHandleRedisInstance函数中,如果是主节点,需要做如下处理: void sentinelHandleRedisInstance(sentinelRedisInstan ...

  8. 根据数据中的key获取value值

    一.测试数据准备 List<Map<String, String>> result = new ArrayList();Map<String, String> ma ...

  9. python基础知识-day9(数据驱动)

    1.数据驱动的概念 在自动化测试中,需要把测试的数据分离到JSON,YAML等文件中. 2.YAML 的相关知识 YAML 入门教程 分类 编程技术 YAML 是 "YAML Ain't a ...

  10. Django【查询】 基础回顾与深入应用

    官方Django3.2 文档:https://docs.djangoproject.com/en/3.2/topics/db/queries/ 本文大部分内容参考官方3.2版本文档撰写,仅供学习使用 ...