全局异常处理器(结束后仍然要经过全局返回处理)
可能刚刚开始接触项目构造的时候会对着一部分有疑惑,比如说我,其实是这样的
重写ErrorController,不在跳转原生错误页面,而是抛出我们的自定义异常
全局异常处理就是指把整个系统的异常统一自动处理,程序员可以做到不用些try/catch就能进行处理项目中出现的异常。
为什么需要全局异常处理呢?
-
第一个原因:不用强制写try/catch,异常交由统一异常的处理机制进行捕获。
-
第二个原因:自定义异常:只能用全局异常来捕获。
-
第三个原因:JSR303的参数验证器,参数校验不通过会抛出异常,也是无法通过try/catch进行直接捕获处理的。
编码实现springboot的全局异常配置
步骤1:统一封装异常处理枚举类
package com.kuangstudy.exception;
import lombok.Getter;
/**
* @Author xuke
* @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:封装异常的处理器
package com.kuangstudy.exception;
import com.kuangstudy.common.R;
import lombok.*;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class ErrorHandler {
// ErrorHandler === R 答案:不想破坏R类。
// 异常的状态码,从枚举中获得
private Integer status;
// 异常的消息,写用户看得懂的异常,从枚举中得到
private String message;
// 异常的名字
private String exception;
/**
* 对异常处理进行统一封装
*
* @param resultCodeEnum 异常枚举
* @param throwable 出现异常
* @param message 异常的消息 null /by zero
* @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;
}
public static ErrorHandler fail(String errorName) {
ErrorHandler errorHandler = new ErrorHandler();
errorHandler.setMessage("操作失败");
errorHandler.setStatus(500);
errorHandler.setException(errorName);
return errorHandler;
}
}
步骤3:定义一个全局异常处理器
是否开启全局返回处理(默认开启,不用设置)
https://blog.csdn.net/LC_Liangchao/article/details/122466572
package com.zykj.newsell.common.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.UndeclaredThrowableException;
/**
* @author lc
* @version 1.0
* @date 2022/4/12 14:46
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 对服务器端出现500异常进行统一处理
*/
@ExceptionHandler(value = ServiceException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorHandler makeExcepton(Throwable e, HttpServletRequest request) {
String message = e.getMessage();
if (e instanceof UndeclaredThrowableException){
Throwable undeclaredThrowable = ((UndeclaredThrowableException) e).getUndeclaredThrowable();
message = undeclaredThrowable.getMessage();
}
ErrorHandler errorHandler = ErrorHandler.fail(e.getClass().getName()+ ": " +message);
log.error("请求的地址:{},出现的异常:{}", request.getRequestURL(), e);
System.out.println("ServiceException");
return errorHandler;
}
/**
* 空指针异常 统一处理
*/
@ExceptionHandler(value =NullPointerException.class)
@ResponseBody
public ErrorHandler exceptionHandler500(NullPointerException e, HttpServletRequest request){
String message = e.getMessage();
ErrorHandler errorHandler = ErrorHandler.fail(e.getClass().getName()+ ": " +message);
log.error("请求的地址:{},出现的空指针异常:{}", request.getRequestURL(), e);
return errorHandler;
}
/**
* 未知异常 统一处理
*/
@ExceptionHandler(value =Exception.class)
@ResponseBody
public ErrorHandler exceptionHandler(Exception e, HttpServletRequest request){
String message = e.getMessage();
if (e instanceof UndeclaredThrowableException){
Throwable undeclaredThrowable = ((UndeclaredThrowableException) e).getUndeclaredThrowable();
message = undeclaredThrowable.getMessage();
}
ErrorHandler errorHandler = ErrorHandler.fail(e.getClass().getName()+ ": " +message);
log.error("请求的地址:{},出现的异常:{}", request.getRequestURL(), e);
System.out.println("Exception");
return errorHandler;
}
}
- makeExcepton方法的作用是:把运行时异常封装为ErrorHandler对象进行统一捕获处理。
- @RestControllerAdvice和@ControllerAdvice它是对controller的增强扩展处理,而全局异常就是一种扩展能力之一。
- @ExceptionHandler(Throwable.class) :统一处理某一类型异常,从而减少代码的出现异常的复杂度和重复率,
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR):指定客户端收到的http状态码,这里配置的是500,就显示成500错误。不指定也是没问题的。因为返回是根据自己的枚举进行处理了。
步骤4:定义测试类
package com.kuangstudy.controller;
import com.kuangstudy.entity.User;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(description = "用户中心")
public class UserController {
@GetMapping("/error1")
public User error1(Integer id) {
if (id.equals(1)) {
throw new RuntimeException("用户名和密码有误!!!");
}
User user = new User();
user.setId(1);
user.setNickname("yykk");
user.setPassword("451212");
user.setAddress("梅州");
return user;
}
@GetMapping("/error2")
public User error2(Integer id) {
int i = 1 / 0;
User user = new User();
user.setId(1);
user.setNickname("yykk");
user.setPassword("451212");
user.setAddress("梅州");
return user;
}
@GetMapping("/getuser")
public User getuser(Integer id) {
User user = new User();
user.setId(1);
user.setNickname("yykk");
user.setPassword("451212");
user.setAddress("梅州");
return user;
}
@ResponseBody //---标记--jackson A 有 B没有
@GetMapping("/getname")
public String getusername() {
return "yykk";
}
}
自定义异常,并集成自定义异常处理器
自定义异常的好处是:可以根据自定异常的信息快速的定位错误出现的模块以及方便记录日志文件,快速进行错误的分析和判定。