1. 程式人生 > 其它 >Spring Boot對json資料的處理以及返回資料的封裝

Spring Boot對json資料的處理以及返回資料的封裝

技術標籤:javaspringBootjavaspring boot

SpringBoot 對Json的配置

jackson 中對null的處理(spring boot 預設)

在實際專案中,我們難免會遇到一些 null 值出現,我們轉 json 時,是不希望有這些 null 出現的,比如
我們期望所有的 null 在轉 json 時都變成 “” 這種空字串,那怎麼做呢?在 Spring Boot 中,我們做一
下配置即可,新建一個 jackson 的配置類:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.
jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.
context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import java.io.IOException; @Configuration public class JacksonConfig { @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class
) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() { @Override public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(""); } }); return objectMapper; } }

使用阿里巴巴FastJson的設定

關於 fastJson 和 jackson 的對比,網上有很多資料可以檢視,主要是根據自己實際專案情況來選擇合適
的框架。從擴充套件上來看,fastJson 沒有 jackson 靈活,從速度或者上手難度來看,fastJson 可以考慮,
我們專案中目前使用的是阿里的 fastJson,挺方便的。

fastJson依賴匯入

使用 fastJson 需要匯入依賴,本次使用 1.2.35 版本,依賴如下:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.35</version>
</dependency>

使用 fastJson 處理 nul

使用 fastJson 時,對 null 的處理和 jackson 有些不同,需要繼承 WebMvcConfigurationSupport
類,然後覆蓋 configureMessageConverters 方法,在方法中,我們可以選擇對要實現 null 轉換的
場景,配置好即可。如下:

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class fastJsonConfig extends WebMvcConfigurationSupport {
  /**
  * 使用阿里 FastJson 作為JSON MessageConverter
  * @param converters
  */
  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>>
converters) {
    FastJsonHttpMessageConverter converter = new
FastJsonHttpMessageConverter();
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(
        // 保留map空的欄位
        SerializerFeature.WriteMapNullValue,
        // 將String型別的null轉成""
        SerializerFeature.WriteNullStringAsEmpty,
        // 將Number型別的null轉成0
        SerializerFeature.WriteNullNumberAsZero,
        // 將List型別的null轉成[]
        SerializerFeature.WriteNullListAsEmpty,
        // 將Boolean型別的null轉成false
        SerializerFeature.WriteNullBooleanAsFalse,
        // 避免迴圈引用
        SerializerFeature.DisableCircularReferenceDetect);
    converter.setFastJsonConfig(config);
    converter.setDefaultCharset(Charset.forName("UTF-8"));
    List<MediaType> mediaTypeList = new ArrayList<>();
    // 解決中文亂碼問題,相當於在Controller上的@RequestMapping中加了個屬性produces
= "application/json"
    mediaTypeList.add(MediaType.APPLICATION_JSON);
    converter.setSupportedMediaTypes(mediaTypeList);
    converters.add(converter);
 }
}

返回結構(重要)

自定義返回結構型別

由於封裝的 json 資料的型別不確定,所以在定義統一的 json 結構時,我們需要用到泛型。統一的 json
結構中屬性包括資料、狀態碼、提示資訊即可,構造方法可以根據實際業務需求做相應的新增即可,一
般來說,應該有預設的返回結構,也應該有使用者指定的返回結構。如下:


import cn.hutool.core.exceptions.ValidateException;
import com.common.enums.ResultCodeEnum;
import com.common.enums.ResultStatusEnum;
//這個程式碼沒有引入,可以將最後一個刪除
import com.common.exceptions.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.net.ConnectException;
import java.sql.SQLException;

/**
 * 統一定義ResponseBody 返回結構
 *
 */
@Data
@Slf4j
public class ResultModel implements Serializable {
    private static final long serialVersionUID = 1071681926787951549L;

    /**
     * 響應業務狀態
     */
    private Integer status;

    /**
     * 業務響應碼, 根據業務響應碼反映異常錯誤型別
     */
    private Integer code;

    /**
     * 響應訊息
     */
    private String msg;

    /**
     * 異常詳細資訊
     */
    private String detailMessage;

    /**
     * 響應中的資料
     */
    private Object data;

    /**
     * 是否請求成功
     */
    private boolean success;

    /**
     * 分頁查詢時有效
     */
    private long total;

    private String token;

    protected ResultModel(Integer status, String msg, Object data, boolean isSuccess) {
        this.status = status;
        this.msg = msg;
        this.data = data;
        this.success = isSuccess;
    }

