目录
@ControllerAdvice 用法
顾名思义,@ControllerAdvice就是@Controller 的增强版。@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用。
1、全局异常处理
@ControllerAdvice最常见的使用场景就是全局异常处理。比如文件上传大小限制的配置,如果用户上传的文件超过了限制大小,就会抛出异常,此时可以通过@ControllerAdvice结合@ExceptionHandler定义全局异常捕获机制,代码如下:
import lombok.extern.slf4j.Slf4j;
import net.xdclass.util.JsonData;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@ControllerAdvice // 需要返回ResponseBody
// @RestControllerAdvice 直接返回Json数据不用返回ResponseBody
@Slf4j
public class CustomExceptionHandler {
// 自定义异常
@ExceptionHandler(value = Exception.class) // 要捕获哪种异常
@ResponseBody // 要是用上面的 @RestControllerAdvice 就不用加此注解
public JsonData handler(Exception e) {
if (e instanceof RuntimeException) { // 判断是不是其子类
BizException bizException = (BizException) e;
log.error("[业务异常]{}", e);
return JsonData.buildCodeAndMsg(bizException.getCode(), bizException.getMsg());
} else {
log.error("[系统异常]{},e");
return JsonData.buildError("系统异常");
}
}
}
附 BizException.class,代码如下
import lombok.Data;
import net.xdclass.enums.BizCodeEnum;
@Data
public class BizException extends RuntimeException {
private int code;
private String msg;
// 构造函数
public BizException(Integer code, String message) {
super(message);
this.code = code;
this.msg = message;
}
// 构造函数
public BizException(BizCodeEnum bizCodeEnum) {
super(bizCodeEnum.getMessage());
this.code = bizCodeEnum.getCode();
this.msg = bizCodeEnum.getMessage();
}
}
自定义异常枚举类 BizCodeEnum.java
public enum BizCodeEnum {
/**
* 短链分组
*/
GROUP_REPEAT(23001, "分组名重复"),
GROUP_OPER_FAIL(23503, "分组名操作失败"),
GROUP_NOT_EXIST(23404, "分组不存在"),
/**
* 验证码
*/
CODE_TO_ERROR(240001, "接收号码不合规"),
CODE_LIMITED(240002, "验证码发送过快"),
CODE_ERROR(240003, "验证码错误"),
CODE_CAPTCHA_ERROR(240101, "图形验证码错误"),
/**
* 账号
*/
ACCOUNT_REPEAT(250001, "账号已经存在"),
ACCOUNT_UNREGISTER(250002, "账号不存在"),
ACCOUNT_PWD_ERROR(250003, "账号或者密码错误"),
ACCOUNT_UNLOGIN(250004, "账号未登录"),
/**
* 短链
*/
SHORT_LINK_NOT_EXIST(260404, "短链不存在"),
/**
* 订单
*/
ORDER_CONFIRM_PRICE_FAIL(280002, "创建订单-验价失败"),
ORDER_CONFIRM_REPEAT(280008, "订单恶意-重复提交"),
ORDER_CONFIRM_TOKEN_EQUAL_FAIL(280009, "订单令牌缺少"),
ORDER_CONFIRM_NOT_EXIST(280010, "订单不存在"),
/**
* 支付
*/
PAY_ORDER_FAIL(300001, "创建支付订单失败"),
PAY_ORDER_CALLBACK_SIGN_FAIL(300002, "支付订单回调验证签失败"),
PAY_ORDER_CALLBACK_NOT_SUCCESS(300003, "支付宝回调更新订单失败"),
PAY_ORDER_NOT_EXIST(300005, "订单不存在"),
PAY_ORDER_STATE_ERROR(300006, "订单状态不正常"),
PAY_ORDER_PAY_TIMEOUT(300007, "订单支付超时"),
/**
* 流控操作
*/
CONTROL_FLOW(500101, "限流控制"),
CONTROL_DEGRADE(500201, "降级控制"),
CONTROL_AUTH(500301, "认证控制"),
/**
* 流量包操作
*/
TRAFFIC_FREE_NOT_EXIST(600101, "免费流量包不存在,联系客服"),
TRAFFIC_REDUCE_FAIL(600102, "流量不足,扣减失败"),
TRAFFIC_EXCEPTION(600103, "流量包数据异常,用户无流量包"),
/**
* 通用操作码
*/
OPS_REPEAT(110001, "重复操作"),
OPS_NETWORK_ADDRESS_ERROR(110002, "网络地址错误"),
/**
* 文件相关
*/
FILE_UPLOAD_USER_IMG_FAIL(700101, "用户头像文件上传失败");
private String message;
private int code;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
BizCodeEnum(int code, String message) {
this.code = code;
this.message = message;
}
}
只需在系统中定义CustomExceptionHandler类,然后添加@ControllerAdvice注解即可。当系统启动时,该类就会被扫描到Spring容器中,然后定义handler方法,在该方法上添加了@ExceptionHandler注解,其中定义的Exception.class 表明该方法用来处理所有类型的异常。如果想让该方法处理所有类型的异常,只需将Exception改为 其他Exception即可。方法的参数可以有异常实例、HttpServletResponse以及HttpServletRequest、Model 等,返回值可以是一段JSON、一个ModelAndView、一个逻辑视图名等。
2、添加全局数据
@ControllerAdvice是一个全局数据处理组件,因此也可以在@ControllerAdvice中配置全局数据,使用@ModelAttribute注解进行配置,代码如下:
@ControllerAdvice
public class GlobalConfig {
@ModelAttribute(value = "info")
public Map<String, String> userInfo() {
HashMap<String, String> map = new HashMap<>();
map.put("username", "罗贯中");
map.put("gender", "男");
return map;
}
}
代码解释:
- 在全局配置中添加userInfo方法,返回一个map。该方法有一个注解@ModelAttribute,其中的value属性表示这条返回数据的key,而方法的返回值是返回数据的value。
- 此时在任意请求的Controller 中,通过方法参数中的Model都可以获取info 的数据。
Controller 例代码如下:
public class MyController {
@GetMapping("/hello")
@ResponseBody
public void hello(Model model) {
Map<String, Object> map = model.asMap();
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
Object value = map.get(key);
System.out.println(key + ">>>>>" + value);
}
}
}
在请求方法中,将Model 中的数据打印出来,如图所示。
还有其他用法见转载链接