异常处理的三种方式

使用 @ExceptionHandler 注解

实现 HandlerExceptionResolver 接口(SpringMVC)

使用 @RestControllerAdvice 注解(诞生于Spring3.2)

官方推荐的是使用@ExceptionHandler注解去捕获固定的异常。

使用统一异常处理,将这些重复的try-catch块抽取出来,这样使我们可以更专注于业务逻辑的处理,同时能够使得异常的处理有一个统一的控制。

使用 @ExceptionHandler 注解

对Controller局部异常处理,@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常。

@RestController
public class TestControllerException { //单个controller进行异常处理
@RequestMapping("/testError")
public String testError() {
int a = 10 / 0;
return "this is testError" + a;
}
/**
* 处理其他异常
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public String exceptionHandler(Exception e) {
System.out.println(e);
return "this is a controller exception method!";
}
/**
* 处理空指针异常
*/
@ExceptionHandler(value =NullPointerException.class)
public String exceptionHandler(NullPointerException e){
System.out.println("发生空指针异常!原因是:"+e);
return "null";
}
}

实现 HandlerExceptionResolver 接口(SpringMVC)

使用全局异常处理器只需要两步:

1.实现HandlerExceptionResolver接口。

2.将实现类作为Spring Bean,这样Spring就能扫描到它并作为全局异常处理器加载。

实例如下:

配置applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="exceptionResolver" class="com.example.ExceptionResolver"/>
</beans>

编写ExceptionResolver

package com.example;
/**
* 全局异常处理
* @Order(-1000) 为了使优先级最高
* @Component 把普通pojo实例化到spring容器中,
* 相当于配置文件中的 <bean id="" class=""/>
*/
@Order(-1000)
@Component
public class ExceptionResolver implements HandlerExceptionResolver { private static Logger logger = LoggerFactory.getLogger(ExceptionResolver.class); @Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
ResultVO result = new ResultVO();
StringBuilder sb = new StringBuilder();
System.out.println("执行全局异常处理-----------------------");
//处理异常
if(ex instanceof BussinessException) {
resolverBussinessException(ex, sb, result);
} else if (ex instanceof BindException) {
resolverBindException(ex, sb, result);
} else {
resolverOtherException(ex, sb, result);
} result.setCode(0);
result.setResult(sb);
result.setTime(new Date()); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.setHeader("Cache-Control", "no-cache, must-revalidate");
try {
response.getWriter().write(JSON.toJSONString(result));
} catch (IOException e) {
logger.error("异常:" + e.getMessage(), e);
e.printStackTrace();
} logger.debug("异常:" + ex.getMessage(), ex);
ex.printStackTrace();
return new ModelAndView();
} /*
* 处理业务层异常
*/
private void resolverBussinessException(Exception ex, StringBuilder sb, ResultVO result) {
BussinessException businessException = (BussinessException) ex;
sb.append(businessException.getMsg());
addResult(result, "业务异常");
} /*
* 处理参数绑定异常
*/
private void resolverBindException(Exception ex, StringBuilder sb, ResultVO result) {
BindException be = (BindException) ex;
List<FieldError> errorList = be.getBindingResult().getFieldErrors();
for (FieldError error : errorList) {
sb.append(error.getObjectName());
sb.append("对象的");
sb.append(error.getField());
sb.append("字段");
sb.append(error.getDefaultMessage());
}
addResult(result, "参数传递异常");
} /*
* 处理其他异常
*/
private void resolverOtherException(Exception ex, StringBuilder sb, ResultVO result) {
sb.append(ex.getMessage());
addResult(result, "其他异常");
} /*
* 封装code和msg
*/
private void addResult(ResultVO result, String msg) {
result.setMsg(msg);
}
}

使用 @RestControllerAdvice 注解

如果单使用方式1中的 @ExceptionHandler,只能在当前Controller中处理异常。

但当配合 @RestControllerAdvice 一起使用的时候,则可以全局捕获。

@RestControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中定义的接口方法加一些逻辑处理,最常用的就是异常处理。

需要配合@ExceptionHandler使用。

当将异常抛到controller时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面。

全局异常处理的原理

在独立的一个类中,定义一套对各种异常的处理机制,然后用@RestControllerAdvice注解该类,统一对不同位置的不同异常进行处理。

编写GlobalExceptionHandler全局异常处理类:

@RestControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /**
* 权限校验异常
*/
@ExceptionHandler(AccessDeniedException.class)
public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
} /**
* 请求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return AjaxResult.error(e.getMessage());
} /**
* 业务异常
*/
@ExceptionHandler(ServiceException.class)
public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
{
log.error(e.getMessage(), e);
Integer code = e.getCode();
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
} /**
* 拦截未知的运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return AjaxResult.error(e.getMessage());
} /**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生系统异常.", requestURI, e);
return AjaxResult.error(e.getMessage());
} /**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public AjaxResult handleBindException(BindException e)
{
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return AjaxResult.error(message);
} /**
* 自定义验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
{
log.error(e.getMessage(), e);
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return AjaxResult.error(message);
} /**
* 演示模式异常
*/
@ExceptionHandler(DemoModeException.class)
public AjaxResult handleDemoModeException(DemoModeException e)
{
return AjaxResult.error("演示模式,不允许操作");
}
}

编写TestAdvice

@RestController
public class TestController extends BaseController
{
@GetMapping("testException")
public AjaxResult testException() throws Exception{
throw new Exception("系统异常");
} @GetMapping("testServiceException")
public AjaxResult testMyException() throws ServiceException {
throw new ServiceException("业务异常");
}
}

Spring的全局(统一)异常处理的更多相关文章

  1. spring 或 springboot统一异常处理

    spring 或 springboot统一异常处理https://blog.csdn.net/xzmeasy/article/details/76150370 一,本文介绍spring MVC的自定义 ...

  2. 基于Spring Boot的统一异常处理设计

    基于Spring Boot的统一异常处理设计 作者: Grey 原文地址:https://www.cnblogs.com/greyzeng/p/11733327.html Spring Boot中,支 ...

  3. 基于spring boot的统一异常处理

    一.springboot的默认异常处理 Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容. 例如这里我 ...

  4. Spring中的统一异常处理方式

    源自:https://segmentfault.com/a/1190000016236188 在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的. 因此, ...

  5. Spring 中的统一异常处理

    在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的.因此,肯定需要在Controller捕获所有异常,并且做适当处理,返回给前端一个友好的错误码. 不过, ...

  6. Spring MVC自定义统一异常处理类,并且在控制台中输出错误日志

    在使用SimpleMappingExceptionResolver实现统一异常处理后(参考Spring MVC的异常统一处理方法), 发现出现异常时,log4j无法在控制台输出错误日志.因此需要自定义 ...

  7. spring boot配置统一异常处理

    基于@ControllerAdvice的统一异常处理 >.这里ServerException是我自定义的异常,和普通Exception分开处理 >.这里的RequestResult是我自定 ...

  8. Spring Boot实践——统一异常处理

    注解说明 @ControllerAdvice,是Spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强.让我们先看看@ControllerAdvice的实现: /** * Special ...

  9. 【Spring Boot】Spring Boot之统一异常处理

    一.统一异常处理的作用 在web应用中,请求处理时,出现异常是非常常见的.所以当应用出现各类异常时,进行异常的统一捕获或者二次处理(比如空指针异常或sql异常正常是不能外抛)是非常必要的,然后右统一异 ...

  10. Spring Cloud:统一异常处理

    在启动应用时会发现在控制台打印的日志中出现了两个路径为 {[/error]} 的访问地址,当系统中发送异常错误时,Spring Boot 会根据请求方式分别跳转到以 JSON 格式或以界面显示的 /e ...

随机推荐

  1. 莫队算法(基础莫队)小结(也做markdown测试)

    莫队 基础莫队 本质是通过排序优化了普通尺取法的时间复杂度. 考虑如果某一列询问的右端点是递增的,那么我们更新答案的时候,右指针只会从左往右移动,那么i指针的移动次数是$O(n)$的. 当然,我们不可 ...

  2. Linux(四):Linux的打包和压缩详解

    关于Linux的文件操作,这里汇总一下打包和压缩的一些命令,以及命令使用的详情. 打包(归档)和压缩 归档,也称为打包,指的是一个文件或目录的集合,而这个集合被存储在一个文件中.归档文件没有经过压缩, ...

  3. Linux(三):Linux的目录及相关作用

    使用 Linux,不仅限于学习各种命令,了解整个 Linux 文件系统的目录结构以及各个目录的功能同样至关重要.使用 Linux 时,通过命令行输入 ls -l / 可以看到,在 Linux 根目录( ...

  4. lca总结+树上差分

    lca lca简称最近公共祖先--简介在此,不过多赘述 这里主要写的是倍增算法,oi-wiki上用的是vector,由于本人不会,只会用链表,所以这里就放链表的代码了 例题 加一个数组按倍增数组的方式 ...

  5. 记录一次对MQTT协议的渗透测试经历

    前言 由于工作需要,特意翻查了MQTT的相关漏洞,并一一学习复现,在此做以学习记录,没有恶意,如有抄袭,请私信作者删除. 技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站.服务器等 ...

  6. WPF,Frame控件的一个BUG

    我使用WPF默认的frame <Frame Style="{DynamicResource FrameStyle1}" x:Name="frame" He ...

  7. 自动化发布ansible以及awx相关(持续更新)

    一 本文章只介绍ansible的基础知识以及一些组织架构,如何批量的处理等 首先一套部署发布任务在ansible里面都是以role的形式展现,并在执行命令的时候执行role入口以及主机列表 例如:an ...

  8. 将外部jar打入本地maven仓库

    1.将jar包放入某不含中文的路径下 ,例如:E:\file\zip4j-1.3.2.jar 2.在命令行输入操作命令 mvn install:install-file -DgroupId=zip4j ...

  9. P1683 入门

    传送锚点:https://www.luogu.com.cn/problem/P1683 题目描述 不是任何人都可以进入桃花岛的,黄药师最讨厌像郭靖一样呆头呆脑的人.所以,他在桃花岛的唯一入口处修了一条 ...

  10. OpenQA.Selenium.WebDriverException The HTTP request to the remote WebDriver server for URL timed out

    OpenQA.Selenium.WebDriverException:"The HTTP request to the remote WebDriver server for URL htt ...