什么是@ControllerAdvice
查看源码的相关注释:
@ControllerAdvice是一个特殊的@Component,用于标识一个类,这个类中被以下三种注解标识的方法:@ExceptionHandler,@InitBinder,@ModelAttribute,将作用于所有的@Controller类的接口上。
个人看起来,觉得像是@controller的增强类,可以对所有的相关接口进行辅助操作。关于Advice,在Spring的AOP中,是用来封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的.
如何在代码中定义全局的异常处理
@ControllerAdvice结合@ExceptionHandler,可以统一处理来自前后端交互产生的异常,并设置到Result对象中,返回给前端,保持系统风格一致。
/**
*全局异常处理类
*用于接收@Controller类抛出的异常并处理
*/
@ControllerAdvice(basePackages={""})
@Slf4j
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = Exception.class) //指定拦截异常类型,可自定义异常类
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) //自定义浏览器返回状态码
public Result<String> handle(Exception e) {
return GlobalExceptionHandler.mapExceptionToResult(e);
}
//此方法可以针对不同的异常进行相应处理
public static Result<String> mapExceptionToResult(Exception e){
//SystemException、WarnException可以由自己定义异常
if(e instanceof SystemException){
SystemException s=(SystemException)e;
return s.toResult();
}else if(e instanceof WarnException){
WarnException w=(WarnException)e;
return w.toResult();
}
return null;
}
}
//自定义异常类
@Slf4j
@Data
public class WarnException extends RuntimeException{
/**
* 异常流水号
*/
protected final String seqNo;
/**
* 抛出异常的源服务信息, appid + : + ip
*/
protected final String sourceService;
/**
* 错误码
*/
protected final String errorCode;
/**
* 抛出异常的源服务信息
*/
public volatile static String sourceServiceCache;
private static final RespLevel RESP_LEVEL = "警告信息-用户输入不合适、不合法";
public WarnException(String message){
this((String)null, message);
}
public WarnException(String message, Throwable t){
this(message, null, t);
}
public WarnException(String errorCode, String message){
this(errorCode, message, null, null, null);
}
public WarnException(String message, String seqNo, Throwable t){
this(message, seqNo, null, t);
}
public WarnException(String message, String seqNo, String sourceService){
this(null, message, seqNo, sourceService, null);
}
public WarnException(String message, String seqNo, String sourceService, Throwable t){
this(null, message, seqNo, sourceService, t);
}
public WarnException(String errorCode, String message, String seqNo, String sourceService){
this(errorCode, message, seqNo, sourceService, null);
}
public WarnException(String errorCode, String message, String seqNo, String sourceService, Throwable t){
super(message, t);
this.errorCode = StringUtils.defaultString(errorCode, Result.FALSE_CODE);
this.seqNo = StringUtils.defaultString(seqNo, generateSeqNo());
this.sourceService = StringUtils.defaultIfBlank(sourceService, sourceServiceCache);
}
/**
* 生成日志流水号
* 格式为 年月日时分秒毫秒(17位)+7位随机字符串,共24位
* */
private String generateSeqNo(){
int length=7;
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
Calendar c= Calendar.getInstance();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(new Random().nextInt(10));
}
return format.format(c.getTime())+sb.toString();
}
/**
* 将异常转换成接口响应数据
* @param <T>
* @return
*/
public <T> Result<T> toResult(){
Result<T> result = new Result<>();
String message = getMessage();
String seqNo = getSeqNo();
result.setErrorMessage(message, getErrorCode());
result.setErrorSeqNo(seqNo);
result.setLevel(RESP_LEVEL );
result.setSourceService(getSourceService());
return result;
}
}
//自定义返回给前端的数据类型
@ApiModel(value = "restful接口响应结果")
@Data
public class Result<T> {
public static final String SUCCESS = "S";
public static final String FALSE = "F";
public static final String SUCCESS_CODE = "000000";
public static final String FALSE_CODE = "999999";
public static final String SUCCESS_MSG = "操作成功";
public static final String FALSE_MSG = "操作失败";
public static final String FAILED_MSG = "系统暂时无法处理您的操作,请联系管理员";// 默认的异常提示
@ApiModelProperty(name = "returnStatus", value = "接口执行状态:S-成功,F-失败", notes = "新建默认为失败")
private String returnStatus = FALSE;
@ApiModelProperty(name = "returnCode", value = "接口返回码:000000-成功,非000000-失败", notes = "错误码定义见XXX,默认失败码为999999")
private String returnCode = FALSE_CODE;
@ApiModelProperty(name = "errorSeqNo", value = "异常信息流水号")
private String errorSeqNo;
@ApiModelProperty(name = "returnMessage", value = "接口返消息", notes = "")
private String returnMessage = FALSE_MSG;
@ApiModelProperty(value = "异常源服务信息, 比如90195:192.168.1.1")
private String sourceService;
@ApiModelProperty(value = "响应信息等级, WARN-用户输入不合适、不合法, ERROR-系统错误, NOTICE-常规提示信息")
private RespLevel level;
@ApiModelProperty(name = "data", value = "返回数据", notes = "")
private T data;
public Result() {
super();
}
public static <T> Result<T> getSuccessResultInstance() {
Result<T> result = new Result<>();
result.setSuccess();
return result;
}
public static <T> Result<T> getSuccessResultDataInstance(T data) {
Result<T> result = new Result<>();
result.setSuccess();
result.setData(data);
return result;
}
public static <T> Result<T> getSuccessResultInstance(String returnMessage) {
Result<T> result = new Result<>();
result.setSuccessWithMessage(returnMessage);
return result;
}
public static <T> Result<T> getFalseResultInstance() {
return new Result<>();
}
public static <T> Result<T> getFalseResultInstance(String errorMessage) {
Result<T> result = new Result<>();
result.setErrorMessageWithDefaultErrorCode(errorMessage);
return result;
}
public static <T> Result<T> getFalseResultInstance(String errorMessage, T data) {
Result<T> result = new Result<>();
result.setErrorMessageWithDefaultErrorCode(errorMessage);
result.setData(data);
return result;
}
public static <T> Result<T> getSuccessResulInstance(String successMessage, String successCode) {
Result<T> result = new Result<>();
result.setSuccessMessage(successMessage, successCode);
return result;
}
public static <T> Result<T> getExceptionResultInstance(String errorMessage, String errorCode, String errorSeqNo) {
Result<T> result = new Result<>();
result.setErrorMessage(errorMessage, errorCode);
result.setErrorSeqNo(errorSeqNo);
return result;
}
public static <T> Result<T> getFalseResultInstance(String errorMessage, String errorCode) {
Result<T> result = new Result<>();
result.setErrorMessage(errorMessage, errorCode);
return result;
}
/**
* 设置消息为成功
*/
public void setSuccess() {
this.returnStatus = SUCCESS;
this.returnCode = SUCCESS_CODE;
this.returnMessage = SUCCESS_MSG;
}
public void setSuccessWithMessage(String returnMessage) {
this.returnStatus = SUCCESS;
this.returnCode = SUCCESS_CODE;
this.returnMessage = returnMessage;
}
/**
* 返回默认错误码999999
*/
public void setErrorMessageWithDefaultErrorCode(String errorMessage) {
this.returnMessage = errorMessage;
}
public void setErrorMessage(String errorMessage, String errorCode) {
this.returnMessage = errorMessage;
this.returnCode = errorCode;
}
private void setSuccessMessage(String successMessage, String successCode) {
this.returnStatus = SUCCESS;
this.returnMessage = successMessage;
this.returnCode = successCode;
}
@JsonIgnore
public boolean isAllSuccess() {
return SUCCESS.equals(returnStatus) && SUCCESS_CODE.equals(returnCode);
}
/**
* 将接口响应转换成系统的功能异常,如果接口是成功的,则返回null
* @return
*/
public WarnException toException(){
RespLevel level = getLevel();
if (FALSE.equals(getReturnStatus())){
if (level == RespLevel.WARN){
return new WarnException(getReturnCode(), getReturnMessage(), getErrorSeqNo(), getSourceService());
}
return new SystemException(getReturnCode(), getReturnMessage(), getErrorSeqNo(), getSourceService());
}
return null;
}
/**
* 返回成功
* @param data
* @param <T>
* @return
*/
public static <T> Result<T> succeed(T data){
return succeed(SUCCESS_MSG, data);
}
/**
* 返回成功, 指定信息
* @param message 成功提示信息
* @param data
* @param <T>
* @return
*/
public static <T> Result<T> succeed(String message, T data){
return succeed(SUCCESS_CODE, message, data);
}
/**
* 返回成功
* @param data
* @param <T>
* @return
*/
public static <T> Result<T> succeed(String code, String message, T data){
return new Result<>(SUCCESS, SUCCESS_CODE, message, RespLevel.SUCCESS, null, null, data);
}
/**
* 返回失败, 默认的提示信息
* @param <T>
* @return
*/
public static <T> Result<T> error(){
return error(FAILED_MSG);
}
/**
* 返回失败, 指定信息
* @param message
* @param <T>S
* @return
*/
public static <T> Result<T> error(String message){
return new Result<T>(FALSE, FALSE_CODE, message, RespLevel.ERROR, BizException.generateSeqNo(), SystemException.sourceServiceCache);
}
/**
* 返回警告, 用户输入错误,如参数不合法、入口错误等
* @param message 警告提示信息, 提示用户修改
* @param <T>
* @return
*/
public static <T> Result<T> warn(String message){
return new Result<>(FALSE, FALSE_CODE, message, RespLevel.WARN, null, WarnException.sourceServiceCache);
}
/**
* 返回notice类型的消息
* @param message
* @param <T>
* @return
*/
public static <T> Result<T> info(String message){
return new Result<>(SUCCESS, SUCCESS_CODE, message, RespLevel.INFO, null, null);
}
private Result(String returnStatus, String code, String message){
this(returnStatus, code, message, RespLevel.INFO, null, null);
}
private Result(String returnStatus, String code, String message, RespLevel level, String seqNo, String sourceService){
this(returnStatus, code, message, level, seqNo, sourceService, null);
}
private Result(String returnStatus, String code, String message, RespLevel level, String seqNo, String sourceService, T data){
this.returnStatus = returnStatus;
this.returnCode = code;
this.returnMessage = message;
this.level = level;
this.errorSeqNo = seqNo;
this.sourceService = sourceService;
this.data = data;
}
}
//controller层
@RestController
@Slf4j
public class QuotaController{
@Autowired
IQuotaService iQuotaService;
//此方法抛出的异常都可以被全局异常类处理,包括其iQuotaInfoService类的具体实现中也可以,使用throw
// if ("".equals(a)) {
// throw new WarnException("eee");
// }
public Result<QuotaRsp> getQuotatail(QuotaReq quotaReq) {
QuotaRsp quotaRsp = iQuotaInfoService.quota(quotaReq);
return Result.getSuccessResultDataInstance(quotaRsp);
}
}
其他:
@RestControllerAdvice = @ControllerAdvice+ @ResponseBody