文章目录
1.Spring MVC异常统一处理的三种方式
- 使用 @ ExceptionHandler 注解:对当前所在Controller的异常进行处理
- 实现 HandlerExceptionResolver 接口
- 使用
@controlleradvice+@ ExceptionHandler
注解:对全局异常进行处理(推荐)
@Controller + @ExceptionHandler
缺点:进行异常处理的方法必须与出错的方法在同一个Controller里面,不能全局控制异常。每个类都要写一遍:
@Controller
public class GlobalController {
/**
* 用于处理异常的
* @return
*/
@ExceptionHandler({
MyException.class})
public String exception(MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
return "exception";
}
@RequestMapping("test")
public void test() {
throw new MyException("出错了!");
}
}
实现 HandlerExceptionResolver 接口
可以进行全局的异常控制
@Component
@Slf4j
public class GlobalDefaultExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
log.info("==============Exception Start 000000=============");
if (ex instanceof BaseException) {
log.debug(ex, ex);
}
else {
log.error(ex, ex);
}
log.info("==============Exception End 000000=============");
//AJAX请求
if (NetworkUtil.isAjax(request)) {
String msg = null;
String code = null;
String detail = null;
if (ex instanceof BaseException) {
msg = ((BaseException) ex).getErrorMsg();
code = ((BaseException) ex).getErrorCode();
detail = ((BaseException) ex).getMsgDetail();
}
else {
FSTErrorCode fc = FSTErrorCode.SYS_ERROR_000000;
msg = fc.getErrorMsg();
code = fc.getErrorCode();
detail = fc.getMsgDetail();
}
try {
JSONObject result = new JSONObject();
result.put("msg", msg);
result.put("code", code);
result.put("detail", detail);
response.setContentType("text/html;charset=utf-8");
response.getWriter().print(result.toString());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//非Ajax请求
else {
ModelAndView mv = new ModelAndView();
mv.setViewName("error/error");//跳转到resources/template/error/error.html
mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));
return mv;
}
}
}
@ControllerAdvice+@ExceptionHandler
- 可以实现全局的异常捕获
@ControllerAdvice
@ResponseBody
@Slf4j
public class WebExceptionHandle {
private static Logger logger = LoggerFactory.getLogger(WebExceptionHandle.class);
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public ServiceResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
log.error("参数解析失败", e);
return ServiceResponseHandle.failed("could_not_read_json");
}
/**
* 405 - Method Not Allowed
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ServiceResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.error("不支持当前请求方法", e);
return ServiceResponseHandle.failed("request_method_not_supported");
}
/**
* 415 - Unsupported Media Type
*/
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ServiceResponse handleHttpMediaTypeNotSupportedException(Exception e) {
log.error("不支持当前媒体类型", e);
return ServiceResponseHandle.failed("content_type_not_supported");
}
/**
* 500 - Internal Server Error
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ServiceResponse handleException(Exception e) {
if (e instanceof BusinessException){
return ServiceResponseHandle.failed("BUSINESS_ERROR", e.getMessage());
}
log.error("服务运行异常", e);
e.printStackTrace();
return ServiceResponseHandle.failed("server_error");
}
}
2.统一响应返回
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiResult<T> implements Serializable {
private static final long serialVersionUID = 411731814484355577L;
private int code;
private String msg;
private boolean isSuccess;
private T data;
public static ApiResult<String> success() {
return success("success");
}
public static <T> ApiResult<T> success(T data) {
return (ApiResult<T>) ApiResult.builder().code(0).msg("操作成功").isSuccess(true).data(data).build();
}
public static ApiResult<String> fail() {
return fail(-1);
}
public static ApiResult<String> fail(int code) {
return fail(code, "fail");
}
public static ApiResult<String> fail(int code,String message) {
return fail(code, message);
}
public static <T> ApiResult<T> fail(T data) {
return fail(-1, data);
}
public static <T> ApiResult<T> fail(int code, T data) {
return (ApiResult<T>) ApiResult.builder().code(code).msg("操作失败").isSuccess(false).data(data).build();
}
public static <T> ApiResult<T> success(int code, String message, T data) {
return (ApiResult<T>) ApiResult.builder().code(code).msg(message).isSuccess(true).data(data).build();
}
public static <T> ApiResult<T> fail(int code, String message, T data) {
return (ApiResult<T>) ApiResult.builder().code(code).msg(message).isSuccess(false).data(data).build();
}
@Override
public String toString() {
return "ApiResult(responseCode=" + this.getCode() + ", responseMsg=" + this.getMsg() + ", isSuccess=" + this.isSuccess() + ", data=" + this.getData() + ")";
}
}
3.统一异常处理
- 使用@ControllerAdvice+ @ExceptionHandler注解进行异常全局捕获;
- 定义一个通用的异常捕获方法,便于捕获未定义的异常信息;
- 自定一个异常类,捕获针对项目或业务的异常;
自定义异常
@Data
public class BusinessException extends RuntimeException {
private Integer code;
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public BusinessException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getMessage());
this.code = resultCodeEnum.getCode();
}
@Override
public String toString() {
return "BusinessException{" + "code=" + code + ", message=" + this.getMessage() + '}';
}
}
异常类型统一使用枚举类管理
@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;
}
}
定义全局异常捕获器
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**-------- 通用异常处理方法 --------**/
@ExceptionHandler(Exception.class)
@ResponseBody
public ApiResult error(Exception e) {
e.printStackTrace();
return ApiResult.fail(-1,"通用异常");
}
/**-------- 指定异常处理方法 --------**/
@ExceptionHandler(NullPointerException.class)
@ResponseBody
public ApiResult error(NullPointerException e) {
e.printStackTrace();
log.error(ExceptionUtil.getMessage(e));
return ApiResult.fail(-1,"空指针异常");
}
@ExceptionHandler(HttpClientErrorException.class)
@ResponseBody
public ApiResult error(IndexOutOfBoundsException e) {
e.printStackTrace();
log.error(ExceptionUtil.getMessage(e));
return ApiResult.fail(-1,"下标越界异常");
}
/**-------- 自定义定异常处理方法 --------**/
@ExceptionHandler(BusinessException.class)
@ResponseBody
public ApiResult error(BusinessException e) {
e.printStackTrace();
log.error(ExceptionUtil.getMessage(e));
return ApiResult.fail(-1,"业务异常");
}
}
【转载】Java统一异常处理及架构实战
https://juejin.cn/post/6844904033488994317