參考文章:https://mp.weixin.qq.com/s/qwzXJ9WDeTAsSsO2297CYQ
https://www.cnblogs.com/xuwujing/p/10933082.html
目錄
(1)統一結果返回
目前的前後端開發大部分數據的傳輸格式都是json,因此定義一個統一規範的數據格式有利於前後端交互與UI 的展示。
統一結果的一般格式: 1.是否響應 2.響應狀態碼 3.狀態碼的描述 4.響應數據5.其他標識符
a. ResultCodeEnum
package com.test.common.result;
import lombok.Getter;
/**
* @Author tanghh
* @Date 2020/4/30 11:06
*/
@Getter
public enum ResultCodeEnum {
SUCCESS(true,20000,"成功"),
UNKNOWN_ERROR(false,20001,"未知錯誤"),
PARAM_ERROR(false,20002,"參數錯誤"),
;
// 響應是否成功
private Boolean success;
// 響應狀態碼
private Integer code;
// 響應信息
private String message;
ResultCodeEnum(boolean success, Integer code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
}
b.統一返回結果類
package com.test.common.result;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* @Author tanghh
* @Date 2020/4/30 13:44
*/
@Data
public class R {
private Boolean success;
private Integer code;
private String message;
private Map<String, Object> data = new HashMap<>();
// 構造器私有
private R(){}
// 通用返回成功
public static R ok() {
R r = new R();
r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
r.setCode(ResultCodeEnum.SUCCESS.getCode());
r.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return r;
}
// 通用返回失敗,未知錯誤
public static R error() {
R r = new R();
r.setSuccess(ResultCodeEnum.UNKNOWN_ERROR.getSuccess());
r.setCode(ResultCodeEnum.UNKNOWN_ERROR.getCode());
r.setMessage(ResultCodeEnum.UNKNOWN_ERROR.getMessage());
return r;
}
// 設置結果,形參爲結果枚舉
public static R setResult(ResultCodeEnum result) {
R r = new R();
r.setSuccess(result.getSuccess());
r.setCode(result.getCode());
r.setMessage(result.getMessage());
return r;
}
/**------------使用鏈式編程,返回類本身-----------**/
// 自定義返回數據
public R data(Map<String,Object> map) {
this.setData(map);
return this;
}
// 通用設置data
public R data(String key,Object value) {
this.data.put(key, value);
return this;
}
// 自定義狀態信息
public R message(String message) {
this.setMessage(message);
return this;
}
// 自定義狀態碼
public R code(Integer code) {
this.setCode(code);
return this;
}
// 自定義返回結果
public R success(Boolean success) {
this.setSuccess(success);
return this;
}
}
c.寫一個接口。
package com.test.controller;
import com.test.common.result.R;
import com.test.model.Student;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* @Author tanghh
* @Date 2020/4/30 13:45
*/
@RestController
@RequestMapping("/test")
public class TestResultController {
@GetMapping(value = "/listAllStudent")
public R list() {
List<Student> list = new ArrayList<>();
Student student1 = new Student(1,"soup");
Student student2 = new Student(2,"soup_tang");
list.add(student1);
list.add(student2);
return R.ok().data("items", list).message("用戶列表");
}
}
d.測試一下這個返回結果的類
在瀏覽器上訪問 http://localhost:8006/test/listAllStudent
(2) 統一異常處理
在使用統一返回結果時,對於在程序運行時有些異常我們無法提前預知,不能走到我們return的R對象返回,這個時候我們就需要定義一個統一的全局異常來捕獲這些信息,並作爲一種結果返回控制層
@ControllerAdvice
改註解爲統一異常處理的核心,是一種作用於控制層的切面通知(Advice),該註解能夠將通用的@ExceptionHandler
@InitBinder 和@ModelAttributes 方法收集到一個類型,並作用到所有控制器上。
該類的設計思路:
- 使用@ExceptionHandler 註解捕獲指定或自定義的異常;
- 使用@ControllerAdvice 集成@ExceptionHandler 的方法到一個類中;
- 必須定義一個通用的異常捕獲方法,遍於捕獲未定義的異常信息;
- 自定義一個異常類,捕獲針對項目或業務的異常;
- 異常的對象信息補充到統一結果枚舉中;
(1)自定義基礎接口類
整個路徑的文件如下:(我這邊爲了方便演示,直接將不同包下的文件放到這個一個包了,開發的時候不要學我,)
首先定義一個基礎的接口類,自定義的錯誤描述枚舉類需實現該接口。
package com.test.common.exception;
/**
* @Author tanghh
* @Date 2020/4/30 17:06
*/
public interface BaseErrorInfoInterface {
/**
* 錯誤碼
* @return
*/
String getResultCode();
/**
* 錯誤描述
* @return
*/
String getResultMsg();
}
(2)自定義一個枚舉類,實現上述接口。
package com.test.common.exception;
/**
* @Author tanghh
* @Date 2020/4/30 17:06
*/
public enum CommonEnum implements BaseErrorInfoInterface {
// 數據操作錯誤定義
SUCCESS("200", "成功!"),
BODY_NOT_MATCH("400","請求的數據格式不符!"),
SIGNATURE_NOT_MATCH("401","請求的數字簽名不匹配!"),
NOT_FOUND("404", "未找到該資源!"),
INTERNAL_SERVER_ERROR("500", "服務器內部錯誤!"),
SERVER_BUSY("503","服務器正忙,請稍後再試!");
/** 錯誤碼 */
private String resultCode;
/** 錯誤描述 */
private String resultMsg;
CommonEnum(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
@Override
public String getResultCode() {
return resultCode;
}
@Override
public String getResultMsg() {
return resultMsg;
}
}
(3)自定義異常子類,用於處理我們發生的業務異常。
package com.test.common.exception;
/**
* @Author tanghh
* @Date 2020/4/30 17:07
*/
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 錯誤碼
*/
protected String errorCode;
/**
* 錯誤信息
*/
protected String errorMsg;
public BizException() {
super();
}
public BizException(BaseErrorInfoInterface errorInfoInterface) {
super(errorInfoInterface.getResultCode());
this.errorCode = errorInfoInterface.getResultCode();
this.errorMsg = errorInfoInterface.getResultMsg();
}
public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
super(errorInfoInterface.getResultCode(), cause);
this.errorCode = errorInfoInterface.getResultCode();
this.errorMsg = errorInfoInterface.getResultMsg();
}
public BizException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg) {
super(errorCode);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg, Throwable cause) {
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public String getMessage() {
return errorMsg;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
(4)自定義數據格式
package com.test.common.exception;
import com.alibaba.fastjson.JSONObject;
/**
* @Author tanghh
* @Date 2020/4/30 17:07
*/
public class ResultBody {
/**
* 響應代碼
*/
private String code;
/**
* 響應消息
*/
private String message;
/**
* 響應結果
*/
private Object result;
public ResultBody() {
}
public ResultBody(BaseErrorInfoInterface errorInfo) {
this.code = errorInfo.getResultCode();
this.message = errorInfo.getResultMsg();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
/**
* 成功
*
* @return
*/
public static ResultBody success() {
return success(null);
}
/**
* 成功
* @param data
* @return
*/
public static ResultBody success(Object data) {
ResultBody rb = new ResultBody();
rb.setCode(CommonEnum.SUCCESS.getResultCode());
rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
rb.setResult(data);
return rb;
}
/**
* 失敗
*/
public static ResultBody error(BaseErrorInfoInterface errorInfo) {
ResultBody rb = new ResultBody();
rb.setCode(errorInfo.getResultCode());
rb.setMessage(errorInfo.getResultMsg());
rb.setResult(null);
return rb;
}
/**
* 失敗
*/
public static ResultBody error(String code, String message) {
ResultBody rb = new ResultBody();
rb.setCode(code);
rb.setMessage(message);
rb.setResult(null);
return rb;
}
/**
* 失敗
*/
public static ResultBody error( String message) {
ResultBody rb = new ResultBody();
rb.setCode("-1");
rb.setMessage(message);
rb.setResult(null);
return rb;
}
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}
(5)自定義全局異常類
package com.test.common.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* @Author tanghh
* @Date 2020/4/30 17:08
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 處理自定義的業務異常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = BizException.class)
@ResponseBody
public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){
logger.error("發生業務異常!原因是:{}",e.getErrorMsg());
return ResultBody.error(e.getErrorCode(),e.getErrorMsg());
}
/**
* 處理空指針的異常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value =NullPointerException.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e){
logger.error("發生空指針異常!原因是:",e);
return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
}
/**
* 處理其他異常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value =Exception.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, Exception e){
logger.error("未知異常!原因是:",e);
return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
}
}
(6)定義一個實體類
package com.test.common.exception;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "student", catalog = "")
public class Student {
private Integer sid;
private String sname;
@Id
@GeneratedValue
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Student() {
}
public Student(Integer sid, String sname) {
setSid(sid);
setSname(sname);
}
}
(7)Controller (爲了測試效果,我這邊弄出了一些異常)
package com.test.common.exception;
/**
* @Author tanghh
* @Date 2020/4/30 17:09
*/
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping(value = "/api")
public class TestStudentController {
@PostMapping("/user")
public boolean insert(@RequestBody Student student) {
System.out.println("開始新增...");
//如果姓名爲空就手動拋出一個自定義的異常!
if(student.getSname()==null){
throw new BizException("-1","用戶姓名不能爲空!");
}
return true;
}
@PutMapping("/user")
public boolean update(@RequestBody Student student) {
System.out.println("開始更新...");
//這裏故意造成一個空指針的異常,並且不進行處理
String str=null;
str.equals("111");
return true;
}
@DeleteMapping("/user")
public boolean delete(@RequestBody Student student) {
System.out.println("開始刪除...");
//這裏故意造成一個異常,並且不進行處理
Integer.parseInt("abc123");
return true;
}
@GetMapping("/user")
public List<Student> findByUser(Student student) {
System.out.println("開始查詢...");
List<Student> userList =new ArrayList<>();
Student student1=new Student(1,"soup_tang");
userList.add(student1);
return userList;
}
}
(8)測試新增(我這邊測試工具用的是postman,)
@PostMapping("/user")
public boolean insert(@RequestBody Student student) {
System.out.println("開始新增...");
//如果姓名爲空就手動拋出一個自定義的異常!
if(student.getSname()==null){
throw new BizException("-1","用戶姓名不能爲空!");
}
return true;
}
(9)測試put 請求,返回請求的格式不符
全局異常是報的是請求的參數格式不符,而後臺內部報的是空指針,全局異常優先處理。
(10) 測試一下刪除方法
@DeleteMapping("/user")
public boolean delete(@RequestBody Student student) {
System.out.println("開始刪除...");
//這裏故意造成一個異常,並且不進行處理
Integer.parseInt("abc123");
return true;
}