前言
异常处理在一个可靠的程序中起着至关重要的工作,合理的异常是一个程序迭代的基石。 抛出异常不同于return
只会返回当前上下文环境,异常可以从内层向外层不断抛出。
如何接管异常
springMvc 提供了@ControllerAdvice
和@RestControllerAdvice
注解,用来接管所有由@Controller
产生的异常,由于我们是API的异常处理所以只需要@RestControllerAdvice
,当然这两者可以都可以使用
例子:
// @ControllerAdvice指定所有@RestController注解的类由此类处理异常
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice {}
// 也可以直接使用@RestControllerAdvice指定
@RestControllerAdvice
public class ExampleAdvice {}
全局的异常处理
在前后端交互项目中,前端需要根据错误代码把错误消息提示用户,这样能有最佳的用户体验,为了让跟前端同事配合往往需要统一异常的格式,这样前端同事仅需要判断错误码来提示用户。
例子:
{
"code": 0, // 这里是返回码,
"msg": "success", // 返回消息的内容
},
{
"code": 401, // 这里是返回码,
"msg": "Unauthorized", // 返回消息的内容
},
{
"code": 403, // 这里是返回码,
"msg": "没有权限", // 返回消息的内容
}
创建异常类
-
在项目目录创建
controller
,exception
,config
,common
目录 -
在
exception
目录中创建BaseException.java
类作为API的异常基类
package com.example.demo.exception;
/**
* 异常基类
*/
public class BaseException extends Exception{
/**
* 错误码
*/
private int code;
/**
* 错误消息
*/
private String msg;
/**
* 有参构造
*/
public BaseException(int code, String msg) {
super();
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
- 定义完针对所有API的异常,接下来就可以根据业务来定义对应的异常类, 在
exception
目录中创建PasswordException.java
并继承先前定义的BaseException.java
。
package com.example.demo.exception;
public class PasswordException extends BasicException{
/**
* 有参构造
*
* @param code
* @param msg
*/
public PasswordException(int code, String msg) {
/*
这里可以设置自己想要的错误码,在抛出的时候需要指定错误码和错误消息
*/
super(code, msg);
}
/**
* 无参构造
*/
public PasswordException() {
/*
这里设置默认的错误码和错误消息在需要抛出错误的时候直接抛出即可
*/
super(403, "默认消息");
}
}
创建返回类
在common
目录中创建ResponseResult.java
类
这个类的作用是用于在统一处理异常的类ExampleAdvice.java
中
package com.example.demo.common;
import com.example.demo.exception.BaseException;
import lombok.Data;
@Data
public class ResponseResult {
/**
* 错误码
*/
private int code;
/**
* 错误消息
*/
private String msg;
/**
* 接收异常
* @param exception
*/
public ResponseResult(Exception exception) {
if (exception instanceof BaseException) {
this.code = ((BaseException) exception).getCode();
this.msg = ((BaseException) exception).getMsg();
}
// .... 其他情况
}
}
创建统一处理异常类
在config
目录中创建ExampleAdvice.java
类
@ExceptionHandler(PasswordException.class)
这个注解这是决定了该方法用来处理哪个异常- 同样你也可以使用如下方法来指定方法接收多种异常:
@ExceptionHandler({ ThisException.class, ThatException.class })
- 同样你也可以指定处理基础异常类, 当然按照最佳实践,异常方法尽量只处理对应的异常,因为过度混用会异常类的继承引起的问题,如
PasswordException
继承于Exception
:
@ExceptionHandler(Exception.class)
package com.example.demo.config;
import com.example.demo.common.ResponseResult;
import com.example.demo.exception.PasswordException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ExampleAdvice {
// @ExceptionHandler用来设置处理哪个异常
@ExceptionHandler(PasswordException.class)
public ResponseResult passwordException(PasswordException exception) {
return new ResponseResult(exception);
}
}
创建控制器
在controller
文件夹中创建ExceptionController.java
package com.example.demo.controller;
import com.example.demo.common.ResponseResult;
import com.example.demo.exception.PasswordException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/exp")
@RestController
public class ExceptionController {
@RequestMapping("/result")
public ResponseResult result() throws PasswordException {
if (true) {
throw new PasswordtException();
// throw new PasswordException(403, "密码错误");
}
return new ResponseResult();
}
}
测试
使用PostMan测试 localhost:8080/exp/result
可以得到结果
{
"code": 403,
"msg" : "默认消息"
}
注释这一行代码
throw new PasswordtException();
取消注释这一行代码
// throw new PasswordException(403, "密码错误");
再次测试可以得到
{
"code": 403,
"msg" : "密码错误"
}
完结
在实际项目中, 可以根据业务需要来定义异常。