𝓝𝓮𝓶𝓸&博客

【SpringMVC】数据转换 & 数据格式化

数据转换 & 数据格式化 & 数据校验

数据转换

数据绑定流程

  1. Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
  2. DataBinder 调用装配在 Spring MVC 上下文中的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
  3. 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象
  4. Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是 DataBinder,运行机制如下:

数据转换

  • Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。
  • ConversionService converters =
    • java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@f874ca
    • java.lang.Character -> java.lang.Number : CharacterToNumberFactory@f004c9
    • java.lang.Character -> java.lang.String : ObjectToStringConverter@68a961
    • java.lang.Enum -> java.lang.String : EnumToStringConverter@12f060a
    • java.lang.Number -> java.lang.Character : NumberToCharacterConverter@1482ac5
    • java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory@126c6f
    • java.lang.Number -> java.lang.String : ObjectToStringConverter@14888e8
    • java.lang.String -> java.lang.Boolean : StringToBooleanConverter@1ca6626
    • java.lang.String -> java.lang.Character : StringToCharacterConverter@1143800
    • java.lang.String -> java.lang.Enum : StringToEnumConverterFactory@1bba86e
    • java.lang.String -> java.lang.Number : StringToNumberConverterFactory@18d2c12
    • java.lang.String -> java.util.Locale : StringToLocaleConverter@3598e1
    • java.lang.String -> java.util.Properties : StringToPropertiesConverter@c90828
    • java.lang.String -> java.util.UUID : StringToUUIDConverter@a42f23
    • java.util.Locale -> java.lang.String : ObjectToStringConverter@c7e20a
    • java.util.Properties -> java.lang.String : PropertiesToStringConverter@367a7f
    • java.util.UUID -> java.lang.String : ObjectToStringConverter@112b07f
    • ……

自定义类型转换器

  • ConversionService 是 Spring 类型转换体系的核心接口。
  • 可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定义一个 ConversionService. Spring 将自动识别出 IOC 容器中的 ConversionService,并在 Bean 属性配置及 Spring MVC 处理方法入参绑定等场合使用它进行数据的转换
  • 可通过 ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
  <property name="converters">
    <list>
      <bean class="com.nemo.springmvc.UserConverter"></bean>
    </list>
  </property>
</bean>

Spring 支持的转换器

Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到 ConversionServiceFactroyBean 中:

  • Converter<S,T>:将 S 类型对象转为 T 类型对象
  • ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类 (Integer、Long、Double 等)对象)可使用该转换器工厂类
  • GenericConverter:会根据源类对象及目标类对象所在的宿主类 中的上下文信息进行类型转换

自定义转换器示例

<mvc:annotation-driven conversion-service=“conversionService”/> 会将自定义的 ConversionService 注册到 Spring MVC 的上下文中

<mvc:annotation-driven conversion-ervice="conversionService"></mvc:annotation-driven>

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
  <property name="converters">
    <list>
      <bean class="com.nemo.springmvc.UserConverter"></bean>
    </list>
  </property>
</bean>
@RequestMapping("/handle24")
public String handle24(@RequestParam("user") User user) {
    System.out.println(user);
    return "success";
}

关于 mvc:annotation-driven

  • <mvc:annotation-driven/> 会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与 ExceptionHandlerExceptionResolver 三个bean。
  • 还将提供以下支持:
    • 支持使用 ConversionService 实例对表单参数进行类型转换
    • 支持使用 @NumberFormat@DateTimeFormat 注解完成数据类型的格式化
    • 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
    • 支持使用 @RequestBody@ResponseBody 注解

既没有配置 <mvc:default-servlet-handler/> 也没有配置 <mvc:annotation-driven/>

配置了 <mvc:default-servlet-handler/> 但没有配置 <mvc:annotation-driven/>

既配置了 <mvc:default-servlet-handler/> 又配置 <mvc:annotation-driven/>

@InitBinder

  • @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
  • @InitBinder方法不能有返回值,它必须声明为void。
  • @InitBinder方法的参数通常是是 WebDataBinder
/**
 * 不自动绑定对象中的 roleSet 属性,另行处理。
 */
@InitBinder
public void intBinder(WebDataBinder dataBinder) {
    dataBinder.setDisallowFields("roleSet");
}

数据格式化

  • 对属性对象的输入/输出进行格式化,从其本质上讲依然属于 “类型转换” 的范畴。
  • Spring 在格式化模块中定义了一个实现 ConversionService 接口的 FormattingConversionService 实现类,该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能
  • FormattingConversionService 拥有一个 FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring 上下文中构造前者
  • FormattingConversionServiceFactroyBean 内部已经注册了:
    • NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用 @NumberFormat 注解
    • JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用 @DateTimeFormat 注解
  • 装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动了。
    <mvc:annotation-driven/> 默认创建的 ConversionService 实例即为 FormattingConversionServiceFactroyBean

日期格式化

@DateTimeFormat 注解可对 java.util.Datejava.util.Calendarjava.long.Long 时间类型进行标注:

  • pattern 属性:类型为字符串。指定解析/格式化字段数据的模式,如:"yyyy-MM-dd hh:mm:ss"
  • iso 属性:类型为 DateTimeFormat.ISO。指定解析/格式化字段数据的ISO模式,包括四种:ISO.NONE(不使用) -- 默认、ISO.DATE(yyyy-MM-dd)ISO.TIME(hh:mm:ss.SSSZ)ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
  • style 属性:字符串类型。通过样式指定日期时间的格式,由两位字符组成,第一位表示日期的格式,第二位表示时间的格式:S:短日期/时间格式、M:中日期/时间格式、L:长日期/时间格式、F:完整日期/时间格式、-:忽略日期或时间格式

数值格式化

@NumberFormat 可对类似数字类型的属性进行标注,它拥有两个互斥的属性:

  • style:类型为 NumberFormat.Style。用于指定样式类型,包括三种:Style.NUMBER(正常数字类型)、Style.CURRENCY(货币类型)、 Style.PERCENT(百分数类型)
  • pattern:类型为 String,自定义样式,如patter="#,###"

格式化示例

<mvc:annotation-driven></mvc:annotation-driven>
public class User {
    @DateTimeFormat(pattern="yyyy/MM/dd")
    private Date birthday;

    @NumberFormat(pattern="#,###.###")
    private Double wages;
}
@RequestMapping("/handle19")
public String handle19(@ModelAttribute("user") User user) {
    user.setId(1000);
    System.out.println(user);
    return "success";
}
posted @   Nemo&  阅读(404)  评论(0编辑  收藏  举报
编辑推荐:
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 2025成都.NET开发者Connect圆满结束
点击右上角即可分享
微信分享提示