1. 程式人生 > 實用技巧 >java使用自定義註解配合Jackson實現動態輸出花樣時間

java使用自定義註解配合Jackson實現動態輸出花樣時間

前言

在專案中經常越到需要將時間欄位轉化為諸如:幾年前、幾月前、幾天前、幾小時前、分鐘前等等的花樣時間,如果每次都因為一個欄位從資料庫取出後還需要進行一次資料處理這樣對於開發來說是很不友好的,本可以直接取資料返回,現因一個欄位要加一層處理,實在有些繁瑣,這時就需要這樣一個外掛來為您解決開發處理層的問題。
本文章命名為花樣時間處理,實現了通過自定義註解把時間欄位處理為花樣時間然後返回前端。期間對於開發者來說就是在欄位上加入註解,並根據需要新增規則引數,之後便可不用理會,Jackson底層序列化時會自動進行處理。

相關技術

Jackson、Annotation
常用於Spring專案中,因為Spring跟Jackson是天然結合的

編碼

花樣時間級別列舉

該級別用於定義花樣時間的最高階,超過級別則使用具體時間戳

package cn.rc100.common.core.time;

import lombok.AllArgsConstructor;

/**
 * <p>
 * 花樣時間級別
 * </p>
 *
 * @author Tophua
 * @since 2020/8/26
 */
@AllArgsConstructor
public enum TricksTimeLevelEnum {
    /**
     * 分鐘
     */
    MINUTE("分"),
    /**
     * 小時
     */
    HOUR("小時"),
    /**
     * 天
     */
    DAY("天"),
    /**
     * 月
     */
    MONTH("月"),
    /**
     * 年
     */
    YEAR("年");
    /**
     * 級別名稱
     */
    private final String name;
}

註解

package cn.rc100.common.core.time;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <p>
 * 花樣時間註解
 * 帶註解的欄位型別必須是LocalDateTime
 * </p>
 *
 * @author Tophua
 * @since 2020/8/26
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = TricksTimeSerialize.class)
public @interface TricksTime {
    /**
     * 花樣時間級別,超過這個級別返回具體時間
     */
    TricksTimeLevelEnum level() default TricksTimeLevelEnum.HOUR;
    /**
     * 花樣時間級別對應最大值,超過這個最大值返回具體時間
     */
    int maxValue() default 24;
}

核心處理

package cn.rc100.common.core.time;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Objects;

/**
 * <p>
 * 花樣時間序列化
 * </p>
 *
 * @author Tophua
 * @since 2020/8/26
 */
@NoArgsConstructor
@AllArgsConstructor
public class TricksTimeSerialize extends JsonSerializer<LocalDateTime> implements ContextualSerializer {
    private TricksTimeLevelEnum level;
    private int maxValue;

    @Override
    public void serialize(LocalDateTime time, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeObject(time);
        String newField = jsonGenerator.getOutputContext().getCurrentName() + "TricksTime";
        LocalDateTime now = LocalDateTime.now();
        int ordinal = level.ordinal();
        long year = time.until(now, ChronoUnit.YEARS);
        if (ordinal == TricksTimeLevelEnum.YEAR.ordinal() && year > 0) {
            if (year >= maxValue) {
                jsonGenerator.writeObjectField(newField, time);
                return;
            }
            jsonGenerator.writeObjectField(newField, year + "年前");
            return;
        }
        long month = time.until(now, ChronoUnit.MONTHS);
        if (ordinal >= TricksTimeLevelEnum.MONTH.ordinal() && month > 0) {
            if (level == TricksTimeLevelEnum.MONTH && month >= maxValue) {
                jsonGenerator.writeObjectField(newField, time);
                return;
            }
            jsonGenerator.writeObjectField(newField, month + "月前");
            return;
        }
        long day = time.until(now, ChronoUnit.DAYS);
        if (ordinal >= TricksTimeLevelEnum.DAY.ordinal() && day > 0) {
            if (level == TricksTimeLevelEnum.DAY && day >= maxValue) {
                jsonGenerator.writeObjectField(newField, time);
                return;
            }
            jsonGenerator.writeObjectField(newField, day + "天前");
            return;
        }
        long hour = time.until(now, ChronoUnit.HOURS);
        if (ordinal >= TricksTimeLevelEnum.HOUR.ordinal() && hour > 0) {
            if (level == TricksTimeLevelEnum.HOUR && hour >= maxValue) {
                jsonGenerator.writeObjectField(newField, time);
                return;
            }
            jsonGenerator.writeObjectField(newField, hour + "小時前");
            return;
        }
        long minute = time.until(now, ChronoUnit.MINUTES);
        if (ordinal >= TricksTimeLevelEnum.MINUTE.ordinal() && minute > 0) {
            if (level == TricksTimeLevelEnum.MINUTE && minute >= maxValue) {
                jsonGenerator.writeObjectField(newField, time);
                return;
            }
            jsonGenerator.writeObjectField(newField, minute >= 5 ? minute + "分鐘前" : "剛剛");
            return;
        }
        jsonGenerator.writeObjectField(newField, time);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            if (Objects.equals(beanProperty.getType().getRawClass(), LocalDateTime.class)) {
                TricksTime tricksTime = beanProperty.getAnnotation(TricksTime.class);
                if (tricksTime == null) {
                    tricksTime = beanProperty.getContextAnnotation(TricksTime.class);
                }
                if (tricksTime != null) {
                    return new TricksTimeSerialize(tricksTime.level(), tricksTime.maxValue());
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }

}

結果

測試時間 2020-08-27 15:01:37

{
            "id": 1,
            "sn": "BGYZT00001",
            "createTime": "2020-08-27 01:30:46",
            "createTimeTricksTime": "13小時前",
            "updateTime": "2020-08-27 14:21:45",
            "tenantId": 1
        }

總結

實際運用中可以根據此思路完成各種類似的需求,減少重複棗輪子。

我是Tophua
雖然寫不出逆天的程式碼,但是每行程式碼都是規範的。