统一异常处理类
代码中无论是业务成功或者失败,都需要封装返回对象,目前代码中都是哪里用到就在哪里进行封装,因此我们可以封装返回对象,以下是代码:
@Data
public class Result<T> {
private String code;
private String message;
private T data;
public Result(T code, T message, T data) {
this.code = String.valueOf(code);
this.message = String.valueOf(message);
this.data = data;
}
// 请求成功,指定data
public static <T> Result<T> success(T data) {
Result<T> tResult = (Result<T>) new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(), data);
return tResult;
}
// 请求成功,指定data和指定message
public static <T> Result<T> success(String message, T data) {
Result<T> tResult = (Result<T>) new Result<>(ResultEnum.SUCCESS.getCode(), message, data);
return tResult;
}
// 请求失败
public static Result<?> failed() {
return new Result<>(ResultEnum.FAILED.getCode(), ResultEnum.FAILED.getMessage(), null);
}
// 请求失败,指定message
public static Result<?> failed(String message) {
return new Result<>(ResultEnum.FAILED.getCode(), message, null);
}
// 请求失败,指定code和message
public static Result<?> failed(String code, String message) {
return new Result<>(code, message, null);
}
}
返回对象枚举类:
public enum ResultEnum {
SUCCESS("200", "请求成功"),
FAILED("500", "请求失败");
private String code;
private String message;
ResultEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
String resultMessage = code + ":" + message;
return resultMessage;
}
}
统一异常捕获
可以给controller层的方法加上切面来统一处理异常,简化代码中出现的大量try()catch()语句;
用@RestControllerAdvice
注解(@ControllerAdvice
也可以),用来定义controller层的切面,添加@Controller
注解的类中的方法执行都会进入该切面,同时我们可以使用@ExceptionHandler
来对不同的异常进行捕获和处理,对于捕获的异常,我们可以进行日志记录,并且封装返回对象。
import org.example.mongodemo.domain.Result;
import org.example.mongodemo.domain.ResultEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
// 使用@RestControllerAdvice和@ControllerAdvice都是可以的
// @RestControllerAdvice(basePackages = {"org.example.ctrl", "org.example.ctrl", .....}), 指定包路径进行切面,可以指定多个包
// @RestControllerAdvice(basePackageClasses = TestController.class) , 指定Contrller.class进行切面
// @RestControllerAdvice 不带参数默认覆盖所有添加了@Controller注解的类
@RestControllerAdvice
public class MyControllerAdviceHanlder {
@Autowired
HttpServletRequest httpServletRequest;
/**
* 日志
*/
private static final Logger logger = LoggerFactory.getLogger(MyControllerAdviceHanlder.class);
private void logErrorPrint(Exception e){
// 组装日志内容
String logInfo = String.format("报错API URL: %S, error = ", httpServletRequest.getRequestURI(), e.getMessage());
// 打印日志
// System.out.println(logInfo);
logger.info(logInfo);
}
/**
* {@code @RequestBody} 参数校验不通过时抛出的异常处理
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
// 打印日志
logErrorPrint(exception);
// 组织异常信息,可能存在多个参数校验失败
BindingResult bindingResult = exception.getBindingResult();
StringBuilder sb = new StringBuilder("校验参数失败:");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
}
return Result.failed(ResultEnum.FAILED.getCode(), sb.toString());
}
/**
* Unchecked类型异常
* 包括:ArithmeticException,NullPointerException,ClassCastException,IllegalArgumentException,IllegalStateException,ArrayIndexOutOfBoundsException异常
*
* @param exception
* @return
*/
@ExceptionHandler(RuntimeException.class)
protected Result serviceException(RuntimeException exception) {
logErrorPrint(exception);
return Result.failed(exception.getMessage());
}
/**
* 其他异常(checked类型异常)
*
* @param exception
* @return
*/
@ExceptionHandler({HttpClientErrorException.class, IOException.class, Exception.class})
protected Result serviceException(Exception exception) {
logErrorPrint(exception);
return Result.failed(exception.getMessage());
}
}