SpringMVC Controller層優雅的處理指定類型返回格式 之 使用Jackson指定註解處理

Controller層優雅的處理指定類型返回格式  之 使用Jackson指定註解處理

 

一、可以用哪些註解?

      在我們日常開發中可能會有對指定類型的參數統一處理返回,比如金額、日期等等

     下面來介紹幾種簡單的使用Json註解的方式來處理這中統一返回的類型

 

1. @JsonDeserializ 註解     

            Controller層使用@RequestBody時 以set的方式去set指定格式值

2. @JsonSerialize註解       

             Controller層使用 @ResponseBody 時以get的方式去響應給前端指定格式的值

3.@JsonFormat註解

      該註解是針對Date類型直接轉化爲我們想要的模式,比如@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")。當然也可以使用

1和2兩個註解去設置

這三個註解可以用於屬性或者方法上(最好是屬性上)但是需要注意如果在方法上使用則@JsonDeserializ註解只能用在set方法上面@JsonSerialize註解只能用在get方法上面。

 

二、具體使用

1. @JsonSerialize註解與@JsonDeserializ 註解 

源碼

package com.fasterxml.jackson.databind.annotation;

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

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.util.Converter;

/**
通過附加用於配置序列化方面的註解“getter”方法或字段,或值類。
當註解值類時,配置用於實例,但可以被更特定的註解覆蓋(附加到方法或字段上的)。
舉例說明如下:
@JsonSerialize(using= MySerializer.class,
as = MySubClass.class,type= JsonSerialize.Typing.STATIC
)
(這是多餘的,因爲有些屬性會阻塞其他屬性:
具體來說,‘using’優先於‘as’,後者優先
在“類型”設置)
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@com.fasterxml.jackson.annotation.JacksonAnnotation
public @interface JsonSerialize
{
    // 用於顯式指定反序列化器的註解

    /**
     要用於的序列化器類序列化相關聯的值。根據註解的內容,值是帶註解的類的實例(全局使用任何需要類序列化器的地方);
	 或者只用於通過getter方法序列化屬性訪問。
     */
    @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties
    public Class<? extends JsonSerializer> using() default JsonSerializer.None.class;

    /**
	用於序列化內容(元素的序列化器類屬性的集合/數組的值)。只能用於屬性(方法、字段、構造函數),而不是值類本身(因爲它們通常是泛型的)
     */
    @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties
    public Class<? extends JsonSerializer> contentUsing()
        default JsonSerializer.None.class;

    /**
      用於序列化映射鍵的序列化器類帶註解的屬性。只能用於屬性(方法、字段、構造函數),而不是類本身的值。
     */
    @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties
    public Class<? extends JsonSerializer> keyUsing()
        default JsonSerializer.None.class;

    /**
      用於序列化該屬性的空值的是帶註解的,而不是默認空序列化器。注意,當註解類型(類)具有目前沒有效果(以後可能會改善)。
      @since 2.3
     */
    @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties
    public Class<? extends JsonSerializer> nullsUsing()
        default JsonSerializer.None.class;

    // 用於類型處理的註解,顯式聲明
    // 用於選擇反序列化器的類型,如果不是顯式的
   // 指定

    /**
     超類型(聲明類型的,它本身是運行時類型的超類型)在定位要使用的序列化程序時用作類型。

      僞類型{@link Void}可用於指示聲明的類型類型按原樣使用(即該註解屬性沒有設置);這是因爲註解屬性不允許爲空。
	  注意:如果也使用{@link #using},則它具有優先(因爲它直接指定了,而這僅用於定位序列化器)這個annotation屬性的值將被忽略。
     */
    public Class<?> as() default Void.class;

    /**
	  用於序列化{@link java.util.Map},而不是以其他方式聲明的類型。必須是聲明類型的超類型;否則可能會出現例外拋出的序列化器。
     */
    public Class<?> keyAs() default Void.class;

    /**
     Concrete type to serialize content value (elements
     of a Collection/array, values of Maps) as,
     instead of type otherwise declared.
     Must be a supertype of declared type; otherwise an exception may be
     thrown by serializer.
	 用於序列化內容值(元素)的具體類型的集合/數組,映射的值)爲,而不是以其他方式聲明的類型。必須是聲明類型的超類型;否則可能會出現例外拋出的序列化器。
     */
    public Class<?> contentAs() default Void.class;
    
    /**
      Whether type detection used is dynamic or static: that is,
      whether actual runtime type is used (dynamic), or just the
      declared type (static).
      Note that Jackson 2.3 changed default to <code>DEFAULT_TYPING</code>,
      which is roughly same as saying "whatever".
      This is important as it allows avoiding accidental overrides
      at property level.
	  
	  使用的類型檢測是動態的還是靜態的:是否使用實際運行時類型(動態),或者僅使用聲明類型(靜態)。
      注意Jackson 2.3將默認值更改爲DEFAULT_TYPING,這大致相當於說“任何”。這很重要,因爲它允許避免意外覆蓋在屬性級別。
     */
    public Typing typing() default Typing.DEFAULT_TYPING;

    // 指定中間轉換器的註解(2.2+)
    
    /**
  要使用哪個helper對象將類型轉換爲內容Jackson知道如何序列化;要麼是因爲基類型不能輕易序列化,或者只是爲了改變序列化。
     *
     * @since 2.2
     */
    @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties
    public Class<? extends Converter> converter() default Converter.None.class;

    /**
     Similar to {@link #converter}, but used for values of structures types
     (List, arrays, Maps).
     Note that this property does NOT have effect when used as Class annotation;
     it can only be used as property annotation: this because association between
     container and value types is loose and as such converters seldom make sense
     for such usage.
	 類似於{@link #converter},但用於結構類型的值(List, arrays, Maps)。
     注意,當用作類註解時,此屬性沒有作用;這樣的用法它只能用作屬性註解:這是因爲關聯容器和值類型是鬆散的,因此這種轉換器很少有意義

     *
     * @since 2.2
     */
    @SuppressWarnings("rawtypes") // to work around JDK8 bug wrt Class-valued annotation properties
    public Class<? extends Converter> contentConverter() default Converter.None.class;
    
    // 包含標準的註解

    /**
     註解Bean的哪些屬性被包含在序列化中(對其他類型沒有影響例如枚舉、原語或集合)。
	 選項是"all" "properties that have value other than null"以及“具有非默認值的屬性”(即默認值爲使用默認no-arg構造的Bean設置屬性構造函數,通常是零)。
     這個屬性已經被專用的@deprecated替換。注意Jackson 2.3將default更改爲DEFAULT_INCLUSION,這大致相當於說“隨便”。這很重要,因爲它允許使用分層的默認值。
     */
    @Deprecated
    public Inclusion include() default Inclusion.DEFAULT_INCLUSION;
    
    /*
    /**********************************************************
    /* 枚舉值需要
    /**********************************************************
     */

    /**
      Enumeration used with {@link JsonSerialize#include} property
      to define which properties
      of Java Beans are to be included in serialization
	 枚舉與 @Deprecated 屬性一起使用定義哪些屬性的Java bean將包含在序列化中
     */
    @Deprecated // since 2.0, marked deprecated in 2.6
    public enum Inclusion
    {
        /**
        值,該值指示始終包含屬性,獨立的價值
         */
        ALWAYS,

        /**
          值,該值指示僅具有非null屬性要包含值。
         */
        NON_NULL,

        /**
        值,該值指示只有具有值的屬性不同於默認設置(即它們擁有的值當Bean用它的無參數構造函數構造時)包括在內。值通常是沒有用的
		 {@link java.util。Map},因爲它們沒有默認值;如果使用,工作方式與{@link #ALWAYS}相同。
         */
        NON_DEFAULT,

        /**
          值,該值指示只有具有值的屬性爲空或被認爲爲空的值爲不包括在內。空被定義爲以下類型:
		   List和Map方法isEmpty()被調用;
              對於Java數組,空數組是長度爲0的數組
           用於Java String, length() 返回值0表示空字符串
           對於其他類型,將包含非空值。
         */
        NON_EMPTY,

        /**
         用於指示的僞值“使用上級默認使用的任何內容”。
         */
        DEFAULT_INCLUSION
        ;
    }

    /**
      與Typing屬性一起使用的枚舉,用於定義類型檢測是基於動態運行時類型(動態)還是聲明的類型(靜態)。
     */
    public enum Typing
    {
        /**
        值,該值指示實際的動態運行時類型爲被使用。
         */
        DYNAMIC,

        /**
         值,該值指示將使用靜態聲明類型
         */
        STATIC,
        
        /**
         用於指示的僞值“使用上級默認使用的任何內容”。
         */
        DEFAULT_TYPING
        ;
    }
}

 我們可以看裏面有很多屬性

 其中我們先看第一個using

 在源碼中顯示該註解屬性的值必須是一個繼承了JsonSerializer的class

