SpringMVC日期参数绑定

  • 我们再项目中多多少少都使用过SprigMVC的参数绑定,只要参数名一致就可以避免从request中获取数据。
  • 项目中,我们更习惯使用DTO来接收数据,当对象中存在如java.util.Date类型的时候。SpringMvc 的请求中的参数(字符串)默认是不能自动地转换为日期的。
  • 需要使用 Converter, InitBinder 或者 Formatter 来把请求中的参数转换为日期。

使用 Converter

Converter 是全局的,可以在所有 Controller 中使用。

  1. 定义字符串转换为日期的类 DateConverter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package top.fulsun.converter;

    import org.springframework.core.convert.converter.Converter;

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
    String pattern = source.length()==10 ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm:ss";
    SimpleDateFormat format = new SimpleDateFormat(pattern);

    try {
    return format.parse(source);
    } catch (ParseException e) {
    e.printStackTrace();
    }

    return null;
    }
    }
  2. SpringMvc 的配置文件中注册 Converter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <mvc:annotation-driven conversion-service="customConversionService">
    </mvc:annotation-driven>

    <bean id="customConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
    <set>
    <bean class="top.fulsun.converter.DateConverter"/>
    </set>
    </property>
    </bean>
  3. 处理请求

    1
    2
    3
    4
    5
    6
    @GetMapping("/to-date")
    @ResponseBody
    public Date toDate(Date date) {
    System.out.println("=========>" + date);
    return date;
    }

使用 InitBinder

注意:

@InitBinder(“date”) 中 date 必须和 请求方法toDate(Date date) 中的 date 名字一样,当然,请求的参数中也必须有名为 date 的参数。

@InitBinder 只能在当前 Controller 中使用,当有多个地方都需要把参数转换为日期对象,则使用 Converter 更适合。

  1. Controller 中定义 InitBinder

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    /**
    * @InitBinder用于在控制器(Controller)中标注于方法上,表示为当前控制器注册一个属性编辑器,只对当前的Controller有效。
    * 第二个参数true表示允许传入的时间为空 如: url?startTime=&name=张
    */
    @InitBinder("date")
    public void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try{
    // 不适用严格解析模式,数据类型不对抛出异常
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }catch (Exception e){
    throw new ApplicationException("时间格式错误", e);
    }

    }
  2. 处理请求

    1
    2
    3
    4
    5
    6
    @GetMapping("/to-date")
    @ResponseBody
    public Date toDate(Date date) {
    System.out.println("=========>" + date);
    return date;
    }

入/出参格式化

  • @DateTimeFormat转换前端string类型到后端date类型,此字段一般加到属性上面, 前台给后台传值时用
  • @JsonFormat转换后端date类型到前端string类型,如果只用到此注解,加到属性上或者方法上都可以;后台传值给前台时
  • @JsonFormat不仅可以完成后台到前台参数传递的类型转换,还可以实现前台到后台类型转换。
  • 当content-type为application/json时,优先使用@JsonFormat的pattern进行类型转换。而不会使用@DateTimeFormat进行类型转换。
  • @JsonFormat注解的作用就是完成json字符串到java对象的转换工作,与参数传递的方向无关。
  • 使用 Spring 的 @DateTimeFormat 注解格式化参数,pattern 属性值指定的日期时间格式

    1
    2
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date date;
  • 如果放回的参数的结果中包含时间,如"date": "2018-08-01T14:25:31.296+0000"。这个格式并不是我们想要的,我们可以将其进行格式化,就需要用到 jackson 的 @JsonFormat 注解。在 spring-boot-start-web 下已经包含了 jackson 相关依赖。

    1
    2
    3
    4
    5
    6
    7
    注解所依赖的jar包
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.7</version>
    </dependency>
  • jackson在序列化时间时是按照国际标准时间GMT进行格式化的。
  • 而在国内默认时区使用的是CST时区,两者相差8小时。可以指定timezone属性解决
  • 属性值上配置

    1
    2
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date date;
  • 配置文件中配置

    1
    2
    3
    # 时间戳统一转换
    spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
    spring.jackson.time-zone=GMT+8

使用String处理

  • 接收的时候使用String ,返回的使用Date对象,可以避免上述方法传参为空报错的问题。

  • 字段描述

    1
    2
    3
    4
    5
    6
    // top.fulsun.app.dto.AppUserQuery
    private String startTime;
    private String endTime;

    // top.fulsun.app.dto.AppUserDto
    private Date createTime = null;
  • sql处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <select id="find" resultType="AppUserDto" parameterType="com.philips.education.app.dto.AppUserQuery" >
    select * from user
    <trim prefix="WHERE" prefixOverrides="AND|OR" >
    <if test="startTime != null and startTime != ''" >
    <![CDATA[
    AND DATE_FORMAT(t_app_user.create_time, '%Y-%m-%d') >= #{startTime, jdbcType=VARCHAR}
    ]]>
    </if>
    <if test="endTime != null and endTime != ''" >
    <![CDATA[
    AND DATE_FORMAT(t_app_user.create_time, '%Y-%m-%d') <= #{endTime, jdbcType=VARCHAR}
    ]]>
    </if>
    </trim>
    </select>