    public static ResultModel ok() {
        return new ResultModel(ResultCodeEnum.SUCCESS, ResultStatusEnum.OK, ResultStatusEnum.OK.getMsg(), null, true);
    }

    public static ResultModel ok(Object data) {
        return new ResultModel(ResultCodeEnum.SUCCESS, ResultStatusEnum.OK, ResultStatusEnum.OK.getMsg(), data, true);
    }

    public static ResultModel ok(Object data, String msg) {
        return new ResultModel(ResultCodeEnum.SUCCESS, ResultStatusEnum.OK, msg, data, true);
    }

    public static ResultModel ok(Object data, String msg, Integer status) {
        ResultStatusEnum statusEnum = ResultStatusEnum.getByCode(status);
        return new ResultModel(ResultCodeEnum.SUCCESS, statusEnum, msg, data, true);
    }

    public static ResultModel ok(Object data, Integer status) {
        ResultStatusEnum statusEnum = ResultStatusEnum.getByCode(status);
        return new ResultModel(ResultCodeEnum.SUCCESS, statusEnum, statusEnum.getMsg(), data, true);
    }

    public static ResultModel fail() {
        return new ResultModel(ResultCodeEnum.ERROR, ResultStatusEnum.INTERNAL_SERVER_ERROR,
                ResultStatusEnum.INTERNAL_SERVER_ERROR.getMsg(), null, false);
    }

    public static ResultModel fail(String msg) {
        return fail(null, msg);
    }

    public static ResultModel fail(Throwable throwable) {
        return new ResultModel(throwable);
    }

    public static ResultModel fail(Object data, String msg) {
        return new ResultModel(ResultCodeEnum.ERROR, ResultStatusEnum.INTERNAL_SERVER_ERROR, msg, data, false);
    }

    public static ResultModel fail(Object data, String msg, Integer status) {
        ResultStatusEnum statusEnum = ResultStatusEnum.getByCode(status);
        return new ResultModel(ResultCodeEnum.ERROR, statusEnum, msg, data, false);
    }

    public static ResultModel fail(Object data, Integer status) {
        ResultStatusEnum statusEnum = ResultStatusEnum.getByCode(status);
        return new ResultModel(ResultCodeEnum.ERROR, statusEnum, statusEnum.getMsg(), data, false);
    }

    public static ResultModel pageOk(Object data, long total) {
        ResultModel model = new ResultModel(ResultCodeEnum.SUCCESS, ResultStatusEnum.OK, ResultStatusEnum.OK.getMsg(),
                data, true);
        model.setTotal(total);

        return model;
    }

    public static ResultModel format(ResultStatusEnum statusEnum) {
        boolean isSuccess = true;
        ResultCodeEnum codeEnum = ResultCodeEnum.SUCCESS;
        switch (statusEnum) {
            case INVALID_REQUEST:
            case UNAUTHORIZED:
            case FORBIDDEN:
            case NOT_FOUND:
            case INTERNAL_SERVER_ERROR:
                codeEnum = ResultCodeEnum.ERROR;
                isSuccess = false;
                break;
            default:
                break;
        }

        return new ResultModel(codeEnum, statusEnum,
                statusEnum.getMsg(), null, isSuccess);
    }

    public static ResultModel format(ResultStatusEnum statusEnum, String msg, Object data) {

        boolean isSuccess = true;
        ResultCodeEnum codeEnum = ResultCodeEnum.SUCCESS;
        switch (statusEnum) {
            case INVALID_REQUEST:
            case UNAUTHORIZED:
            case FORBIDDEN:
            case NOT_FOUND:
            case INTERNAL_SERVER_ERROR:
                codeEnum = ResultCodeEnum.ERROR;
                isSuccess = false;
                break;
            default:
                break;
        }

        return new ResultModel(codeEnum, statusEnum,
                msg, data, isSuccess);
    }

    private ResultModel(ResultCodeEnum codeEnum, ResultStatusEnum statusEnum, String msg, Object data, boolean isSuccess) {
        this.status = statusEnum.getCode();
        this.code = codeEnum.getCode();
        this.msg = msg;
        this.data = data;
        this.success = isSuccess;
        this.total = 0;
    }

