springboot日期格式化及時差問題分析
提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
前言
隨著mysql8.0的問世,里面確實增加了很多功能,例如之前我發(fā)表的文章,數(shù)據(jù)庫層面的遞歸查詢等;不過也隨之而來帶來了一些不兼容的問題,比如group by 報錯,還有就是日期時差問題;
一、mysql中日期字段的正確設(shè)置
create_time timestamp default CURRENT_TIMESTAMP not null comment '創(chuàng)建時間', update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '修改時間'
創(chuàng)建時間會自動獲取當前時間
修改數(shù)據(jù)的時候,會自動更新 修改時間,免去了每次程序都要設(shè)置的麻煩
二、日期格式化,時差
1. 日期字段返回格式不正確–方案一
例如一個實體中內(nèi)容如下
@Data
public class AAA{
//創(chuàng)建時間
private Date createTime;
//修改時間
private Date updateTime;
}這樣的話,返回的日期格式就錯誤的,其次也會導(dǎo)致時間會早于數(shù)據(jù)庫的真正時間八小時。我們可以有兩種選擇,直接對當前字段設(shè)置日期格式
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")//取日期時使用 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")//存日期時使用
也就是這樣
@Data
public class AAA{
//創(chuàng)建時間
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")//取日期時使用
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")//存日期時使用
private Date createTime;
//修改時間
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")//取日期時使用
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")//存日期時使用
private Date updateTime;
}是不是很煩呀每次都要對每個實體類中的每個日期字段都添加
2.日期字段返回格式不正確–方案二
全局設(shè)置日期格式化的格式,并且全局聲名所有日期 的 補差 八小時,設(shè)置yml即可
spring:
profiles:
active: dev
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8二、日期無法自動填充
由于我已經(jīng)設(shè)置了創(chuàng)建時間的自動填充,和修改時間的自動修改,在數(shù)據(jù)庫層面已經(jīng)沒有問題了,但是當我用mybatis的時候,由于insertselective 等的字段非空判斷,導(dǎo)致就不會生成創(chuàng)建時間和修改時間;咋搞?
對于次問題,我們通過攔截器,全局設(shè)置自動填充日期等統(tǒng)一信息,還可以有創(chuàng)建人,修改人等;
1. mybatis-plus
由于mp提供了注解,我們可以通過設(shè)置一個注解就可以搞定填充問題
@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
2. mybatis 只能靠自己了
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
/**
* mybatis 攔截器字段自動填充
**/
@Slf4j
@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class MybatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
log.debug("------sqlId------" + mappedStatement.getId());
// sql類型:insert、update、select、delete
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Object parameter = invocation.getArgs()[1];
log.debug("------sqlCommandType------" + sqlCommandType);
if (parameter == null) {
return invocation.proceed();
}
// 當sql為新增或更新類型時,自動填充操作人相關(guān)信息
if (SqlCommandType.INSERT == sqlCommandType) {
Field[] fields = getAllFields(parameter);
for (Field field : fields) {
try {
//注入創(chuàng)建時間
if ("createTime".equals(field.getName())) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
//注入修改時間
if ("updateTime".equals(field.getName())) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
} catch (Exception e) {
log.error("failed to insert data, exception = ", e);
}
}
}
if (SqlCommandType.UPDATE == sqlCommandType) {
Field[] fields = getAllFields(parameter);
for (Field field : fields) {
try {
if ("updateTime".equals(field.getName())) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
} catch (Exception e) {
log.error("failed to update data, exception = ", e);
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
/**
* 獲取類的所有屬性,包括父類
*
* @param object
* @return
*/
private Field[] getAllFields(Object object) {
Class<?> clazz = object.getClass();
List<Field> fieldList = new ArrayList<>();
while (clazz != null) {
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
}
1 MybatisInterceptor
2 MybatisConfiguration
廢話不多說,直接上代碼
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
/**
* mybatis 攔截器字段自動填充
**/
@Slf4j
@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class MybatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
log.debug("------sqlId------" + mappedStatement.getId());
// sql類型:insert、update、select、delete
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Object parameter = invocation.getArgs()[1];
log.debug("------sqlCommandType------" + sqlCommandType);
if (parameter == null) {
return invocation.proceed();
}
// 當sql為新增或更新類型時,自動填充操作人相關(guān)信息
if (SqlCommandType.INSERT == sqlCommandType) {
Field[] fields = getAllFields(parameter);
for (Field field : fields) {
try {
//注入創(chuàng)建時間
if ("createTime".equals(field.getName())) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
//注入修改時間
if ("updateTime".equals(field.getName())) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
} catch (Exception e) {
log.error("failed to insert data, exception = ", e);
}
}
}
if (SqlCommandType.UPDATE == sqlCommandType) {
Field[] fields = getAllFields(parameter);
for (Field field : fields) {
try {
if ("updateTime".equals(field.getName())) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
} catch (Exception e) {
log.error("failed to update data, exception = ", e);
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
/**
* 獲取類的所有屬性,包括父類
*
* @param object
* @return
*/
private Field[] getAllFields(Object object) {
Class<?> clazz = object.getClass();
List<Field> fieldList = new ArrayList<>();
while (clazz != null) {
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
}
/**
* mybatis 攔截器注入
**/
@Configuration
public class MybatisConfiguration {
/**
* 注冊攔截器
*/
@Bean
public MybatisInterceptor getMybatisInterceptor() {
return new MybatisInterceptor();
}
}總結(jié)
如上就解決了大部分項目中時間的問題,歡迎討論,咨詢~~
到此這篇關(guān)于springboot日期格式化,時差問題的文章就介紹到這了,更多相關(guān)springboot日期格式化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot中的靜態(tài)資源加載順序優(yōu)先級
這篇文章主要介紹了springboot中的靜態(tài)資源加載順序優(yōu)先級,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
spring中實現(xiàn)容器加載完成后再執(zhí)行自己的方法
這篇文章主要介紹了spring中實現(xiàn)容器加載完成后再執(zhí)行自己的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02
解決idea默認帶的equals和hashcode引起的bug
這篇文章主要介紹了解決idea默認帶的equals和hashcode引起的bug,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

