spring实体类(POJO)参数的赋值(form表单)原理
作者:互联网
10、实体类(POJO)参数的赋值(form表单)原理
10.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; }
-
源码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、定制化属性转换器
-
编写自定义配置转换规则
@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; }); } }; }
-
测试用例
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>
-
Debug测试
测试的时候就会在全部转换器中找到我们定制的哪一个
标签:实体类,form,Pet,spring,pet,split,new,方法,类中 来源: https://www.cnblogs.com/shuisanya/p/16385349.html