简介
一、定义运行异常父类
二、定义异常响应对象和返回的Code状态码
三、定义全局异常类
四、使用全局异常类
简介
对全局运行异常处理进行封装,出现异常返回异常编码和自定义异常信息。
一、定义运行异常父类
以经常用的运行时异常RuntimeException为例
设计思想:
1、我们在定义自定义异常时,给前端发送异常的文本内容,但前端不通过文本判断
2、接口处理成功时不需要返回异常信息,前端接收到成功会自动跳转
3、返回的内容从对数据库影响的行数(例子)改为状态码和描述信息
import lombok.Getter;
public class ServiceException extends RuntimeException {
/**
* 状态码
*/
@Getter
private Integer state;
public ServiceException(Integer state, String message) {
super(message);
this.state = state;
}
}
二、定义异常响应对象和返回的Code状态码
import cn.tedu.csmall.product.ex.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JsonResult implements Serializable {
/**
* 状态码
*/
private Integer state;
/**
* 操作“失败”时的描述文本
*/
private String message;
public static JsonResult ok() {
JsonResult jsonResult = new JsonResult();
//ServiceCode.OK的这种写法是为了统一标准,且修改方便
jsonResult.setState(ServiceCode.OK);
return jsonResult;
}
/**
* 重载的错误返回,返回自己错误的异常信息
*/
public static JsonResult fail(ServiceException e) {
return fail(e.getState(), e.getMessage());
}
/**
* 重载的错误返回,不同的实现方式
*/
public static JsonResult fail(Integer state, String message) {
JsonResult jsonResult = new JsonResult();
jsonResult.setState(state);
jsonResult.setMessage(message);
return jsonResult;
}
}
public class ServiceCode {
public static final Integer OK = 200;
public static final Integer ERR_NOT_FOUND = 404;
public static final Integer ERR_CONFLICT = 409;
}
三、定义全局异常类
import cn.tedu.csmall.product.ex.ServiceException;
import cn.tedu.csmall.product.web.JsonResult;
import cn.tedu.csmall.product.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
/**
* 全局异常处理器
*/
@Slf4j//日志
@RestControllerAdvice //异常集合类
public class GlobalExceptionHandler {
/**
* 常见的运行时异常的响应信息
*/
@ExceptionHandler
public JsonResult handleServiceException(ServiceException e) {
return JsonResult.fail(e);
}
/**
* 在接收DTO对象但对象参数,属性不对时返回错误信息
*/
@ExceptionHandler
public JsonResult handleBindException(BindException e) {
//第二种写法,其实直接传入e也行
String message = e.getFieldError().getDefaultMessage();
return JsonResult.fail(ServiceCode.ERR_CONFLICT, message);
}
/**
* 异常的顶级父类异常,可以防止500错误,且将信息都能够输出到控制台中
* 一般用于输出服务器错误,就是还没定的错误处理机制,但遇上了,就走这个异常处理方法
*/
@ExceptionHandler
public String handleThrowable(Throwable e) {
String message = "服务器忙,请稍后再尝试,或联系系统管理员!(在开发过程中,看到此消息,应该检查出现异常的原因,并补充对此类异常的针对性的处理)";
log.warn("程序执行过程中出现Throwable!");
log.warn("异常类型:{}", e.getClass().getName());
log.warn("异常信息:{}", e.getMessage());
log.warn("异常跟踪信息如下:", e); // 输出异常信息时,第1个参数中不要使用占位符
// e.printStackTrace();
return message;
}
}
四、使用全局异常类
import cn.tedu.csmall.product.ex.ServiceException;
import cn.tedu.csmall.product.web.ServiceCode;
import org.springframework.web.bind.annotation.*;
@ResponseBody
@RestController
public class test {
/**
* 除法计算
*/
@GetMapping("/divide/{a}/{b}")
public int divide(@PathVariable("a") int a, @PathVariable("b") int b){
if(b==0){
throw new ServiceException(ServiceCode. BAD_REQUEST ,"被除数b为0");
//throw new ServiceException(400,"b为0");
}
return a/b;
}
/**
* 模拟添加字符串到数组
*/
@GetMapping("/addToArr/{a}")
public String addToArr(@PathVariable("a") String txt){
String [] a = {};
a[1]=txt;
return "模拟字符串添加进数组";
}
}
测试的内容
除法测试
模拟添加字符串到数组测试
综上所述:全局异常处理可以将运行时的异常进行封装,当出现异常时返回异常编码和异常信息的JSON信息,且面对不同的异常通过设置不同的message来设置响应的异常信息。
可以用于减少代码量,使前端可以快速的判断不同的响应状态
且可以对全局异常进行输出(不会返回500响应)