# exception-handler **Repository Path**: geekerdream/exception-handler ## Basic Information - **Project Name**: exception-handler - **Description**: 统一异常处理,配置简单,可扩展。支持Spring项目、SpringBoot项目。 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 34 - **Forks**: 13 - **Created**: 2018-03-04 - **Last Updated**: 2024-08-29 ## Categories & Tags **Categories**: utils **Tags**: None ## README [TOC] ## 作者:编程界的小学生 ## 时间:2018-02-03 ## 项目名称:exception-handler ## 是什么? **统一异常处理。支持返回统一的Json格式和跳转到错误页面。** ## 有什么用? **我们项目中难免会遇到一些异常,比如自定义异常、参数传递异常等等其他异常。遇到异常我们一般是捕获并解决,或者直接将错误信息抛给客户端,问题来了,一堆乱七八糟的错误日志直接抛给用户,用户看得懂吗?会有人说,那可以直接判断状态码不是200的话就弹出系统异常等字样提示。是可以的,但是我们想更精确的知道是什么异常,比如参数异常,我们的业务异常等,所以这个`exception-handler`就是一个统一异常处理的工具类。他能帮我们处理你任何自定义的异常以及其他异常,处理方式为统一返回如下格式的JSON给客户端** ``` { "code": 1, "msg": "系统异常", "result": "xxxxx" } ``` *注意:不同类型的异常code是不同的,内置分为参数异常和系统异常,前端可以根据不同的code来进行不同的处理,比如跳转不同的页面等。* ## 怎么用? **我上面说了有什么用,现在来说说具体怎么用。分为两种使用,一种是maven项目的使用,一种是非maven项目的使用。** **maven项目的使用** *首先下载此项目,在项目根目录(包含pom.xml的目录)运行如下命令* `mvn clean install` *然后将如下配置放到你项目的pom.xml中* ```xml com.chentongwei exception-handler 1.0.0 ``` **非maven项目的使用** *首先下载项目,然后导出成jar包放到项目的lib目录。* **接下来说下spring项目和springboot项目如何使用** **`spring`使用** *直接复制下面配置到你的配置文件即可。* `` **`springboot`使用** *将如下配置类复制到你项目中受spring所管理的包中即可生效。* ```java import com.chentongwei.interceptor.ExceptionResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author TongWei.Chen 2018-03-01 16:13 */ @Configuration public class WebConfig { @Bean public ExceptionResolver getBean() { return new ExceptionResolver(); } } ``` **配置完成后即可使用,如果你项目中报任何错误,都会被系统拦截到并将错误级别(这里所谓的错误级别是指msg)和错误具体信息抛给客户端。如果我们想要抛出我们自定义的异常的怎么办?** **可以直接自己建立自定义异常类并继承`com.chentongwei.exception.ExceptionStrategy`(内置了一个`BussinessException`)** *自定义异常Demo* ```java import com.chentongwei.enums.IBaseEnum; import com.chentongwei.strategy.ExceptionStrategy; /** * @author TongWei.Chen 2018-03-01 15:55 */ public class UserNotExistException extends ExceptionStrategy { private IBaseEnum baseEnum; public IBaseEnum getBaseEnum() { return baseEnum; } public void setBaseEnum(IBaseEnum baseEnum) { this.baseEnum = baseEnum; } public UserNotExistException(IBaseEnum baseEnum) { this.baseEnum = baseEnum; } @Override public IBaseEnum resolverException() { return this.baseEnum; } } ``` *注意:`com.chentongwei.enums.IBaseEnum`是我自定义的一个错误信息枚举接口,所以必须包含比此属性并且带有此属性的构造器。* **如果我们想自定义异常错误码和错误信息怎么办?可以自定义枚举类然后实现`com.chentongwei.enums.IBaseEnum`** *自定义枚举Demo* ```java import com.chentongwei.enums.IBaseEnum; /** * @author TongWei.Chen 2018-03-02 14:20:38 */ public enum ResponseEnum implements IBaseEnum{ NULL(2, "未查到此数据") ; private int code; private String msg; ResponseEnum(int code, String msg) { this.code = code; this.msg = msg; } @Override public int getCode() { return this.code; } @Override public String getMsg() { return this.msg; } } ``` **完整Demo** ```java import com.chentongwei.enums.IBaseEnum; import com.chentongwei.strategy.ExceptionStrategy; /** * @author TongWei.Chen 2018-03-01 15:55 */ public class UserNotExistException extends ExceptionStrategy { private IBaseEnum baseEnum; public IBaseEnum getBaseEnum() { return baseEnum; } public void setBaseEnum(IBaseEnum baseEnum) { this.baseEnum = baseEnum; } public UserNotExistException(IBaseEnum baseEnum) { this.baseEnum = baseEnum; } @Override public IBaseEnum resolverException() { return this.baseEnum; } } import com.chentongwei.enums.IBaseEnum; /** * @author TongWei.Chen 2018-03-02 14:20:38 */ public enum ResponseEnum implements IBaseEnum{ NULL(2, "未查到此数据") ; private int code; private String msg; ResponseEnum(int code, String msg) { this.code = code; this.msg = msg; } @Override public int getCode() { return this.code; } @Override public String getMsg() { return this.msg; } } @RestController public class UserController { @GetMapping("/user/{id}") public void detail(@PathVariable Integer id) { throw new UserNotExistException(ResponseEnum.NULL); } } ``` **调用URL** ```url http://ip:port/projectname/user/1 ``` **返回结果** ```json { "code": 2, "msg": "未查到此数据", "result": "未查到此数据" } ``` **结果简单说明** 上面的JSON数据很明显是我们自定义枚举类里的内容,所以这样就达到了可扩展,根据不同的业务可以抛出不同的异常。而我们的`exception-handler`全都会为我们捕获并抛给客户端。 **跳转页面配置** 上面说的是返回统一的JSON,接下来简单说下如果不是静态分离的项目,应该如何配置才能跳转到自定义的异常页面上。 在`resources`目录下新建`system.properties`,里面支持两个参数,如下 ```properties com.chentongwei.exception.handler.type=HTML com.chentongwei.exception.view=/error.html ``` *第一个参数若不配置则默认是返回JSON,这里配置为HTML,则就会触发跳转到页面的逻辑,而不是统一返回JSON的逻辑;第二个参数是需要跳转到哪个页面上。* ## 项目其他描述 *如果你有用到Hibernate Valid(比如@NotNull,@NotEmpty等等注解验证),则我们的`exception-handler`也为我们捕获了此异常,称之为参数传递异常。如下做个Demo进行演示查看效果* ```java import org.hibernate.validator.constraints.Range; import javax.validation.constraints.NotNull; /** * @author TongWei.Chen 2018-02-28 15:49 */ public class UserIO { @NotNull(message = "用户名不能为空") private String username; @Range(min = 0, max = 100, message = "年龄必须在0~100之间") private int age; private int ageTo; private String xxx; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getAgeTo() { return ageTo; } public void setAgeTo(int ageTo) { this.ageTo = ageTo; } public String getXxx() { return xxx; } public void setXxx(String xxx) { this.xxx = xxx; } } @GetMapping("/user") public List query(@Valid UserIO userIO) { return null; } ``` **调用URL** `http://ip:port/projectname/user?username=&age=101` **返回结果** ```json { "code": 3, "msg": "参数传递异常", "result": "年龄必须在0~100之间并且用户名不能为空" } ``` **结果简单说明** code为3,msg称为参数传递异常,result是具体因为什么而发生异常的一个详细说明。很完美的JSON。完全无需我们在额外管理其他东西。 *PS:对Valid验证不了解的,希望自行学习下,学习成本很低,很了不起的一个校验框架,能省下很多时间,也支持自定义的注解校验,不是此处重点,所以不进行过多讲解。* *日志问题* 我们都想在抛出异常时记录下日志到文件,默认采取的是log4j,若你是logback或其他,请自行将`com.chentongwei.interceptor.ExceptionResolver`里面这句话换掉。 `private static final Logger LOG = LogManager.getLogger("exceptionLog");` 若您采取的是log4j,则只需要声明个name为exceptionLog的logger即可。 *值得注意的地方* 若此项目与您的项目jar重复导致问题的话,请用maven依赖的时候将我这里的jar排除掉即可。 ## 写在最后的话 我是一个对编程充满无限兴趣的小学生。写的东西不是很完美,希望大家多多提ISSUE,共同交流一起进步! *个人名言:* **什么都要会一点,这样装起逼来不会尴尬。** **彪悍的人生不需要解释。**