亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解SpringBoot統(tǒng)一響應(yīng)體解決方案

 更新時間:2019年07月18日 14:13:16   作者:Null  
這篇文章主要介紹了詳解SpringBoot統(tǒng)一響應(yīng)體解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

最近在優(yōu)化自己之前基于Spring AOP的統(tǒng)一響應(yīng)體的實現(xiàn)方案。

什么是統(tǒng)一響應(yīng)體呢?在目前的前后端分離架構(gòu)下,后端主要是一個RESTful API的數(shù)據(jù)接口。

但是HTTP的狀態(tài)碼數(shù)量有限,而隨著業(yè)務(wù)的增長,HTTP狀態(tài)碼無法很好地表示業(yè)務(wù)中遇到的異常情況。

那么可以通過修改響應(yīng)返回的JSON數(shù)據(jù),讓其帶上一些固有的字段,例如以下這樣的

{
 "code": 10000,
 "msg": "success",
 "data": {
  "id": 2,
  "name": "test"
 }
}

其中關(guān)鍵屬性的用途如下:

  • code為返回結(jié)果的狀態(tài)碼
  • msg為返回結(jié)果的消息
  • data為返回的業(yè)務(wù)數(shù)據(jù)

這3個屬性為固有屬性,每次響應(yīng)結(jié)果都會有帶有它們。

需求

希望實現(xiàn)一個能夠代替基于AOP的實現(xiàn)方案,需要滿足以下幾點:

  1. 原有的基于AOP的實現(xiàn)方案需要Controller的返回類型為Object,需要新方案不限制返回類型
  2. 原有的基于AOP的實現(xiàn)方案需要通過切面表達(dá)式+注解控制切點的Controller(注解的包名修改會導(dǎo)致切面表達(dá)式的修改,即需要修改兩處地方),需要新方案能夠基于注解,而不需要修改切面表達(dá)式

方案思路

基于上述的需求,選擇使用Spring的Controller增強(qiáng)機(jī)制,其中關(guān)鍵的類為以下3個:

  • @ControllerAdvice:類注解,用于指定Controller增強(qiáng)處理器類。
  • ResponseBodyAdvice:接口,實現(xiàn)后beforeBodyWrite()方法后可以對響應(yīng)的body進(jìn)行修改,需要結(jié)合@ControllerAdvice使用。
  • @ExceptionHandler:方法注解,用于指定異常處理方法,需要結(jié)合@ControllerAdvice和@ResponseBody使用。

示例關(guān)鍵代碼

本示例使用的Spring Boot版本為2.1.6.RELEASE,同時需要開發(fā)工具安裝lombok插件

引入依賴

 <dependencies>
  <!--web-starter-->
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <!--lombok-->
  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
  </dependency>

  <!--test-starter-->
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
 </dependencies>

統(tǒng)一響應(yīng)體

Controller增強(qiáng)后統(tǒng)一響應(yīng)體對應(yīng)的對象

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

/**
 * 統(tǒng)一的公共響應(yīng)體
 * @author NULL
 * @date 2019-07-16
 */
@Data
@AllArgsConstructor
public class ResponseResult implements Serializable {
 /**
  * 返回狀態(tài)碼
  */
 private Integer code;
 /**
  * 返回信息
  */
 private String msg;
 /**
  * 數(shù)據(jù)
  */
 private Object data;

}

統(tǒng)一響應(yīng)注解

統(tǒng)一響應(yīng)注解是一個標(biāo)記是否開啟統(tǒng)一響應(yīng)增強(qiáng)的注解

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

/**
 * 統(tǒng)一響應(yīng)注解<br/>
 * 添加注解后,統(tǒng)一響應(yīng)體才能生效
 * @author NULL
 * @date 2019-07-16
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface BaseResponse {

}

狀態(tài)碼枚舉

統(tǒng)一響應(yīng)體中返回的狀態(tài)碼code和狀態(tài)信息msg對應(yīng)的枚舉類

/**
 * 返回狀態(tài)碼
 *
 * @author NULL
 * @date 2019-07-16
 */
public enum ResponseCode {
 /**
  * 成功返回的狀態(tài)碼
  */
 SUCCESS(10000, "success"),
 /**
  * 資源不存在的狀態(tài)碼
  */
 RESOURCES_NOT_EXIST(10001, "資源不存在"),
 /**
  * 所有無法識別的異常默認(rèn)的返回狀態(tài)碼
  */
 SERVICE_ERROR(50000, "服務(wù)器異常");
 /**
  * 狀態(tài)碼
  */
 private int code;
 /**
  * 返回信息
  */
 private String msg;

