出处:  SpringMVC实现全局异常处理器

  

  我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。这篇博文主要总结一下SpringMVC中如何统一处理异常。

异常处理思路

  首先来看一下在springmvc中,异常处理的思路

Spring MVC处理异常有4种方式: 

(1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver;

(2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器;

(3)使用@ExceptionHandler注解实现异常处理;
(4)使用@ControllerAdvice + @ExceptionHandler

下面使用 @ControllerAdvice + @ExceptionHandler来实现

通过 @ControllerAdvice 注解,我们可以在一个地方对所有 @Controller 注解的控制器进行管理。
注解了 @ControllerAdvice 的类的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,这对所有注解了 @RequestMapping 的控制器内的方法都有效。

  1:@ExceptionHandler:用于捕获所有控制器里面的异常,并进行处理。
  2:@InitBinder:用来设置 WebDataBinder,WebDataBinder 用来自动绑定前台请求参数到 Model 中。
  3:@ModelAttribute:@ModelAttribute 本来的作用是绑定键值对到 Model 里,此处是让全局的@RequestMapping 都能获得在此处设置的键值对。
本文使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理。只要设计得当,就再也不用在 Controller 层进行 try-catch 了!

一、经典案例
 需求:希望通过全局统一的异常处理将自定义错误码以json的形式发送给前端。

1、统一返回结果类 ApiResult
首先,定义一个统一结果返回类,最终需要将这个结果类的内容返回给前端。:

/**
* Api统一的返回结果类
*/
public class ApiResult { /**
* 结果码
*/
private String code; /**
* 结果码描述
*/
private String msg; public ApiResult() {
} public ApiResult(ResultCode resultCode) {
this.code = resultCode.getCode();
this.msg = resultCode.getMsg();
} /**
* 生成一个ApiResult对象, 并返回
*
* @param resultCode
* @return
*/
public static ApiResult of(ResultCode resultCode) {
return new ApiResult(resultCode);
} 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;
} @Override
public String toString() {
return "ApiResult{" +
"code='" + code + '\'' +
", msg='" + msg + '\'' +
'}';
} }

2、错误码枚举类 ResultCode

有了 ApiResult ,接下来需要定义一个枚举类, 来包含所有自定义的结果码。

/**
* 错误码
*/
public enum ResultCode {
SUCCESS("0", "success"),
UNKNOWN_ERROR("0x10001", "unkonwn error"),
USERNAME_ERROR("0x10002", "username error or does not exist"),
PASSWORD_ERROR("0x10003", "password error"),
USERNAME_EMPTY("0x10004", "username can not be empty"); private String code;
private String msg; ResultCode(String code, String msg) {
this.code = code;
this.msg = msg;
} public String getCode() {
return code;
} public String getMsg() {
return msg;
} }

3、自定义业务异常类 BusinessRuntimeException

接下来需要定义我们自己的业务异常类,以后和业务相关的异常通通抛出这个异常类,我们将错误码枚举变量的值存于其中。

/**
* 自定义业务异常
*/
public class BusinessRuntimeException extends RuntimeException{ private String code;
private String msg;
private ResultCode resultCode; public BusinessRuntimeException(ResultCode resultCode) {
super(resultCode.getMsg());
this.code = resultCode.getCode();
this.msg = resultCode.getMsg();
this.resultCode = resultCode;
} 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 ResultCode getResultCode() {
return resultCode;
} public void setResultCode(ResultCode resultCode) {
this.resultCode = resultCode;
} }

4、全局异常处理类 GlobalExceptionResolver
最后便是定义全局异常处理类。

  1:通过 @ControllerAdvice 指定该类为 Controller 增强类。
  2:通过 @ExceptionHandler 自定捕获的异常类型。
  3:通过 @ResponseBody 返回 json 到前端。
注意一点:被@ControllerAdvice注解的全局异常处理类也是一个 Controller ,我们需要配置扫描路径,确保能够扫描到这个Controller。

/**
* 全局Controller层异常处理类
*/
@ControllerAdvice
public class GlobalExceptionResolver { /**
*处理所有不可知异常
* @param e 异常
* @return json结果
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public ApiResult handleException(Exception e) {
System.out.println(e.getMessage());
return ApiResult.of(ResultCode.UNKNOWN_ERROR);
} /**
* 处理所有业务异常
* @param e 业务异常
* @return json结果
*/
@ExceptionHandler(BusinessRuntimeException.class)
@ResponseBody
public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
System.out.println(e.getMessage());
return ApiResult.of(e.getResultCode());
} }

二、测试

1、测试 TestExceptionController

@Controller
@RequestMapping("/test/")
public class TestExceptionController { /**
* 测试返回异常信息
* @return
*/
@RequestMapping(value = "exception.do",method = RequestMethod.GET)
public String returnExceptionInfo() { if (1 != 2) {
// 用户民错误或不存在异常
throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR);
} return "success";
} }

