1、封装自定义响应
在实际项目中,一般会把结果放在一个封装类中,封装类中包含http状态值,状态消息,以及实际的数据。
/**
* Json格式的数据进行响应
* 因为所有的响应的结果都采用Json格式的数据进行响应,所以需要实现Serializable接口
*/
@Data
public class JsonResult<E> implements Serializable {
private Integer state; // 状态码
private String message; // 描述信息
// 数据类型不确定,用E表示任何的数据类型,一个类里如果声明的有泛型的数据类型,类也要声明为泛型
private E data; // 数据
//无参构造
public JsonResult() {
}
//将状态码传给构造方法初始化对象
public JsonResult(Integer state) {
this.state = state;
}
//将状态码和数据传给构造方法初始化对象
public JsonResult(Integer state, E data) {
this.state = state;
this.data = data;
}
//如果有异常,直接将异常传递给构造方法初始化对象
public JsonResult(Throwable e) {
this.message=e.getMessage();
}
/**以及属性的get和set方法*/
}
2、统一异常处理
如果访问到了不存在的页面,或者服务器内出现了异常,SpringBoot会返回默认的错误页面。可以将自定义的错误页面放到SpringBoot的默认规则下的路径。
生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。
2.1、Service层规划可能出现的异常
-
创建业务层异常类的基类-ServiceException继承RuntimeException,重写五个异常处理方法。
-
创建具体的异常处理类-每一个都要继承ServiceException,并重写方法。
-
UserNotFoundException--用户名不存在异常
-
UsernameDuplicatedException--用户名被占用异常
-
PasswordNotMatchException--密码校验不匹配异常
-
InsertException--插入异常
-
UpdateException--更新数据异常
/** * 业务层异常的基类 */ public class ServiceException extends RuntimeException{ // 什么也不返回 public ServiceException() { super(); } //返回异常信息(常用) public ServiceException(String message) { super(message); } //返回异常信息和异常对象(常用) public ServiceException(String message, Throwable cause) { super(message, cause); } public ServiceException(Throwable cause) { super(cause); } protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
-
-
规划好异常后,需要在ServiceImpl写相应业务逻辑,碰到异常就处理。
// 通过user参数来获取传递过来的username String username = user.getUsername(); // 调用findByUsername(username)判断是否被注册过 User result = userMapper.findByUsername(username); // 判断结果集是否为null,不为null的话则需抛出用户名被占用的异常 if(result !=null){ // 抛出异常 throw new UsernameDuplicatedException("用户名被占用!"); }
2.2、Controller层统一异常处理
-
创建控制层基类BaseController--使用@RestControllerAdvice+@ExceptionHandler表示该方法用于处理捕获抛出的异常
@ControllerAdvice 注解的原理是SpringAOP提供的,是将Controller层的方法作为切面,从而对Controller层方法进行拦截处理。
/** 控制层类的基类*/
@RestControllerAdvice
public class BaseController {
public static final int ok = 200; // 操作成功的状态码
/**
* 1.@ExceptionHandler表示该方法用于处理捕获抛出的异常
* 2.什么样的异常才会被这个方法处理呢?所以需要ServiceException.class,
* 这样的话只要是抛出ServiceException异常就会被拦截到handleException方法,
* 此时handleException方法就是请求处理方法,返回值就是需要传递给前端的数据
* 3.被ExceptionHandler修饰后如果项目发生异常,那么异常对象就会被自动传递给此方法的参数列表上,
* 所以形参就需要写Throwable e用来接收异常对象
*/
@ExceptionHandler({ServiceException.class,FileUploadException.class}) // 用于统一处理抛出的异常
public JsonResult<Void> handlerException(Throwable e){
JsonResult<Void> result = new JsonResult<>();
if(e instanceof UsernameDuplicatedException){
result.setState(4000);
result.setMessage("用户名已被占用");
}else if(e instanceof UserNotFoundException){
result.setState(5001);
result.setMessage("用户名不存在的异常");
}else if(e instanceof PasswordNotMatchException){
result.setState(5002);
result.setMessage("用户名密码错误的异常");
}else if(e instanceof InsertException){
result.setState(5003);
result.setMessage("注册时产生未知的异常");
}else if (e instanceof UpdateException) {
result.setState(5004);
result.setMessage("更新数据时产生未知的异常");
}else if (e instanceof FileEmptyException) {
result.setState(6000);
} else if (e instanceof FileSizeException) {
result.setState(6001);
} else if (e instanceof FileTypeException) {
result.setState(6002);
} else if (e instanceof FileStateException) {
result.setState(6003);
} else if (e instanceof FileUploadIOException) {
result.setState(6004);
} else if (e instanceof AddressCountLimitException) {
result.setState(4003);
result.setMessage("用户的收货地址超出上限的异常");
}
return result;
}
}
-
规划创建Controller层要处理的异常
同service层,相同的方式