@ControllerAdvice
该注解为统一异常处理的核心
是一种作用于控制层的切面通知(Advice),该注解能够将通用的@ExceptionHandler、@InitBinder和@ModelAttributes方法收集到一个类型,并应用到所有控制器上
该类中的设计思路:
使用@ExceptionHandler注解捕获指定或自定义的异常;
使用@ControllerAdvice集成@ExceptionHandler的方法到一个类中;
必须定义一个通用的异常捕获方法,便于捕获未定义的异常信息;
自定一个异常类,捕获针对项目或业务的异常;
异常的对象信息补充到统一结果枚举中;
自定义全局异常类
import com.example.demo.util.R;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 全局异常处理类
*/
@ControllerAdvice
public class CommonExceptionHandler {
/**
* 通用异常处理
* @param ex
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public R exceptionHandler(Exception ex) {
//输出异常信息
ex.printStackTrace();
//处理校验注解异常信息
if (ex instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException mex = (MethodArgumentNotValidException) ex;
List<FieldError> errorList = mex.getBindingResult().getFieldErrors();
StringBuffer strBuffer = new StringBuffer();
for(FieldError err: errorList){
strBuffer.append(err.getDefaultMessage()).append(",");
}
return R.failed(strBuffer.substring(0, strBuffer.length() - 1));
} else {
return R.failed(ex.getMessage());
}
}
/**
* 单独针对某个异常处理
* @param e
* @return
*/
@ExceptionHandler(NullPointerException.class)
@ResponseBody
public R error(NullPointerException e) {
//输出异常信息
e.printStackTrace();
return R.failed("空指针异常");
}
}
这就是主要核心的代码。
SpringBoot代码示例
1.项目目录:
2.Controller代码:
import com.example.demo.model.User;
import com.example.demo.util.R;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
* 用户登录控制器
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
/**
* 用户登录
* @param user
* @return
*/
@PostMapping(value = "/login")
public R login(@Valid @RequestBody User user){
System.out.println("登录成功!");
return R.ok(user);
}
}
3.User实体类
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 用户登录实体类
*/
@Data
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
@Size(max = 20, min = 6, message = "密码长度在6-20字符之间")
private String password;
}
4.ApiCode枚举
/**
* api枚举器
*/
public enum ApiCode {
FAILED(-1L, "操作失败"),
SUCCESS(0L, "执行成功");
private final long code;
private final String msg;
private ApiCode(long code, String msg) {
this.code = code;
this.msg = msg;
}
public long getCode() {
return this.code;
}
public String getMsg() {
return this.msg;
}
}
5.R返回对象参考了mybatis-plus中R对象的设计
import com.example.demo.myenum.ApiCode;
import lombok.Data;
/**
* 返回对象
*/
@Data
public class R<T> {
private long code;
private String msg;
private T data;
public R() {
}
public static <T> R<T> ok(T data) {
ApiCode aec = ApiCode.SUCCESS;
if(data instanceof Boolean && Boolean.FALSE.equals(data)) {
aec = ApiCode.FAILED;
}
return restResult(data, aec.getCode(), aec.getMsg());
}
public static <T> R<T> failed(String msg) {
return restResult(null, ApiCode.FAILED.getCode(), msg);
}
private static <T> R<T> restResult(T data, long code, String msg) {
R<T> apiResult = new R();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
}
PostMan请求测试
看到这个结果我们的全局统一处理注解校验异常就成功了。