效果:

其他比较全的文章可以看这个: SpringMVC中的统一异常处理

SpringMVC实现全局异常处理器 (转)的更多相关文章

  1. 关于SpringMVC的全局异常处理器

    近几天又温习了一下SpringMVC的运行机制以及原理 我理解的springmvc,是设计模式MVC中C层,也就是Controller(控制)层,常用的注解有@Controller.@RequestM ...

  2. 基于SpringMVC的全局异常处理器介绍(转)

    近几天又温习了一下SpringMVC的运行机制以及原理 我理解的springmvc,是设计模式MVC中C层,也就是Controller(控制)层,常用的注解有@Controller.@RequestM ...

  3. springmvc中拦截器与springmvc全局异常处理器的问题

    最近在做一个练手的小项目, 系统架构中用了springmvc的全局异常处理器, 做了系统的统一异常处理. 后来加入了springmvc的拦截器, 为了一些需求, 在拦截器中的 preHandle 方法 ...

  4. SSM之全局异常处理器

    1. 异常处理思路 首先来看一下在springmvc中,异常处理的思路:   如上图所示,系统的dao.service.controller出现异常都通过throws Exception向上抛出,最后 ...

  5. (转)SpringMVC学习(八)——SpringMVC中的异常处理器

    http://blog.csdn.net/yerenyuan_pku/article/details/72511891 SpringMVC在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常 ...

  6. 13.SpringMVC之全局异常

    我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发.测试通过手段减少运行时异常的发生.在开发中,不管是dao层 ...

  7. Spring Boot 中全局异常处理器

    Spring Boot 中全局异常处理器,就是把错误异常统一处理的方法.等价于Springmvc中的异常处理器. 步骤一:基于前面的springBoot入门小demo修改 步骤二:修改HelloCon ...

  8. 七 异常处理的两种方式(创建全局异常处理器&自定义异常)

    1 创建全局异常处理器 实现HandlerExceptionResolve接口 package com.springmvc01; import javax.servlet.http.HttpServl ...

  9. 从源码看全局异常处理器@ExceptionHandler&@ExceptionHandler的生效原理

    1.开头在前 日常开发中,几乎我们的项目都会用到异常处理器,我们通常会定制属于自己的异常处理器,来处理项目中大大小小.各种各样的异常.配置异常处理器目前最常用的方式应该是使用@ControllerAd ...

随机推荐

  1. Latex里面的\newtheorem*{xx}{yy}后面的*是干什么的?

    答案: 加了*表示不标号.例如: 同样使用命令: \begin{prb} xx\end{prb} 1. \newtheorem{prb}{Problem Formulation} → Problem ...

  2. 24.Python比较运算符(关系运算符

    比较运算符,也成关系运算符,用于对常量.变量或表达式的结果进行大小.真假等比较,如果比较结果为真,则返回 True:反之,则返回 False. Python 支持的比较运算符如表 1 所示. 表 1 ...

  3. Java基础__ToString()方法

    Java toString() 方法 (一).方便println()方法的输出 public class TString { private String name; public TString(S ...

  4. [CSP-S模拟测试]:A(数学)

    题目传送门(内部题44) 输入格式 一行四个整数,分别表示$S,T,a,b$. 输出格式 输出最小步数,数据保证有解. 样例 样例输入: 10 28 4 2 样例输出: 数据范围与提示 样例解释: 先 ...

  5. Padding Oracle 和 CBC字节翻转攻击学习

    以前一直没时间来好好研究下这两种攻击方式,虽然都是很老的点了= =! 0x01:Padding oracle CBC加密模式为分组加密,初始时有初始向量,密钥,以及明文,明文与初始向量异或以后得到中间 ...

  6. MySQL 主从复制 (CentOS 7)

    1.主从复制原理 (1) 当master 服务器上的数据发生改变时,则将其改变写入二进制日志文件中: (2) slave服务器会在一定时间间隔内对 master 服务器上的二进制日志进行探测,探测其是 ...

  7. ftp相关

    已经存在虚拟账户 添加新账户 .在/etc/vsftpd/user.txt里面配置用户名密码 单行是用户名 双行是密码 .导入新用户密码 db_load -T -t hash -f /etc/vsft ...

  8. koa 基础(十五)cookie 设置中文

    1.app.js // 引入模块 const Koa = require('koa'); const router = require('koa-router')(); /*引入是实例化路由 推荐*/ ...

  9. PHP中获取数组中单列的值

    PHP中获取数组中单列的值如下: 利用PHP中的数组函数 array_column():返回数组中某个单列的值.(PHP 5.5+适用) 语法: array_column(array,column_k ...

  10. LC 687. Longest Univalue Path

    Given a binary tree, find the length of the longest path where each node in the path has the same va ...