先創建一個crud的專案,
controller呼叫service呼叫mapper
以下以簡單代碼代替
- controller
@GetMapping("/getUserById")
public String getUserById(String id){
String userById = userService.getUserById(id);
return userById;
}
- service
@Override
public String getUserById(String id) {
// 模擬業務
User user = userMapper.selectById(id);
return user.toString();
}
上面代碼雖然是把資料回傳給前臺了,但是沒有處理例外以及沒有一個明確的標識告訴前端我是成功還是失敗了,此時我們需要封裝一下統一的成功失敗標志來告訴前臺如何處理回傳資料,
使用Lombok 簡單封裝了一個CommonResponse類
@Data
public class CommonResponse {
/**
* 回傳業務碼用來判斷成功失敗
* 200 成功
* 500 失敗
*/
private String code;
/** 描述 */
private String massage;
/** 描述 */
private Object date;
public CommonResponse(String code, String massage, Object date) {
this.code = code;
this.massage = massage;
this.date = date;
}
public static CommonResponse succeed(){
return getCommonResponse(CodeEnum.SUCCESS.getCode(), CodeEnum.SUCCESS.getMassage(), null);
}
public static CommonResponse succeed(Object date){
return getCommonResponse(CodeEnum.SUCCESS.getCode(), CodeEnum.SUCCESS.getMassage(), date);
}
public static CommonResponse succeed(String massage,Object date){
return getCommonResponse(CodeEnum.SUCCESS.getCode(), massage, date);
}
public static CommonResponse error(String massage){
return getCommonResponse(CodeEnum.ERROR.getCode(), massage, null);
}
public static CommonResponse error(String code,String massage){
return getCommonResponse(code, massage, null);
}
public static CommonResponse error(){
return getCommonResponse(CodeEnum.ERROR.getCode(), CodeEnum.ERROR.getMassage(), null);
}
public static CommonResponse getCommonResponse(String code, String massage, Object date){
return new CommonResponse(code,massage,date);
}
}
回傳的controller使用統一的CommonResponse
@GetMapping("/getUserById")
public CommonResponse getUserById(String id){
String userById = userService.getUserById(id);
return CommonResponse.succeed(userById);
}
回傳
{
"code": "200",
"massage": "成功",
"date": "User(id=1, username=嘉文00, password=1000000, age=5555)"
}
上述回傳基本符合預期,但是當程式出現未知例外怎么辦了,
對service改造下
@Override
public String getUserByIdException(String id) {
User user = userMapper.selectById(id);
// 模擬業務例外
int i=5/0;
return user.toString();
}
controller 改造
@GetMapping("/getUserById")
public CommonResponse getUserById(String id){
try{
String userById = userService.getUserById(id);
return CommonResponse.succeed(userById);
}catch(Exception e){
e.printStackTrace();
log.error(e.getMessage());
return CommonResponse.error(e.getMessage());
}
}
上面是不是也可以,通過trycatch來判斷如何回傳,但是這樣代碼中就會出現大量的try catch,是不是很不好看,我們能不能添加一個統一的try呢,答案是可以的,
使用spring提供的統一的例外處理
spring 提供了三種例外捕獲方式,個人比較推薦這一種
@Slf4j
@ControllerAdvice
public class ExceptionHandle {
/**
* 處理未知例外
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public CommonResponse handleException(Exception e){
log.error("系統例外:{}",e.getMessage());
return CommonResponse.error(e.getMessage());
}
/**
* 處理主動拋出的自定義例外
* @param e
* @return
*/
@ExceptionHandler(BusinessException.class)
@ResponseBody
public CommonResponse handleBusinessException(BusinessException e){
log.error("自定義例外:{}",e.getErrMassage());
return CommonResponse.error(e.getErrCode(),e.getErrMassage());
}
}
踩過的坑:
- 這個地方在寫的時候遇到一個坑,因為捕獲例外后的回傳值是CommonResponse,所以要加上注解 @ResponseBody 便于 格式轉換,
- 在配置@ExceptionHandler的時候不能配置兩個相同的Exception,否則會不知道使用哪個而報錯,
這時controller 已經很清晰了,如下:只用處理好業務呼叫,無需處理向上拋出的例外,
@GetMapping("/getUserByIdException")
public CommonResponse getUserByIdException(String id){
String userById = userService.getUserByIdException(id);
return CommonResponse.succeed(userById);
}
@GetMapping("/getUserByIdBusinessException")
public CommonResponse getUserByIdBusinessException(String id){
String userById = userService.getUserByIdBusinessException(id);
return CommonResponse.succeed(userById);
}
當然有時候我們會遇到自己的校驗不通過來終止程式,我們可以throw 一個Exception 或者我們需要定制回傳碼,自定義一個例外類也行,如下簡單示例,大家可以根據自己的業務需求去自定義,
- 自定義例外類BusinessException
@Data
public class BusinessException extends RuntimeException{
private static final long serialVersionUID = 918204099850898995L;
private String errCode;
private String errMassage;
public BusinessException(String errCode,String errMassage){
super(errMassage);
this.errCode = errCode;
this.errMassage = errMassage;
}
}
- service回傳自定義例外
@Override
public String getUserByIdBusinessException(String id) {
User user = userMapper.selectById(id);
// 模擬業務例外
if("1".equals(id)){
throw new BusinessException("400","id為1的資料不支持查詢,");
}
return user.toString();
}
此時我們前端得到的回傳
## 請求
http://localhost:8088/getUserByIdBusinessException?id=1
## 回傳
{
"code": "400",
"massage": "id為1的資料不支持查詢,",
"date": null
}
以上就是統一例外捕獲跟統一的回傳,
另外我們實際專案為了使業務例外好看,統一,我們可以定義一個列舉來存放我們的業務例外資訊,
- 定義一個列舉類
public enum ExceptionEnum {
BUSINESS_NOT_ONE("400","id為1的資料不支持查詢"),
ERR_NOT_LOOK("401","長得太帥不讓看")
// 往后面累加...
;
private String code;
private String desc;
ExceptionEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public void ThrowException(){
ThrowException(code,desc);
}
public void ThrowException(String errMassage){
errMassage = desc +":"+errMassage;
ThrowException(code,errMassage);
}
private BusinessException ThrowException(String code,String desc){
throw new BusinessException(code,desc);
}
}
- 在service 中拋出列舉例外
@Override
public String getUserByIdBusinessExceptionByEnumOne(String id) {
User user = userMapper.selectById(id);
// 模擬業務例外
if("1".equals(id)){
ExceptionEnum.BUSINESS_NOT_ONE.ThrowException();
}
return user.toString();
}
@Override
public String getUserByIdBusinessExceptionByEnumTwo(String id) {
User user = userMapper.selectById(id);
// 模擬業務例外
if("look".equals(id)){
// 可以動態拼接例外資訊
ExceptionEnum.ERR_NOT_LOOK.ThrowException("你說對吧"+id);
}
return user.toString();
}
- 前臺回傳
{
"code": "400",
"massage": "id為1的資料不支持查詢",
"date": null
}
{
"code": "401",
"massage": "長得太帥不讓看:你說對吧look",
"date": null
}
這種做法的好處就是方便管理,一眼就知道自己專案中有多少錯誤,多少例外,但是也會有同學覺得這樣寫好費勁,每次拋例外的時候還要先在列舉類中定義,所以這個做法是專案跟成員而定,
以上是本人拙見,若有不合適之處,歡迎留言指正,
從專案中來到專案中去
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/300902.html
標籤:其他
