[TOC]
统一异常处理。支持返回统一的Json格式和跳转到错误页面。
我们项目中难免会遇到一些异常,比如自定义异常、参数传递异常等等其他异常。遇到异常我们一般是捕获并解决,或者直接将错误信息抛给客户端,问题来了,一堆乱七八糟的错误日志直接抛给用户,用户看得懂吗?会有人说,那可以直接判断状态码不是200的话就弹出系统异常等字样提示。是可以的,但是我们想更精确的知道是什么异常,比如参数异常,我们的业务异常等,所以这个exception-handler
就是一个统一异常处理的工具类。他能帮我们处理你任何自定义的异常以及其他异常,处理方式为统一返回如下格式的JSON给客户端
{
"code": 1,
"msg": "系统异常",
"result": "xxxxx"
}
注意:不同类型的异常code是不同的,内置分为参数异常和系统异常,前端可以根据不同的code来进行不同的处理,比如跳转不同的页面等。
我上面说了有什么用,现在来说说具体怎么用。分为两种使用,一种是maven项目的使用,一种是非maven项目的使用。
maven项目的使用
首先下载此项目,在项目根目录(包含pom.xml的目录)运行如下命令
mvn clean install
然后将如下配置放到你项目的pom.xml中
<dependency>
<groupId>com.chentongwei</groupId>
<artifactId>exception-handler</artifactId>
<version>1.0.0</version>
</dependency>
非maven项目的使用
首先下载项目,然后导出成jar包放到项目的lib目录。
接下来说下spring项目和springboot项目如何使用
spring
使用
直接复制下面配置到你的配置文件即可。
<bean id="exceptionResolver" class="com.chentongwei.interceptor.ExceptionResolver" />
springboot
使用
将如下配置类复制到你项目中受spring所管理的包中即可生效。
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
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
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
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
http://ip:port/projectname/user/1
返回结果
{
"code": 2,
"msg": "未查到此数据",
"result": "未查到此数据"
}
结果简单说明
上面的JSON数据很明显是我们自定义枚举类里的内容,所以这样就达到了可扩展,根据不同的业务可以抛出不同的异常。而我们的exception-handler
全都会为我们捕获并抛给客户端。
跳转页面配置
上面说的是返回统一的JSON,接下来简单说下如果不是静态分离的项目,应该如何配置才能跳转到自定义的异常页面上。
在resources
目录下新建system.properties
,里面支持两个参数,如下
com.chentongwei.exception.handler.type=HTML
com.chentongwei.exception.view=/error.html
第一个参数若不配置则默认是返回JSON,这里配置为HTML,则就会触发跳转到页面的逻辑,而不是统一返回JSON的逻辑;第二个参数是需要跳转到哪个页面上。
如果你有用到Hibernate Valid(比如@NotNull,@NotEmpty等等注解验证),则我们的exception-handler
也为我们捕获了此异常,称之为参数传递异常。如下做个Demo进行演示查看效果
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<User> query(@Valid UserIO userIO) {
return null;
}
调用URL
http://ip:port/projectname/user?username=&age=101
返回结果
{
"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,共同交流一起进步!
个人名言:
什么都要会一点,这样装起逼来不会尴尬。
彪悍的人生不需要解释。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型