天天看點

SpringMVC Controller層優雅的處理指定類型傳回格式 之 使用Jackson指定注解處理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
        ;
    }
}
           

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

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

 其中我們先看第一個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));
    }

  }
}
           

然後就可以看結果了

不使用注解的情況

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

使用注解後

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

@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;
	}

}
           

[email protected] 處理時間

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

繼續閱讀