 ResponseCode(int code, String msg) {
  this.code = code;
  this.msg = msg;
 }

 public int getCode() {
  return code;
 }

 public String getMsg() {
  return msg;
 }
}

業(yè)務(wù)異常類

業(yè)務(wù)異常類是用于識別業(yè)務(wù)相關(guān)的異常,需要注意這個異常類強(qiáng)制需要以ResponseCode作為構(gòu)造方法入?yún)?,這樣可以通過捕獲異常獲得返回的狀態(tài)碼信息

import com.rjh.web.response.ResponseCode;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 業(yè)務(wù)異常類,繼承運(yùn)行時異常,確保事務(wù)正常回滾
 *
 * @author NULL
 * @since 2019-07-16
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class BaseException extends RuntimeException{

 private ResponseCode code;

 public BaseException(ResponseCode code) {
  this.code = code;
 }

 public BaseException(Throwable cause, ResponseCode code) {
  super(cause);
  this.code = code;
 }
}

異常處理類

用于處理Controller運(yùn)行時未捕獲的異常的處理類。

import com.rjh.web.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 異常處理器
 *
 * @author NULL
 * @since 2019-07-16
 */
@ControllerAdvice(annotations = BaseResponse.class)
@ResponseBody
@Slf4j
public class ExceptionHandlerAdvice {
 /**
  * 處理未捕獲的Exception
  * @param e 異常
  * @return 統(tǒng)一響應(yīng)體
  */
 @ExceptionHandler(Exception.class)
 public ResponseResult handleException(Exception e){
  log.error(e.getMessage(),e);
  return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null);
 }

 /**
  * 處理未捕獲的RuntimeException
  * @param e 運(yùn)行時異常
  * @return 統(tǒng)一響應(yīng)體
  */
 @ExceptionHandler(RuntimeException.class)
 public ResponseResult handleRuntimeException(RuntimeException e){
  log.error(e.getMessage(),e);
  return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null);
 }

 /**
  * 處理業(yè)務(wù)異常BaseException
  * @param e 業(yè)務(wù)異常
  * @return 統(tǒng)一響應(yīng)體
  */
 @ExceptionHandler(BaseException.class)
 public ResponseResult handleBaseException(BaseException e){
  log.error(e.getMessage(),e);
  ResponseCode code=e.getCode();
  return new ResponseResult(code.getCode(),code.getMsg(),null);
 }
}

響應(yīng)增強(qiáng)類

Conrtoller增強(qiáng)的統(tǒng)一響應(yīng)體處理類,需要注意異常處理類已經(jīng)進(jìn)行了增強(qiáng),所以需要判斷一下返回的對象是否為統(tǒng)一響應(yīng)體對象。

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 統(tǒng)一響應(yīng)體處理器
 * @author NULL
 * @date 2019-07-16
 */
@ControllerAdvice(annotations = BaseResponse.class)
@Slf4j
public class ResponseResultHandlerAdvice implements ResponseBodyAdvice {

 @Override
 public boolean supports(MethodParameter returnType, Class converterType) {
  log.info("returnType:"+returnType);
  log.info("converterType:"+converterType);
  return true;
 }

 @Override
 public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
  if(MediaType.APPLICATION_JSON.equals(selectedContentType) || MediaType.APPLICATION_JSON_UTF8.equals(selectedContentType)){ // 判斷響應(yīng)的Content-Type為JSON格式的body
   if(body instanceof ResponseResult){ // 如果響應(yīng)返回的對象為統(tǒng)一響應(yīng)體,則直接返回body
    return body;
   }else{
    // 只有正常返回的結(jié)果才會進(jìn)入這個判斷流程,所以返回正常成功的狀態(tài)碼
    ResponseResult responseResult =new ResponseResult(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),body);
    return responseResult;
   }
  }
  // 非JSON格式body直接返回即可
  return body;
 }
}

使用示例

首先準(zhǔn)備一個User對象

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;

/**
 * 用戶類
 * @author NULL
 * @date 2019-07-16
 */
@Data
@EqualsAndHashCode
public class User implements Serializable {

 private Integer id;

 private String name;
 
}

然后是準(zhǔn)備一個簡單的UserController即可

import com.rjh.web.entity.User;
import com.rjh.web.exception.BaseException;
import com.rjh.web.response.BaseResponse;
import com.rjh.web.response.ResponseCode;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 測試用的Controller
 *
 * @author NULL
 * @date 2019-07-16
 */
