作者:残城碎梦 围观群众:588 更新于 标签:spring boot异常处理全局异常处理
相信大家在编写代码的时候都很烦恼一件事。那就是频繁的异常处理。大量的try catch在逻辑层中使用不仅非常麻烦。也让我们的代码可读性较差。所以在spring boot 项目中使用全局异常处理是非常有必要的。
@ControllerAdvice注解
在spring中可以使用@ControllerAdvice 声明一些全局的东西。例如全局异常处理,数据绑定,数据异常处理等。在这里我们需要与@ExceptionHandler来结合使用做全局异常处理。
@ExceptionHandler注解
使用@ExceptionHandler注解可以统一的对某类异常进行处理。
在对@ExceptionHandler和@ControllerAdvice注解有了一定的了解以后。我们开始我们的代码实现。
package top.demo.common.exception;
/** * * @author zzy * @date 2021/3/15 15:42 */
public interface BaseExceptionInfo {
/** * 获取错误码 * @return */
String getErrCode();
/** * 获取错误描述 * @return */
String getErrMsg();
}
2.定义常见的异常枚举类
package top.demo.common.exception;
/** * 异常枚举类 * * @author zzy * @date 2021/3/15 15:49 */
public enum ErrCommonEnum implements BaseExceptionInfo {
SUCCESS("200", "成功!"),
BODY_NOT_MATCH("400", "请求的数据格式不符!"),
NOT_LOGIN("401", "请登录后重新访问!"),
NO_PERMISSION("402", "您没有权限访问!"),
NOT_FOUND("404", "未找到该资源!"),
INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
SERVER_BUSY("503", "服务器正忙,请稍后再试!"),
;
private String errCode; //错误码
private String errMsg; //错误描述
ErrCommonEnum(String errCode, String errMsg) {
this.errCode = errCode;
this.errMsg = errMsg;
}
@Override
public String getErrCode() {
return errCode;
}
@Override
public String getErrMsg() {
return errMsg;
}
}
3.自定义异常
package top.demo.common.exception;
/** * 自定义异常,处理业务异常 * @author zzy * @date 2021/3/15 15:58 */
public class CustomException extends RuntimeException {
protected String errCode; //错误码
protected String errMsg; //错误描述
public CustomException(){
super();
}
public CustomException(BaseExceptionInfo baseExceptionInfo){
super(baseExceptionInfo.getErrCode());
this.errCode = baseExceptionInfo.getErrCode();
this.errMsg = baseExceptionInfo.getErrMsg();
}
public CustomException(BaseExceptionInfo baseExceptionInfo, Throwable cause){
super(baseExceptionInfo.getErrCode(), cause);
this.errCode = baseExceptionInfo.getErrCode();
this.errMsg = baseExceptionInfo.getErrMsg();
}
public CustomException(String errMsg){
super(errMsg);
this.errMsg = errMsg;
}
public CustomException(String errCode, String errMsg){
super(errCode);
this.errCode = errCode;
this.errMsg = errMsg;
}
public CustomException(String errCode, String errMsg, Throwable cause){
super(errCode, cause);
this.errCode = errCode;
this.errMsg = errMsg;
}
public String getErrCode() {
return errCode;
}
public void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
4.编写公共的api相应类。
package top.demo.common;
import top.demo.common.exception.ErrCommonEnum;
/** * api接口响应类 * @author zzy * @date 2021/3/15 16:14 */
public class ApiResponse {
private boolean success; //是否成功
private String code; //状态码
private String msg; //提示信息
private Object data; //绑定的数据
private Integer count; //如果是分页的话。返回数据总条数
ApiResponse(boolean success, String code, String msg){
this.success = success;
this.code = code;
this.msg = msg;
this.data = null;
this.count = 0;
}
ApiResponse(boolean success, String code, String msg, Object data){
this.success = success;
this.code = code;
this.msg = msg;
this.data = data;
this.count = 0;
}
ApiResponse(boolean success, String code, String msg, Object data, Integer count){
this.success = success;
this.code = code;
this.msg = msg;
this.data = data;
this.count = count;
}
public static ApiResponse ok(){
return new ApiResponse(true,ErrCommonEnum.SUCCESS.getErrCode(),ErrCommonEnum.SUCCESS.getErrMsg());
}
public static ApiResponse ok(String msg){
return ok(msg,null);
}
public static ApiResponse ok(String msg, Object data){
return new ApiResponse(true, ErrCommonEnum.SUCCESS.getErrCode(),msg,data);
}
public static ApiResponse err(ErrCommonEnum errCommonEnum){
return new ApiResponse(false,errCommonEnum.getErrCode(),errCommonEnum.getErrMsg());
}
public static ApiResponse err(String msg){
return err("-1",msg);
}
public static ApiResponse err(String code ,String msg){
return new ApiResponse(false,code,msg);
}
public static ApiResponse tableData(Object data,Integer count){
return new ApiResponse(true,"200","获取成功", data, count);
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public void demo(){
System.out.println();
}
}
5.使用上面两个注解完成全局的异常处理
package top.demo.common.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import top.demo.common.ApiResponse;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/** * 全局的异常处理类 * @author zzy * @date 2021/3/15 18:50 */
@ControllerAdvice
public class GlobalExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/** * 处理业务逻辑异常 * @param req * @param e * @return */
@ExceptionHandler(value = CustomException.class)
@ResponseBody
public ApiResponse customExceptionHandler(HttpServletRequest req,CustomException e){
logger.error("发生业务逻辑异常! 原因是:{}",e.getErrMsg());
return ApiResponse.err(e.getErrCode(),e.getErrCode());
}
/** * 捕获空指针异常 * @param req * @param e * @return */
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ApiResponse nullPointerExceptionHandler(HttpServletRequest req,NullPointerException e){
e.printStackTrace();
logger.error("发生了空指针异常! 原因是:{}",e.getMessage());
return ApiResponse.err(ErrCommonEnum.INTERNAL_SERVER_ERROR);
}
/** * 捕获其他异常 * @param req * @param e * @return */
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ApiResponse exceptionHandler(HttpServletRequest req,Exception e){
e.printStackTrace();
logger.error("未知异常! 原因是:{}",e.getMessage());
return ApiResponse.err(ErrCommonEnum.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(value = Throwable.class)
@ResponseBody
public ApiResponse throwableHandler(HttpServletRequest req,Throwable e){
logger.error("未知异常! 原因是:{}",e.getMessage());
return ApiResponse.err(ErrCommonEnum.INTERNAL_SERVER_ERROR);
}
}
package top.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import top.demo.common.ApiResponse;
import java.util.List;
/** * @author zzy * @date 2021/5/6 9:01 */
@Controller
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/null")
@ResponseBody
public ApiResponse nullDemo() {
List list = null;
System.out.println(list.size());
return ApiResponse.ok("空指针异常没有被捕获");
}
@GetMapping("/zero")
@ResponseBody
public ApiResponse zero(){
int a = 1 / 0;
System.out.println(a);
return ApiResponse.ok("异常没有被捕获");
}
@GetMapping("/demo")
@ResponseBody
public ApiResponse demo(){
return ApiResponse.ok("正常情况没有问题");
}
}
在项目中使用一开始是没有任何问题的。但是给代码添加了切面日志处理之后发现全局的异常处理失效了。在检查代码发现。切面日志处理中含有try catch 。影响了全局异常处理。需要注意的地方是在逻辑代码中如果含有 try catch 会优先被try catch捕获。不会被全局异常处理捕获,其中包含切面中的try catch。
最后欢迎大家访问我的个人博客网站:zShare个人博客