全局异常处理
- 这种方式可以更方便的对一个类的所有方法都进行异常处理,写好异常类后我们只需使用注解添加到类和方法上即可
异常处理一般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;}}
@Getterpublic 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返回信息封装类```javapackage 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*/@Datapublic 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; } }