@BaseResponse
@RestController
@RequestMapping("users")
public class UserController {

 @GetMapping("/{userId}")
 public User getUserById(@PathVariable Integer userId){
  if(userId.equals(0)){
   throw new BaseException(ResponseCode.RESOURCES_NOT_EXIST);
  }
  if(userId.equals(1)){
   throw new RuntimeException();
  }
  User user=new User();
  user.setId(userId);
  user.setName("test");
  return user;
 }
 
}

運(yùn)行結(jié)果

在瀏覽器直接訪問http://127.0.0.1:8080/users/0,則返回結(jié)果如下(結(jié)果經(jīng)過格式化處理):

{
 "code": 10001,
 "msg": "資源不存在",
 "data": null
}

在瀏覽器直接訪問http://127.0.0.1:8080/users/1,則返回結(jié)果如下(結(jié)果經(jīng)過格式化處理):

{
 "code": 50000,
 "msg": "服務(wù)器異常",
 "data": null
}

在瀏覽器直接訪問http://127.0.0.1:8080/users/2,則返回結(jié)果如下(結(jié)果經(jīng)過格式化處理):

{
 "code": 10000,
 "msg": "success",
 "data": {
  "id": 2,
  "name": "test"
 }
}

由運(yùn)行結(jié)果可以得知統(tǒng)一響應(yīng)增強(qiáng)其實已經(jīng)生效了,而且能夠很好的處理異常。

示例代碼地址

下面是這個示例的代碼地址,如果覺得不錯或者幫助到你,希望大家給個Star:

https://github.com/spring-based-solutions/spring-web-unified-response-demo

參考資料

https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-controller-advice
https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-exceptionhandler

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • openFeign服務(wù)之間調(diào)用保持請求頭信息處理方式

    openFeign服務(wù)之間調(diào)用保持請求頭信息處理方式

    這篇文章主要介紹了openFeign服務(wù)之間調(diào)用保持請求頭信息處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • MyBatis-Plus 如何實現(xiàn)連表查詢的示例代碼

    MyBatis-Plus 如何實現(xiàn)連表查詢的示例代碼

    這篇文章主要介紹了MyBatis-Plus 如何實現(xiàn)連表查詢的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • springboot集成es插入和查詢的簡單使用示例詳解

    springboot集成es插入和查詢的簡單使用示例詳解

    這篇文章主要介紹了springboot集成es 插入和查詢的簡單使用,本文分步驟結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • Java簡單實現(xiàn)UDP和TCP的示例

    Java簡單實現(xiàn)UDP和TCP的示例

    下面小編就為大家?guī)硪黄狫ava簡單實現(xiàn)UDP和TCP的示例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • Java中indexOf函數(shù)示例詳解

    Java中indexOf函數(shù)示例詳解

    Java String 類的 indexOf() 方法返回指定字符串中指定字符或字符串第一次出現(xiàn)的位置,這篇文章主要介紹了Java中indexOf函數(shù)詳解,需要的朋友可以參考下
    2024-01-01
  • mybatis?查詢方式與效率高低對比

    mybatis?查詢方式與效率高低對比

    這篇文章主要介紹了mybatis?查詢方式與效率高低對比,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 區(qū)塊鏈常用數(shù)據(jù)庫leveldb用java來實現(xiàn)常規(guī)操作的方法

    區(qū)塊鏈常用數(shù)據(jù)庫leveldb用java來實現(xiàn)常規(guī)操作的方法

    這篇文章主要介紹了區(qū)塊鏈常用數(shù)據(jù)庫leveldb用java來實現(xiàn)常規(guī)操作,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • SpringMVC前端和后端數(shù)據(jù)交互總結(jié)

    SpringMVC前端和后端數(shù)據(jù)交互總結(jié)

    本篇文章主要介紹了SpringMVC前端和后端數(shù)據(jù)交互總結(jié),具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Spring Boot整合RabbitMQ開發(fā)實戰(zhàn)詳解

    Spring Boot整合RabbitMQ開發(fā)實戰(zhàn)詳解

    這篇文章主要介紹了Spring Boot整合RabbitMQ開發(fā)實戰(zhàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Javabean轉(zhuǎn)換成json字符并首字母大寫代碼實例

    Javabean轉(zhuǎn)換成json字符并首字母大寫代碼實例

    這篇文章主要介紹了javabean轉(zhuǎn)成json字符并首字母大寫代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02

最新評論