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());
        }
    }
}

最后

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

總結

時間參數這個坑還是有點大的,之前都是針對性的處理,只要一變化就沒法了;現在這個還是可以應付基本上會出現的錯誤了;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM