全局异常拦截和返回值封装共分为五个类,分别是错误码枚举类、返回值封装类、自定义业务异常类、全局拦截类、全局返回值处理类。
错误码枚举类
用来定义返回值的错误码。
package com.masy.global.exception;
/**
* @ClassName ErrorCode
* @Description 错误码枚举
* @Author masy
* @Date 2023/4/322:18
**/
public enum ErrorCode {
/*成功*/
SUCCESS(0, "成功"),
FAIL(500, "失败"),
SYSTEM_ERROR(10000, "系统异常"),
PARAM_ERROR(10100, "参数异常"),
USER_AUTH_FAIL(20001, "用户鉴权失败"),
;
private Integer code;
private String msg;
ErrorCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public static String getMsgByCode(Integer code) {
for (ErrorCode ec : values()) {
if (ec.getCode().equals(code)) {
return ec.getMsg();
}
}
return null;
}
}
返回值封装类
用来将返回值统一封装。
package com.masy.global.exception;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @ClassName Result
* @Description 返回值封装
* @Author masy
* @Date 2023/4/322:18
**/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1581329103599839148L;
private boolean success;
private Integer code;
private String msg;
private T data;
private LocalDateTime timestamp = LocalDateTime.now();
public Result() {
this.success = true;
this.code = ErrorCode.SUCCESS.getCode();
this.msg = ErrorCode.SUCCESS.getMsg();
}
public Result(boolean success) {
this.success = success;
this.code = success ? ErrorCode.SUCCESS.getCode() : ErrorCode.FAIL.getCode();
this.msg = success ? ErrorCode.SUCCESS.getMsg() : ErrorCode.FAIL.getMsg();
this.timestamp = LocalDateTime.now();
}
public void setCode(Integer code) {
this.code = code;
}
public void setSuccess(boolean success) {
this.success = success;
}
public void setData(T data) {
this.data = data;
}
public void setMsg(String msg) {
this.msg = msg;
}
public static <T> Result<T> success() {
Result<T> res = new Result<>();
res.setSuccess(true);
res.setCode(ErrorCode.SUCCESS.getCode());
res.setMsg(ErrorCode.SUCCESS.getMsg());
return res;
}
public static <T> Result<T> success(T data) {
Result<T> res = new Result<>();
res.setSuccess(true);
res.setCode(ErrorCode.SUCCESS.getCode());
res.setMsg(ErrorCode.SUCCESS.getMsg());
res.setData(data);
return res;
}
public static <T> Result<T> fail(ErrorCode errorResponse) {
Result<T> res = new Result<>();
res.setSuccess(false);
res.setCode(errorResponse.getCode());
res.setMsg(errorResponse.getMsg());
return res;
}
public static <T> Result<T> fail(ErrorCode errorResponse, T data) {
Result<T> res = new Result<>();
res.setSuccess(false);
res.setCode(errorResponse.getCode());
res.setMsg(errorResponse.getMsg());
res.setData(data);
return res;
}
public boolean isSuccess() {
return success;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public T getData() {
return data;
}
public LocalDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
}
自定义业务异常类
用来抛出业务异常。
package com.masy.global.exception;
/**
* @ClassName BusinessException
* @Description 业务异常
* @Author masy
* @Date 2023/4/322:18
**/
public class BusinessException extends RuntimeException {
private ErrorCode errorCode;
public BusinessException() {
this.errorCode = ErrorCode.FAIL;
}
public BusinessException(ErrorCode errorCode) {
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
}
全局异常拦截类
用来拦截抛出的异常,做处理。
package com.masy.global.exception;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @ClassName GlobalExceptionHandler
* @Description 全局异常拦截
* @Author masy
* @Date 2023/4/322:18
**/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 空指针异常
*
* @param e 异常
* @return com.masy.global.exception.Result<?>
* @author masy
* @date 2023/4/3 22:46
*/
@ExceptionHandler(value = NullPointerException.class)
public Result<?> handler(NullPointerException e) {
return Result.fail(ErrorCode.SYSTEM_ERROR);
}
/**
* 参数异常
*
* @param e 异常
* @return com.masy.global.exception.Result<?>
* @author masy
* @date 2023/4/3 22:46
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result<?> handler(MethodArgumentNotValidException e) {
return Result.fail(ErrorCode.PARAM_ERROR);
}
/**
* 捕获业务异常
*
* @param e 异常
* @return com.masy.global.exception.Result<?>
* @author masy
* @date 2023/4/3 22:46
*/
@ExceptionHandler(value = BusinessException.class)
public Result<?> handler(BusinessException e) {
return Result.fail(e.getErrorCode());
}
/**
* 捕获其他异常
*
* @param e 异常
* @return com.masy.global.exception.Result<?>
* @author masy
* @date 2023/4/3 22:46
*/
@ExceptionHandler(value = Exception.class)
public Result<?> handler(Exception e) {
return Result.fail(ErrorCode.FAIL);
}
}
全局返回值处理类
用来将返回值统一封装,不用在每个接口中封装。
package com.masy.global.config;
import com.masy.global.exception.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @ClassName ResponseResultAdvice
* @Description 返回数据封装
* @Author masy
* @Date 2023/4/323:49
**/
@RestControllerAdvice
public class ResponseResultAdvice implements ResponseBodyAdvice<Object> {
/**
* 跳过判断是否有返回值,直接调用beforeBodyWrite
*
* @param returnType 返回值类型
* @param converterType
* @return boolean
* @author masy
* @date 2023/4/3 23:50
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result) {
return body;
} else {
return Result.success(body);
}
}
}
使用
package com.masy.global.controller;
import com.alibaba.fastjson.JSON;
import com.masy.global.exception.BusinessException;
import com.masy.global.exception.ErrorCode;
import com.masy.global.exception.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName Test
* @Description TODO
* @Author masy
* @Date 2023/4/322:54
**/
@RestController
@RequestMapping("test")
public class Test {
@GetMapping()
public Map<String,String> test() {
Map<String,String> map = new HashMap<>();
map.put("a","1");
return map;
}
@GetMapping("success")
public Result<Map<String,String>> test1() {
Map<String,String> map = new HashMap<>();
map.put("a","1");
return Result.success(map);
}
@GetMapping("fail")
public Result<String> fail(){
throw new BusinessException(ErrorCode.PARAM_ERROR);
}
}
返回效果