controller方法常用的两种入参解析
springmvc 对于controller 方法的入参解析,常用到的有两种:
1.基于request请求参数、Form表单参数实现解析功能,如简单类或者自定义类入参;
2.基于request body实现解析功能,如@RequestBody 注解类入参。
......
springmvc 实现的两种方法入参解析器
1.针对上述的简单类和自定义类,springmvc 提供不同的解析器实现,下文详述;
列表A:
ServletModelAttributeMethodProcessor(自定义类解析)
RequestParamMethodArgumentResolver(简单类解析(primitive、String、Number、Date、URL等))
2.针对application/json 请求解析,springmvc 直接委托给JSON 解析库实现入参的反序列化。
列表B:
RequestResponseBodyMethodProcessor
......
基于请求参数的方法入参解析器
决定采用上述列表A中哪个解析器,核心在于需要解析的clazz类型。
/**
* 检测指定的clazz是否为’简单‘类型。
* 定义为:primitive、String、CharSequence、Number、Date、URI、URL、Locale、Class 或者这些类型的Array
* 用途:决定注入类解析或者controller 方法入参类解析。
*/
public static boolean isSimpleProperty(Class clazz) {
Assert.notNull(clazz, "Class must not be null");
return isSimpleValueType(clazz) || (clazz.isArray() && isSimpleValueType(clazz.getComponentType()));
}
如果入参类型为自定义类,首先需要new instance,由此决定使用调用简单的DataBinder.convert还是AbstractPropertyAccessor.setPropertyValue。
DataBinder和 AbstractPropertyAccessor 都实现了TypeConverter 接口,基础的转换逻辑是相同的实现。
/**
* 调度PropertyEditor、Converter,实现执行String To 指定类型转换
**/
public T convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// 优先使用Custom editor
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
// 其次使用配置的 conversionService,内置了n多converter,基本可以支持所有的类型转换
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) {
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
try {
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
}
catch (ConversionFailedException ex) {
}
}
}
// 优先使用Custom editor情况下,首先尝试进行简单的StringToCollection转换,再使用editor进行转换
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
// 以下代码正常情况不可能覆盖到...
return (T) convertedValue;
}
自定义表单请求解析Editor
Converter列表
之前推荐过PropertyEditor的实现,现在看看spring 内置的Converter,更加强大,如下:
// 能想到的类型转换都包括了,完美!
// 1.标准类型Converter
converterRegistry.addConverter(new StringToBooleanConverter());
converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
converterRegistry.addConverter(new StringToCharacterConverter());
converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new NumberToCharacterConverter());
converterRegistry.addConverterFactory(new CharacterToNumberFactory());
converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
converterRegistry.addConverter(Enum.class, String.class, new EnumToStringConverter(conversionService));
converterRegistry.addConverter(new StringToLocaleConverter());
converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new PropertiesToStringConverter());
converterRegistry.addConverter(new StringToPropertiesConverter());
converterRegistry.addConverter(new StringToUUIDConverter());
converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
// 2.集合类转换Converter,内部实现迭代处理
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
// 3.回调类型处理Converter
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter(conversionService));
converterRegistry.addConverter(new FallbackObjectToStringConverter());