public Class<? extends JsonSerializer> using() default JsonSerializer.None.class;

 走進JsonSerializer 源碼

 

 /**
       可調用該方法來要求實現序列化此序列化程序句柄類型的值。
     *
     * @param value Value to serialize; can <b>not</b> be null.
     * @param gen Generator used to output resulting Json content
     * @param serializers Provider that can be used to get serializers for
     *   serializing Objects value contains, if any.
     */
    public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers)
        throws IOException, JsonProcessingException;

 其中只有一個待實現的方法 serialize 方法並且他還有三個參數

       1.value  也就是我們待處理的值

        2.gen    用於輸出結果Json內容的gen生成器

       有這兩個呢我們就已經可以簡單知道需要怎麼操作了,下面我以統一處理BigDecimal爲例

我們日常處理金額會有一個金額乘以100 然後返回給前端,前端要是使用則除以一百即可

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.math.BigDecimal;

/**
 * 浮點型乘100返回整型統一json註解處理
 *
 * 直接在字段上面添加一下註解
 *
 *  例如:
 *   @JsonSerialize(using = BigDecimalJsonSerialize.class)
 *   private BigDecimal productPrice;
 * @Author 王福強
 * @Since 2019年06月03日 15:15
 * @Email [email protected]
 */
public class BigDecimalJsonSerialize extends JsonSerializer<BigDecimal> {
  private BigDecimal oneHundred = new BigDecimal(100);
  @Override
  public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
    if(value != null) {
      //最後輸出的值    value.multiply() 是乘以某個指定值,上面定義了100 所以這裏就是*100
      gen.writeNumber(value.multiply(oneHundred));
    }

  }
}

 

然後就可以看結果了

不使用註解的情況

使用註解後

 

 

@JsonDeserializ 與@ JsonSerialize 其實也差不多  需要實現該方法

   public abstract T deserialize(JsonParser p, DeserializationContext ctxt)
        throws IOException, JsonProcessingException;

 

 將前端傳過來的*100 的整數除以一百轉換爲浮點數


public class BigDecimalJsonDeserialize extends JsonDeserializer<BigDecimal> {
 
	private BigDecimal oneHundred = new BigDecimal(100);
 
	@Override
	public BigDecimaldeserialize(JsonParser jp, DeserializationContext ctxt)
			throws IOException, JsonProcessingException {
 
		  Number numberValue = null;
    BigDecimal divide = null;
    try {
      numberValue = jp.getNumberValue();
      BigDecimal bigDecimal = new BigDecimal(numberValue.intValue());
      divide = bigDecimal.divide(oneHundred, 2, BigDecimal.ROUND_HALF_UP);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return divide;
	}

}

2.@JsonFormat 處理時間

@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")
 private Date expiredDate;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章