首頁 > 軟體

springboot日期格式化及時差問題分析

2022-12-11 14:01:46

提示:文章寫完後,目錄可以自動生成,如何生成可參考右邊的幫助檔案

前言

隨著mysql8.0的問世,裡面確實增加了很多功能,例如之前我發表的文章,資料庫層面的遞迴查詢等;不過也隨之而來帶來了一些不相容的問題,比如group by 報錯,還有就是日期時差問題;

一、mysql中日期欄位的正確設定

create_time timestamp default CURRENT_TIMESTAMP not null comment '建立時間',
update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '修改時間'

建立時間會自動獲取當前時間
修改資料的時候,會自動更新 修改時間,免去了每次程式都要設定的麻煩

二、日期格式化,時差

1. 日期欄位返回格式不正確–方案一

例如一個實體中內容如下

@Data
public class AAA{
   //建立時間
    private Date createTime;
    //修改時間
    private Date updateTime;
 }

這樣的話,返回的日期格式就錯誤的,其次也會導致時間會早於資料庫的真正時間八小時。我們可以有兩種選擇,直接對當前欄位設定日期格式

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")//取日期時使用
   @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")//存日期時使用

也就是這樣

@Data
public class AAA{
   //建立時間
   @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.日期欄位返回格式不正確–方案二

全域性設定日期格式化的格式,並且全域性聲名所有日期 的 補差 八小時,設定yml即可

spring:
  profiles:
    active: dev
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

二、日期無法自動填充

由於我已經設定了建立時間的自動填充,和修改時間的自動修改,在資料庫層面已經沒有問題了,但是當我用mybatis的時候,由於insertselective 等的欄位非空判斷,導致就不會生成建立時間和修改時間;咋搞?

對於次問題,我們通過攔截器,全域性設定自動填充日期等統一資訊,還可以有建立人,修改人等;

1. mybatis-plus

由於mp提供了註解,我們可以通過設定一個註解就可以搞定填充問題

@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為新增或更新型別時,自動填充操作人相關資訊
        if (SqlCommandType.INSERT == sqlCommandType) {

            Field[] fields = getAllFields(parameter);
            for (Field field : fields) {
                try {
                    //注入建立時間
                    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為新增或更新型別時,自動填充操作人相關資訊
        if (SqlCommandType.INSERT == sqlCommandType) {

            Field[] fields = getAllFields(parameter);
            for (Field field : fields) {
                try {
                    //注入建立時間
                    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();
    }
}

總結

如上就解決了大部分專案中時間的問題,歡迎討論,諮詢~~

到此這篇關於springboot日期格式化,時差問題的文章就介紹到這了,更多相關springboot日期格式化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com