Spring Boot 统一处理全局异常

网友投稿 1036 2022-05-30

目录

注解的介绍

@ControllerAdvice

@ExceptionHandler拦截异常并统一处理

代码实现

自定义异常

统一异常处理

前端返回值类

测试用例

如果本篇博客对您有一定的帮助,大家记得留言++哦。

注解的介绍

@ControllerAdvice

@ControllerAdvice注解是spring3.2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。

这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。@ControllerAdvice是在类上声明的注解,其用法主要有三点:

1.结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。

2.结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。

3.结合方法型注解@ModelAttribute,表示其注解的方法将会在目标Controller方法执行之前执行。

从上面的讲解可以看出,@ControllerAdvice的用法基本是将其声明在某个bean上,然后在该bean的方法上使用其他的注解来指定不同的织入逻辑。不过这里@ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持。

针对声明@ExceptionHandler 、 @InitBinder或@ModelAttribute方法的类的@Component @ExceptionHandler , @InitBinder在多个@Controller类之间共享。

使用@ControllerAdvice注解的类可以明确声明为 Spring bean 或通过类路径扫描自动检测。 所有此类 bean 都根据Ordered语义或@Order / @Priority声明进行Ordered , Ordered语义优先于@Order / @Priority声明。 然后在运行时按该顺序应用@ControllerAdvice bean。 但是请注意,实现PriorityOrdered @ControllerAdvice bean 的PriorityOrdered不高于实现Ordered @ControllerAdvice bean。 此外, Ordered不适用于范围内的@ControllerAdvice例如,如果这样的 bean 已被配置为请求范围或会话范围的 bean。 对于处理异常, @ExceptionHandler将在第一个具有匹配异常处理程序方法的通知中被选择。 对于模型的属性和数据绑定初始化, @ModelAttribute和@InitBinder方法将遵循@ControllerAdvice秩序。

注意:对于@ExceptionHandler方法,在特定建议 bean 的处理程序方法中,根异常匹配将优先于仅匹配当前异常的原因。 但是,与较低优先级建议 bean 上的任何匹配(无论是根还是原因级别)相比,更高优先级建议上的原因匹配仍然是首选。 因此,请在具有相应顺序的优先建议 bean 上声明您的主要根异常映射。

默认情况下, @ControllerAdvice ControllerAdvice 中的方法全局应用于所有控制器。 使用诸如annotations 、 basePackageClasses和basePackages (或其别名value )之类的选择器来定义目标控制器的更窄子集。 如果声明了多个选择器,则应用布尔OR逻辑,这意味着所选控制器应至少匹配一个选择器。 请注意,选择器检查是在运行时执行的,因此添加许多选择器可能会对性能产生负面影响并增加复杂性。

@ExceptionHandler拦截异常并统一处理

配合 @ExceptionHandler注解结合使用,当异常抛到controller层时,可以对异常进行统一的处理,规定返回的json格式或者跳转到指定的错误页面等.

@ExceptionHandler的作用主要在于声明一个或多个类型的异常,当符合条件的Controller抛出这些异常之后将会对这些异常进行捕获,然后按照其标注的方法的逻辑进行处理,从而改变返回的视图信息。

用于处理特定处理程序类和/或处理程序方法中的异常的注解。

使用此注解注释的处理程序方法允许具有非常灵活的签名。 它们可能具有以下类型的参数,按任意顺序排列:

异常参数:声明为一般异常或更具体的异常。 如果注解本身没有通过其value()缩小异常类型,这也可用作映射提示

代码实现

自定义异常

/**

* 自定义一个异常类,用于处理我们发生的业务异常

*

* @author Promsing(张有博)

* @version 1.0.0

* @since 2021/11/27 - 20:14

*/

public class BizException extends RuntimeException {

private static final long serialVersionUID = 1L;

/**

* 错误码

*/

protected String errorCode;

/**

* 错误信息

*/

protected String errorMsg;

public BizException() {

super();

}

public BizException(FrontResult errorInfoInterface) {

super(errorInfoInterface.getCode());

this.errorCode = errorInfoInterface.getMessage();

this.errorMsg = errorInfoInterface.getMessage();

}

public BizException(FrontResult errorInfoInterface, Throwable cause) {

super(errorInfoInterface.getCode(), cause);

this.errorCode = errorInfoInterface.getCode();

this.errorMsg = errorInfoInterface.getMessage();

}

public BizException(String errorMsg) {

super(errorMsg);

this.errorMsg = errorMsg;

}

public BizException(String errorCode, String errorMsg) {

super(errorCode);

this.errorCode = errorCode;

this.errorMsg = errorMsg;

}

public BizException(String errorCode, String errorMsg, Throwable cause) {

super(errorCode, cause);

this.errorCode = errorCode;

this.errorMsg = errorMsg;

}

public String getErrorCode() {

return errorCode;

}

public void setErrorCode(String errorCode) {

this.errorCode = errorCode;

}

public String getErrorMsg() {

return errorMsg;

}

public void setErrorMsg(String errorMsg) {

this.errorMsg = errorMsg;

}

public String getMessage() {

return errorMsg;

}

@Override

public Throwable fillInStackTrace() {

return this;

}

}

统一异常处理

import com.tfjy.arbackend.enumtool.ResultCodeEnum;

import com.tfjy.arbackend.enumtool.ResutlMsgEnum;

import com.tfjy.arbackend.util.FrontResult;

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 javax.servlet.http.HttpServletRequest;

import java.io.IOException;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.sql.SQLException;

/**

* 统一异常处理

*

* @author Promsing(张有博)

* @version 1.0.0

* @since 2021/11/27 - 20:14

*/

