上篇提到通过
@ControllerAdvice
和ResponseBodyAdvice
接口实现对请求接口的拦截封装处理,进行统一格式返回,问题来了:
程序在执行过程中难免会出现异常,怎样处理,是否也可以统一处理?
实现全局异常处理
1 创建返回异常信息枚举类
ResultCodeEnum:
用于封装错误信息,方便异常抛出时调用。
package com.liyi.common.exception;
import lombok.Getter;
/**
* @Author
* @Description 专门处理异常
* @Date 21:14 2021/6/25
* @Param
* @return
**/
@Getter
public enum ResultCodeEnum {
UNKNOWN_REASON(false, 20001, "未知错误"),
SERVER_ERROR(false, 500, "服务器忙,请稍后在试"),
ORDER_CREATE_FAIL(false, 601, "订单下单失败");
private Boolean success;
private Integer code;
private String message;
private ResultCodeEnum(Boolean success, Integer code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
}
2 创建返回的异常对象
ErrorHandler:
异常统一返回的对象
package com.liyi.common.exception;
import lombok.*;
import lombok.experimental.Accessors;
@Builder
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ErrorHandler {
// 异常的状态码,从枚举中获得
private Integer status;
// 异常的消息,写用户看得懂的异常,从枚举中得到
private String message;
// 异常的名字
private String exception;
/**
* 对异常处理进行统一封装
*
* @param resultCodeEnum 异常枚举
* @param throwable 异常对象
* @param message 异常信息
* @return
*/
public static ErrorHandler fail(ResultCodeEnum resultCodeEnum, Throwable throwable, String message) {
ErrorHandler errorHandler = ErrorHandler.fail(resultCodeEnum, throwable);
errorHandler.setMessage(message);
return errorHandler;
}
/**
* 对异常枚举进行封装
*
* @param resultCodeEnum
* @param throwable
* @return
*/
public static ErrorHandler fail(ResultCodeEnum resultCodeEnum, Throwable throwable) {
ErrorHandler errorHandler = new ErrorHandler();
errorHandler.setMessage(resultCodeEnum.getMessage());
errorHandler.setStatus(resultCodeEnum.getCode());
errorHandler.setException(throwable.getClass().getName());
return errorHandler;
}
}
3 对异常进行全局拦截
GlobalExceptionHandler:
package com.liyi.configuration;
import com.liyi.common.exception.ErrorHandler;
import com.liyi.common.exception.OrderException;
import com.liyi.common.exception.ResultCodeEnum;
import com.liyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 对服务器端出现500异常进行统一处理
*/
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorHandler makeExcepton(Throwable e, HttpServletRequest request) {
ErrorHandler errorHandler = ErrorHandler.fail(ResultCodeEnum.SERVER_ERROR, e);
log.error("请求的地址是:{},出现的异常是:{}", request.getRequestURL(), e.getMessage());
return errorHandler;
}
}
- makeExcepton方法的作用是:把运行时异常封装为ErrorHandler对象进行统一捕获处理。
- @RestControllerAdvice和@ControllerAdvice它是对controller的增强扩展处理,而全局异常就是一种扩展能力之一。
- @ExceptionHandler(Throwable.class) :统一处理某一类型异常,从而减少代码的出现异常的复杂度和重复率,
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR):指定客户端收到的http状态码,这里配置的是500,就显示成500错误。不指定也是没问题的。因为返回是根据自己的枚举进行处理了。
4.测试
package com.liyi.controller;
import com.liyi.common.exception.OrderException;
import com.liyi.common.exception.ResultCodeEnum;
import com.liyi.common.exception.ServiceException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(description = "订单管理")
@RequestMapping("/order/")
public class OrderController {
@GetMapping("createOrder")
@ApiOperation(value = "创建订单")
public void createOrder(Integer id){
if(id==1){
throw new OrderException(ResultCodeEnum.ORDER_CREATE_FAIL);
}
if(id ==2){
throw new ServiceException(ResultCodeEnum.UNKNOWN_REASON);
}
}
}
5 创建具体要抛出的异常类
ServiceException:
自定义的异常类
package com.liyi.common.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
public class ServiceException extends RuntimeException{
private Integer code;
private String message;
public ServiceException(ResultCodeEnum resultCodeEnum){
this.code = resultCodeEnum.getCode();
this.message = resultCodeEnum.getMessage();
}
public ServiceException(Integer code ,String message){
this.code = code;
this.message = message;
}
}
6.添加自定义异常处理方法
package com.liyi.configuration;
import com.liyi.common.exception.ErrorHandler;
import com.liyi.common.exception.OrderException;
import com.liyi.common.exception.ResultCodeEnum;
import com.liyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 对服务器端出现500异常进行统一处理
*/
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorHandler makeExcepton(Throwable e, HttpServletRequest request) {
ErrorHandler errorHandler = ErrorHandler.fail(ResultCodeEnum.SERVER_ERROR, e);
log.error("请求的地址是:{},出现的异常是:{}", request.getRequestURL(), e.getMessage());
return errorHandler;
}
@ExceptionHandler(ServiceException.class)
public ErrorHandler makeServiceException(ServiceException serviceException,HttpServletRequest request){
ErrorHandler errorHandler = ErrorHandler.builder().
message(serviceException.getMessage()).
status(serviceException.getCode()).build();
log.error("请求路径为:{},出现的异常是:{}",request.getRequestURL(),serviceException.getMessage());
return errorHandler;
}
}
该文章仅学习记录使用