Spring Boot對json資料的處理以及返回資料的封裝
阿新 • • 發佈:2020-12-16
技術標籤: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;
}
}