全局异常处理
- 这种方式可以更方便的对一个类的所有方法都进行异常处理,写好异常类后我们只需使用注解添加到类和方法上即可
异常处理一般2种
实现一个
BaseException
,其他业务异常继承该基类@Data
@EqualsAndHashCode(callSuper = true)
public class BaseException extends RuntimeException {
private Integer code;
private String message;
//默认使用系统抛出的异常消息,也可以自定义消息
public BaseException(Status status) {
super(status.getMessage());
this.code = status.getCode();
this.message = status.getMessage();
}
public BaseException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
}
@Getter
public class JsonException extends BaseException {
public JsonException(Status status) {
super(status);
}
public JsonException(Integer code, String message) {
super(code, message);
}
}
信息类 ```java @Getter public enum Status { /**
操作成功 */ OK(200, “操作成功”),
/**
- 未知异常 / UNKNOWN_ERROR(500, “服务器出错啦”); /*
- 状态码 / private Integer code; /*
内容 */ private String message;
Status(Integer code, String message) { this.code = code; this.message = message; } }
- result返回信息封装类
```java
package com.xkcoding.exception.handler.model;
import com.xkcoding.exception.handler.constant.Status;
import com.xkcoding.exception.handler.exception.BaseException;
import lombok.Data;
/**
* <p>
* 通用的 API 接口封装
* </p>
*
* @author yangkai.shen
* @date Created in 2018-10-02 20:57
*/
@Data
public class ApiResponse {
/**
* 状态码
*/
private Integer code;
/**
* 返回内容
*/
private String message;
/**
* 返回数据
*/
private Object data;
/**
* 无参构造函数
*/
private ApiResponse() {
}
/**
* 全参构造函数
*
* @param code 状态码
* @param message 返回内容
* @param data 返回数据
*/
private ApiResponse(Integer code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* 构造一个自定义的API返回
*
* @param code 状态码
* @param message 返回内容
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse of(Integer code, String message, Object data) {
return new ApiResponse(code, message, data);
}
/**
* 构造一个成功且带数据的API返回
*
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse ofSuccess(Object data) {
return ofStatus(Status.OK, data);
}
/**
* 构造一个成功且自定义消息的API返回
*
* @param message 返回内容
* @return ApiResponse
*/
public static ApiResponse ofMessage(String message) {
return of(Status.OK.getCode(), message, null);
}
/**
* 构造一个有状态的API返回
*
* @param status 状态 {@link Status}
* @return ApiResponse
*/
public static ApiResponse ofStatus(Status status) {
return ofStatus(status, null);
}
/**
* 构造一个有状态且带数据的API返回
*
* @param status 状态 {@link Status}
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse ofStatus(Status status, Object data) {
return of(status.getCode(), status.getMessage(), data);
}
/**
* 构造一个异常且带数据的API返回
*
* @param t 异常
* @param data 返回数据
* @param <T> {@link BaseException} 的子类
* @return ApiResponse
*/
public static <T extends BaseException> ApiResponse ofException(T t, Object data) {
return of(t.getCode(), t.getMessage(), data);
}
/**
* 构造一个异常且带数据的API返回
*
* @param t 异常
* @param <T> {@link BaseException} 的子类
* @return ApiResponse
*/
public static <T extends BaseException> ApiResponse ofException(T t) {
return ofException(t, null);
}
}
定义异常转发器
- 异常转发器即对不同异常类定义不同方法,这样无需控制器或者服务层创建设置异常信息对象,直接调异常转发器即可
@ControllerAdvice
用于声明全局信息(即表示该类可以使用定义的全局规则),最常用于与@ExceptionHandler
结合来实现全局异常处理- 该注解就是在
@Controller
基础上增加了声明全局的功能,如果需要全类使用字符串交互,使用**@RestControllerAdvice**
- 该注解就是在
@ExceptionHandler
标注于方法上,表示使用一个全局异常- 如
@ExceptionHandler(value = JsonException.class)
JsonException是自定义的一个异常类 - 该方法单独使用时用于控制器类的非控制器方法上,表示控制器方法发生异常时就调用该方法
@ControllerAdvice public class UserController { @ExceptionHandler(RuntimeException.class) //如果发生运行时异常... // --------------注意可以定义request参数以获取发生异常的请求---------- //可以自由设置返回类型。如返回响应模型 public ModelAndView handleUnknowException(Exception ex,HttpServletRequest request) { return new ModelAndView("500.html", Map.of("error", ex.getClass().getSimpleName(), "message", ex.getMessage())); } ... }
- 如
@ControllerAdvice
@Slf4j
public class DemoExceptionHandler {
private static final String DEFAULT_ERROR_VIEW = "error";
/**
* 统一 json 异常处理
*
* @param exception JsonException
* @return 统一返回 json 格式
*/
@ExceptionHandler(value = JsonException.class)
@ResponseBody
public ApiResponse jsonErrorHandler(JsonException exception) {
log.error("【JsonException】:{}", exception.getMessage());
return ApiResponse.ofException(exception);
}
/**
* 统一 页面 异常处理
*
* @param exception PageException
* @return 统一跳转到异常页面
*/
@ExceptionHandler(value = PageException.class)
public ModelAndView pageErrorHandler(PageException exception) {
log.error("【DemoPageException】:{}", exception.getMessage());
ModelAndView view = new ModelAndView();
view.addObject("message", exception.getMessage());
view.setViewName(DEFAULT_ERROR_VIEW);
return view;
}
}
抛出自定义异常
需要抛出异常的地方
throw new 异常类;
@GetMapping("/page") public ModelAndView pageException() { if(用户未登录){ throw new PageException(Status.UNKNOWN_ERROR); } else { .... } }
全局响应处理
直接配置个如下的全局响应处理即可
@ControllerAdvice public class GloabController implements ResponseBodyAdvice<Object> { //该方法可以精确设置哪些类型的 @Override public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) { Class clazz=returnType.getClass(); return returnType.getGenericParameterType().equals(HttpResult.class); } @Override public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType, final Class<? extends HttpMessageConverter<?>> selectedConverterType, final ServerHttpRequest request, final ServerHttpResponse response) { //方便自定义HttpResult时 if (body == null || body instanceof HttpResult) { return body; } final HttpResult result=new HttpResult(); result.setCode(200); result.setMsg(""); result.setData(body); if (true) {// 2 ObjectMapper objectMapper = new ObjectMapper(); try { return objectMapper.writeValueAsString(result); } catch (JsonProcessingException e) { throw new RuntimeException("将 Response 对象序列化为 json 字符串时发生异常", e); } } return result; } }