SpringBoot中對異常的統一處理
異常處理也可以說成是一種數據傳輸方式,簡單來講,可以在Services中拋出異常信息,在controller中接收異常信息,然后就可以返回到頁面顯示了。
異常處理實例
如果我們需要獲取用戶的年齡,并根據年齡進行判斷,并作出不同的響應。
1.首先我們會定義返回結果數據的通用類,如下:
public class Msg {
//狀態碼100-成功,200-失敗
private int code;
//提示信息
private String msg;
//具體提示消息
private String message;
//用戶要返回給瀏覽器的數據
private Map<String, Object> extend = new HashMap<String, Object>();
public static Msg success(String message){
Msg result = new Msg();
result.setCode(100);
result.setMsg("處理成功");
return result;
}
public static Msg fail(String message){
Msg result = new Msg();
result.setCode(200);
result.setMsg("處理失敗");
result.setMessage(message);
return result;
}
public Msg add(String key,Object value){
this.getExtend().put(key, value);
return this;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Map<String, Object> getExtend() {
return extend;
}
public void setExtend(Map<String, Object> extend) {
this.extend = extend;
}
}
2.修改Controller中的添加一個用戶的方法
@PostMapping(value = "/users")
public Msg addUser(@Valid User user, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return Msg.fail(bindingResult.getFieldError().getDefaultMessage());
}
user.setUserName(user.getUserName());
user.setAge(user.getAge());
return Msg.success().add("user",userRepository.save(user));
}
3.測試
我們先測試失敗的時候,我們開始做了一個年齡age的檢驗,不滿足校驗就會報錯,如下:
image
我們再來測試成功的時候,如下:
image
可以看出我們寫的通用的返回類,返回給客戶端的數據格式是一致的。上面僅僅是測試一下我們寫的通用返回類,下面我們將繼續完成對用戶年齡的判斷。
4.Services中添加方法
public void getAge(Integer id){
User user = userRepository.findOne(id);
Integer age = user.getAge();
if(age < 20){
//返回你還在上大學吧
}else if(age > 20 && age < 30){
//返回你剛工作不久吧
}
}
5.userController中根據年齡獲取用戶
@GetMapping(value = "users/getAge/{id}")
public void getAge(@PathVariable("id") Integer id){
userService.getAge(id);
}
但是,在controller中怎么獲取Services中的返回的值,可能有的或說將Services的返回值改為String,如果我們要做其他操作,要返回一個對象或者其他呢,當然還有很多方式可以實現,但是隨著業務的復雜,我們最好的使用統一異常的方式較為好些。
6.修改Services中的getAge方法
public void getAge(Integer id) throws Exception{
User user = userRepository.findOne(id);
Integer age = user.getAge();
if(age < 20){
//返回你還在上大學吧
throw new Exception("你還在上大學吧!!!");
}else if(age > 20 && age < 30){
//返回你剛工作不久吧
throw new Exception("你剛工作不久吧!!!");
}
}
7.增加一個統一異常處理類
import com.study.springbootdemo.domain.Msg;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class ExceptionHandle {
//使用注解說明要捕獲哪一個異常類,Exception是我們拋出異常使用的類
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Msg handle(Exception e){
return Msg.fail(e.getMessage());
}
}
8.測試
首先先看我數據庫中表的信息
image
測試年齡小于20d的異常捕獲和返回
image
測試年齡大于20小于30的異常捕獲和返回
image
9.自定義異常類
使用Exception異常類只能拋出一個異常信息,throw new Exception("你還在上大學吧!!!");,如果我們要拋出其他的信息就要自定義異常類。
public class UserException extends RuntimeException{
private String mes;
public UserException(String msg,String message){
super(message);
this.mes = msg;
}
public String getMes() {
return mes;
}
public void setMes(String mes) {
this.mes = mes;
}
}
10.修改Services類,拋出自定義異常類
public void getAge(Integer id) throws Exception{
User user = userRepository.findOne(id);
Integer age = user.getAge();
if(age < 20){
//返回你還在上大學吧
throw new UserException("年齡小于20的異常","你還在上大學吧!!!");
}else if(age > 20 && age < 30){
//返回你剛工作不久吧
throw new UserException("年齡大于20且小于30的異常","你剛工作不久吧!!!");
}
}
11.異常捕獲類
@ControllerAdvice
public class ExceptionHandle {
//使用注解說明要捕獲哪一個異常類,Exception是我們拋出異常使用的類
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Msg handle(Exception e){
if(e instanceof UserException){
UserException userException = (UserException) e;
userException.getMes();//自定義異常的第一個信息
userException.getMessage();//自定義異常的第二個信息
return Msg.fail(userException.getMes());
}
return Msg.fail(e.getMessage());
}
}
12優化Services
如果有很多的異常信息在各個類中拋出,修改和維護就特別困難,所以我們使用枚舉來統一管理,新建一個枚舉
public enum ResultEnum {
ERROR_ONE("101","你還在上大學吧!!!"),
ERRON_TWO("102","你剛工作不久吧!!!")
;
private String mes;
private String message;
public String getMes() {
return mes;
}
ResultEnum(String msg,String message){
this.mes = msg;
this.message = message;
}
public String getMessage() {
return message;
}
}
然后修改我們自定義異常類
public class UserException extends RuntimeException{
private String mes;
public UserException(ResultEnum resultEnum){
super(resultEnum.getMessage());
this.mes = mes;
}
public String getMes() {
return mes;
}
public void setMes(String mes) {
this.mes = mes;
}
}
修改我們的Services
public void getAge(Integer id) throws Exception{
User user = userRepository.findOne(id);
Integer age = user.getAge();
if(age < 20){
//返回你還在上大學吧
throw new UserException(ResultEnum.ERROR_ONE);
}else if(age > 20 && age < 30){
//返回你剛工作不久吧
throw new UserException(ResultEnum.ERRON_TWO);
}
}