@ControllerAdvice注解的类,会被作用于@RequesMapping注解的方法上。
先来看看它的基本实现
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
被Component注解,说明可以通过<context:component-scan>来扫描到。
在Web开发中,最基本的都是从Controller到Service再到DAO。在开发的过程中,会需要处理各种异常。Service异常往上抛,如果上层没有try-catch,就会出异常。而通过ControllerAdvice 注解,我们可以使得所有异常在controller进行处理,而开发过程中更加专注于业务的处理。
首先定义一个全局异常的处理类
package com.creditease.microloan.mil.loanrepay.exception.handler;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.creditease.microloan.mil.loanrepay.exception.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* 全局异常处理类
* <p>
* Created by Kong on 17/6/12.
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 接口有参数未传
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
@ResponseBody
public JSONObject missActionParam(HttpServletRequest req, MissingServletRequestParameterException e) throws Exception {
return makeErrorObj("接口有参数未传", req, e);
}
/**
* 加密解密错误
*/
@ExceptionHandler(value = CryptException.class)
@ResponseBody
public JSONObject cryptError(HttpServletRequest req, CryptException e) throws Exception {
return makeErrorObj("加密解密有误", req, e);
}
/**
* 数字格式错误
*/
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public JSONObject numberFormatError(HttpServletRequest req, NumberFormatException e) throws Exception {
return makeErrorObj("数字格式错误", req, e);
}
/**
* JSON格式解析错误
*/
@ExceptionHandler(value = JSONException.class)
@ResponseBody
public JSONObject jsonError(HttpServletRequest req, JSONException e) throws Exception {
return makeErrorObj("JSON格式解析错误", req, e);
}
/**
* 服务器内部错误
*/
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public JSONObject nullError(HttpServletRequest req, NullPointerException e) throws Exception {
return makeErrorObj("服务器内部错误", req, e);
}
/**
* HTTP请求外部服务失败
*/
@ExceptionHandler(value = HTTPConnException.class)
@ResponseBody
public JSONObject requestError(HttpServletRequest req, HTTPConnException e) throws Exception {
return makeErrorObj("HTTP请求外部服务失败", req, e);
}
/**
* 绑卡错误
*/
@ExceptionHandler(value = CardException.class)
@ResponseBody
public JSONObject payError(HttpServletRequest req, CardException e) throws Exception {
return makeErrorObj("绑卡错误", req, e);
}
/**
* 支付失败
*/
@ExceptionHandler(value = PayException.class)
@ResponseBody
public JSONObject payError(HttpServletRequest req, PayException e) throws Exception {
return makeErrorObj("支付失败", req, e);
}
/**
* 第三方支付API返回错误
*/
@ExceptionHandler(value = ThirdPartyPaymentException.class)
@ResponseBody
public JSONObject thirdPayError(HttpServletRequest req, ThirdPartyPaymentException e) throws Exception {
return makeErrorObj("第三方支付API返回错误", req, e);
}
/**
* 查询还款计划错误
*/
@ExceptionHandler(value = RepaymentScheduleException.class)
@ResponseBody
public JSONObject scheduleError(HttpServletRequest req, RepaymentScheduleException e) throws Exception {
return makeErrorObj("查询还款计划错误", req, e);
}
/**
* 未知错误
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public JSONObject scheduleError(HttpServletRequest req, Exception e) throws Exception {
return makeErrorObj("未知错误", req, e);
}
/**
* 构造错误信息
*
* @param msg 错误描述
* @param e 异常信息
* @return
*/
private JSONObject makeErrorObj(String msg, HttpServletRequest req, Exception e) {
JSONObject obj = new JSONObject();
obj.put("status", "fail");
obj.put("msg", msg + " (" + e.getMessage() + ")");
JSONObject logObj = new JSONObject();
logObj.put("status", "fail");
logObj.put("msg", msg);
logObj.put("error", e.getMessage());
logObj.put("url", req.getRequestURL());
logObj.put("field", req.getParameterMap());
logger.error(logObj.toJSONString(), e);
return obj;
}
}
通过注解@ExceptionHandler指定异常类型,当被@RequestMapping注解的方法抛出相应的类的异常,就执行相应的异常处理逻辑。
当然我们需要自异常处理类型,比如CryptException,
package com.creditease.microloan.mil.loanrepay.exception;
/**
* Created by weili on 17/6/19.
*/
public class CryptException extends RuntimeException{
public CryptException(String message){super(message);}
public CryptException(String message,Throwable cause){super(message,cause);}
public CryptException(Throwable cause){super(cause);}
}
当然可以自定义多种异常的类型,然后在GlobalExceptionHandler.java中进行处理。这样整个工程的所有的所有异常被集中到一个地方,方便增加和删除,也极大的方便业务的开发。