springboot处理date参数

该图片由grebmot在Pixabay上发布

前言

最近在后台开发中遇到了时间参数的坑,就单独把这个问题提出来找时间整理了一下;

正文

测试方法

bean代码:


public class DateModelNoAnnotation {
    private Integer id;
    private Date receiveDate;
}
    

controller代码:


@RestController
@RequestMapping("/date")
public class DateVerifyController {
    //    方式一
    @PostMapping("/no")
    public String dateUnNoAnnotation(DateModelNoAnnotation dateModelNoAnnotation){
        System.out.println(dateModelNoAnnotation.toString());
        return "SUCCESS";
    }

//    方式二
    @PostMapping("/has")
    public String dateHasAnnotation(@RequestBody DateModelNoAnnotation dateModelNoAnnotation){
        System.out.println(dateModelNoAnnotation.toString());
        return "SUCCESS";
    }
//    方式三
    @GetMapping("/param")
    public String dateParams(@RequestParam("id")Integer id, @RequestParam("receiveDate")Date receiveDate){
        System.out.println("id====="+id);
        System.out.println("receiveDate====="+receiveDate);
        System.out.println("receiveDate====="+receiveDate.getTime());
        return "SUCCESS";
    }
//    方式四
    @GetMapping("/no/param")
    public String dateNoParams(Integer id,Date receiveDate){
        System.out.println("id====="+id);
        System.out.println("receiveDate====="+receiveDate);
        System.out.println("receiveDate====="+receiveDate.getTime());
        return "SUCCESS";
    }
}

接收参数的几种方式(实验)

  1. 通过bean来接收数据(表单方式)
  • 这种方式只支持"yyyy/MM/dd HH:mm:ss"这种格式的time参数
  1. 通过bean来接收数据(json格式)
  • 这种方式只支持"yyyy-MM-dd HH:mm:ss"这种格式的time参数
  1. 通过RequestParam注解
  • 这种方式只支持"yyyy/MM/dd HH:mm:ss"这种格式的time参数
  1. 不通过RequestParam注解
  • 这种方式只支持"yyyy/MM/dd HH:mm:ss"这种格式的time参数

以上几种接收参数的方式接收的参数格式并不统一,而且有时候web前端传入的时间参数为时间戳,还得写修改接口或者让其自己修改格式;
后端给前端统一返回json格式的数据,且时间格式为"yyyy-MM-dd HH:mm:ss"

解决方案

开发之前统一时间接口接收的时间格式

一 yyyy/MM/dd HH:mm:ss 格式

后端所有接口统一接收"yyyy/MM/dd HH:mm:ss"或"yyyy/MM/dd"格式时间参数

第一种: 舍弃上边的方式二的接口

第二种:不舍弃方拾二,在bean的时间属性上添加JsonFormat注解,例如:


    com.fasterxml.jackson.annotation.JsonFormat;
    
    @JsonFormat(timezone = "GMT+8",pattern = "yyyy/MM/dd HH:mm:ss")
    private Date receiveDate;
    

优势: 不舍弃方式二接口,且统一了时间格式

使用该注解的弊端: 当pattern="yyyy/MM/dd" 时, 只支持处理“2019/09/03"格式时间参数,不支持“2019/09/03 00:00:00”,且会报错,当pattern="yyyy/MM/dd HH:mm:ss"时,只支持处理“2019/09/03 00:00:00"格式时间参数,其余格式均会报错;

二 接收所有时间格式

  • yyyy-MM-dd HH:mm:ss 格式
  • yyyy-MM-dd 格式
  • 时间戳
  • yyyy/MM/dd HH:mm:ss 格式
  • yyyy/MM/dd 格式
注意

该方式不对json或xml的数据处理,比如使用@RequestBody注解的bean(也就是方式二)

工具类:


import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @author gyc
 * @title: DateConverter
 * @projectName app
 * @date 2019/8/1914:36
 * @description: 时间转换类
 */
public class CourseDateConverter implements Converter<String, Date> {
    private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";
    private static final String dateFormata = "yyyy-MM-dd HH:mm:ss";
    private static final String shortDateFormat = "yyyy-MM-dd";
    private static final String shortDateFormata = "yyyy/MM/dd";
    private static final String timeStampFormat = "^\\d+$";
    @Override
    public Date convert(String value) {
        if(StringUtils.isEmpty(value)) {
            return null;
        }
        value = value.trim();
        try {
            if (value.contains("-")) {
                SimpleDateFormat formatter;
                if (value.contains(":")) {
                    //yyyy-MM-dd HH:mm:ss 格式
                    formatter = new SimpleDateFormat(dateFormat);
                } else {
                    //yyyy-MM-dd 格式
                    formatter = new SimpleDateFormat(shortDateFormat);
                }
                return formatter.parse(value);
            } else if (value.matches(timeStampFormat)) {
                //时间戳
                Long lDate = new Long(value);
                return new Date(lDate);
            }else if (value.contains("/")){
                SimpleDateFormat formatter;
                if (value.contains(":")) {
//                    yyyy/MM/dd HH:mm:ss 格式
                    formatter = new SimpleDateFormat(dateFormata);
                } else {
//                    yyyy/MM/dd 格式
                    formatter = new SimpleDateFormat(shortDateFormata);
                }
                return formatter.parse(value);
            }
        } catch (Exception e) {
            throw new RuntimeException(String.format("parser %s to Date fail", value));
        }
        throw new RuntimeException(String.format("parser %s to Date fail", value));
    }
}

将时间转换类应用到接口上

介绍两种方式:使用@Component + @PostConstruct或@ControllerAdvice + @InitBinder

第一种方式:

@Component + @PostConstruct

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import javax.annotation.PostConstruct;

@Component
public class WebConfigBeans {
  @Autowired
  private RequestMappingHandlerAdapter handlerAdapter;
  @PostConstruct
  public void initEditableAvlidation() {
    ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer)handlerAdapter.getWebBindingInitializer();
    if(initializer.getConversionService()!=null) {
      GenericConversionService genericConversionService = (GenericConversionService)initializer.getConversionService();

      genericConversionService.addConverter(new DateConverterConfig());

    }
  }
}

第二种方式:

@ControllerAdvice + @InitBinder

import com.aegis.config.converter.DateConverter;
import com.aegis.model.bean.common.JsonResult;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
@ControllerAdvice
public class CourseControllerHandler {
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        GenericConversionService genericConversionService = (GenericConversionService) binder.getConversionService();
        if (genericConversionService != null) {
            genericConversionService.addConverter(new CourseDateConverter());
        }
    }
}

最后

我使用的最后的一种方法的第二种方式

总结

时间参数这个坑还是有点大的,之前都是针对性的处理,只要一变化就没法了;现在这个还是可以应付基本上会出现的错误了;

posted @ 2019-09-03 17:52  guoyuchuan  阅读(6556)  评论(0编辑  收藏  举报