    public ResultModel(Throwable throwable) {
        this.success = false;

        log.error("系統錯誤,", throwable);

        this.status = 500;

        // 獲取詳細資訊
        StringWriter stringWriter= new StringWriter();
        PrintWriter writer= new PrintWriter(stringWriter);
        throwable.printStackTrace(writer);
        StringBuffer buffer= stringWriter.getBuffer();

        this.detailMessage = buffer.toString();
        if (throwable instanceof NullPointerException) {
            this.code = 1001;
            this.msg = "空指標異常";
        } else if (throwable instanceof ClassCastException) {
            this.code = 1002;
            this.msg = "型別強制轉換異常";
        } else if (throwable instanceof ConnectException) {
            this.code = 1003;
            this.msg = "連結失敗";
        } else if (throwable instanceof IllegalArgumentException) {
            this.code = 1004;
            this.msg = "傳遞非法引數異常";
        } else if (throwable instanceof IndexOutOfBoundsException) {
            this.code = 1006;
            this.msg = "下標越界異常";
        } else if (throwable instanceof SecurityException) {
            this.code = 1007;
            this.msg = "安全異常";
        } else if (throwable instanceof SQLException) {
            this.code = 1008;
            this.msg = "資料庫錯誤";
        } else if (throwable instanceof ArithmeticException) {
            this.code = 1009;
            this.msg = "算術運算異常";
        } else if (throwable instanceof ValidationException || throwable instanceof ValidateException) {
            this.code = 1010;
            this.msg = "引數異常," + throwable.getMessage();
        } else if (throwable instanceof BusinessException) {
            this.code = 500;
            this.msg = throwable.getMessage();
        } else if (throwable instanceof UnauthorizedException) {
            this.code = 401;
            this.msg = "許可權認證異常";
        } else if (throwable instanceof ElasticException) {
            this.code = 1011;
            this.msg = "Elastic異常";
        } else if (throwable instanceof RRException) {
            this.code = 1012;
            this.msg = "業務異常";
        } else if (throwable instanceof RuntimeException) {
            this.code = 1013;
            this.msg = "執行時異常";
        } else if (throwable instanceof Exception) {
            this.code = 9999;
            this.msg = "伺服器錯誤";
        }
    }
}



/**
 * 請求資源狀態碼列舉
 *
 */

public enum ResultCodeEnum {
    /**
     * 成功 0
     */
    SUCCESS(0, "請求成功"),
    /**
     * 失敗 1
     */
    ERROR(1, "請求失敗");
    private Integer code;
    private String msg;

    ResultCodeEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

package com.dhcc.mrp.common.enums;


/**
 * HTTP狀態碼
 *
 */
public enum ResultStatusEnum {
    /**
     * 200 請求成功
     */
    OK(200, "OK", "請求成功!"),
    /**
     * 201 建立或者修改資料成功
     */
    CREATED(201, "CREATED", "資源建立成功!"),
    /**
     * 204 刪除資料成功
     */
    NO_CONTENT(204, "NO CONTENT", "伺服器成功處理了請求,但不需要返回任何實體內容!"),
    /**
     * 400 請求有錯誤
     */
    INVALID_REQUEST(400, "INVALID REQUEST", "請求失敗,具體檢視返回業務狀態碼與對應訊息!"),
    /**
     * 401 沒有許可權
     */
    UNAUTHORIZED(401, "Unauthorized", "請求失敗,未經過身份認證!"),
    /**
     * 403 使用者訪問被禁止(已經授權)
     */
    FORBIDDEN(403, "Forbidden", "使用者訪問被禁止!"),
    /**
     * 404 請求不存在
     */
    NOT_FOUND(404, "NOT FOUND", "請求不存在!"),

    /**
     * 405 請求方法不支援
     */
    NOT_SUPPORT(405, "Not Support", "請求方法不支援!"),
    /**
     * 500 伺服器發生錯誤
     */
    INTERNAL_SERVER_ERROR(500, "INTERNAL SERVER ERROR", "伺服器遇到了一個未曾預料的狀況,導致了它無法完成對請求的處理!");

    private Integer code;
    private String name;
    private String msg;

    ResultStatusEnum(Integer code, String name, String msg) {
        this.code = code;
        this.name = name;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public static ResultStatusEnum getByCode(Integer code) {
        if (code == null) {
            // 預設返回200
            return ResultStatusEnum.OK;
        }

        ResultStatusEnum[] types = ResultStatusEnum.values();
        for (ResultStatusEnum type : types) {
            if (type.code.equals(code)) {
                return type;
            }
        }

        return ResultStatusEnum.OK;
    }

}