@ControllerAdvice//使用该注解表示开启了全局异常的捕获

public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

/**

* 处理自定义的业务异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value = BizException.class)

@ResponseBody

public FrontResult bizExceptionHandler(HttpServletRequest req, BizException e){

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("发生业务异常!原因是:{}",e.getErrorMsg());

return FrontResult.getExceptionResult(e.getErrorCode(),e.getErrorMsg());

}

/**

* 处理空指针的异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value =NullPointerException.class)

@ResponseBody

public FrontResult exceptionHandler(HttpServletRequest req, NullPointerException e) {

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("发生空指针异常!原因是:",e);

return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

}

/**

* 处理索引越界异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value =IndexOutOfBoundsException.class)

@ResponseBody

public FrontResult exceptionHandler(HttpServletRequest req, IndexOutOfBoundsException e){

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("索引越界异常!原因是:",e);

return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

}

/**

* 处理类未找到异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value =ClassNotFoundException.class)

@ResponseBody

public FrontResult exceptionHandler(HttpServletRequest req, ClassNotFoundException e) {

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("发生类未找到异常!原因是:",e);

return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

}

/**

* 处理SQL异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value = SQLException.class)

@ResponseBody

public FrontResult exceptionHandler(HttpServletRequest req, SQLException e) {

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("发生SQL异常!原因是:",e);

return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

}

/**

* 处理IO异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value = IOException.class)

@ResponseBody

public FrontResult exceptionHandler(HttpServletRequest req, IOException e) {

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("发生IO异常!原因是:",e);

return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

}

/**

* 处理其他异常

* @param req

* @param e

* @return

*/

@ExceptionHandler(value =Exception.class)

@ResponseBody

public FrontResult exceptionHandler(HttpServletRequest req, Exception e){

logger.error("URL : " + req.getRequestURL().toString());

logger.error("HTTP_METHOD : " + req.getMethod());

logger.error("未知异常!原因是:",e);

return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

}

}

前端返回值类

import com.tfjy.arbackend.enumtool.ResultCodeEnum;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

@Data

@AllArgsConstructor

@NoArgsConstructor

public class FrontResult {

/**

* 结果状态码

*/

private String code;

/**

* 响应结果描述

*/

private String message;

/**

* 返回数据

*/

private Object data;

/**

* 静态方法,返回前端实体结果

*

* @param code 状态码

* @param message 消息

* @param data 数据

* @return 前端实体结果

*/

public static FrontResult build(String code, String message, Object data) {

return new FrontResult(code, message, data);

}

/**

* 返回成功的结果实体

*

* @param message 消息

* @param data 数据

* @return 实体

*/

public static FrontResult getSuccessResult(String message, Object data) {

FrontResult result = new FrontResult();

result.code = ResultCodeEnum.SUCCESS.getCode();

result.message = message;

result.data = data;

return result;

}

/**

* 返回无需data的成功结果实体

*

* @param message 消息内容

* @return 返回结果

*/

public static FrontResult getSuccessResultOnlyMessage(String message) {

FrontResult result = new FrontResult();

result.code = ResultCodeEnum.SUCCESS.getCode();

result.message = message;

result.data = null;

return result;

}

/**

* 获取一个异常结果

*

* @param code 错误码

* @param message 自定义异常信息

* @return FrontResult

*/

public static FrontResult getExceptionResult(String code, String message) {

FrontResult result = new FrontResult();

result.code = code.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getCode() : code;

result.message = message.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getMsg() : message;

return result;

}

}

import lombok.AllArgsConstructor;

@AllArgsConstructor

public enum ResultCodeEnum {

// 请求成功

SUCCESS("0000"),

// 请求失败

FAIL("1111"),

// EXCEL 导入失败

EXCEL_FAIL("1000"),

// userID 为空

ID_NULL("1001"),

// 前端传的实体为空

MODEL_NULL("1002"),

// 更新失败

UPDATE_FAIL("1011"),

// 参数为空

PARAM_ERROR("400"),

// 代码内部异常

CODE_EXCEPTION("500", "代码内部异常");

/**

* 状态码

*/

private String code;

public String getCode() {

Spring Boot 统一处理全局异常

return code;

}

ResultCodeEnum(String code) {

this.code = code;

}

private String msg;

public String getMsg() {

return msg;

}

}

public enum ResutlMsgEnum {

//查询成功

FIND_SUCCESS("查询成功!"),

//查询失败

FIND_FAIL("查询失败!"),

//更新成功

UPDATE_SUCCESS("更新成功"),

//更新失败

UPDATE_FAIL("更新成功"),

SEND_SUCCESS("发送成功"),

SEND_FAIL("发送失败");

private String msg;

ResutlMsgEnum(String msg) {

this.msg = msg;

}

public String getMsg() {

return msg;

}

}

测试用例

/**

* 测试用例

*

* @author Promsing(张有博)

* @version 1.0.0

* @since 2021/11/29 - 9:05

*/

@Api(tags = {"测试controller"})

@RequestMapping(value = "/testController")

@RestController

public class TestController {

@ApiOperation(value = "测试null")

@GetMapping(value = "getNull")

public FrontResult getNull() {

int length = 0;

String name=null;

length = name.length();

return FrontResult.build(ResultCodeEnum.SUCCESS.getCode(),

ResutlMsgEnum.EXECUTE_SUCCESS.getMsg(), length);

}

}

其他异常同理,也可以捕获。完美,没问题。全局统一异常处理设置成功。

如果本篇博客对您有一定的帮助,大家记得留言++哦。

Spring Spring boot

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【高并发】优化加锁方式时竟然死锁了!!
下一篇:Excel表格中如何制作平面直角坐标系
相关文章