前言:统一异常处理类(切面类,如下 RequestAspect )返回的值,将会通过切入点(也就是这里那些被增强的接口方法)的返回类型返回。
也就是说,异常处理类假如返回类型是 Object ,那么接口的返回类型就必须大于等于 Object 类,才可以接得住异常处理类得返回值。
其实,关于 AOP 特性,有一个很重要的事情,切入面的返回数据最终还是要通过切入点的返回类型进行返回。
由此可得,统一异常类、接口类得返回类型统统写为 Object ,其实是一种规范。(当然有更好的规范)
统一异常处理使用 Spring AOP 机制,使用 Around 增强 Controller 类的每一个方法,即:对应每一个 SpringMVC 的 Mapping ,都对应的进行了统一的异常处理。
下面代码同时在其中嵌入了打印日志、统一返回数据类型(所有返回的对象都会被包装为统一数据类型)。
处理逻辑
- 获取时间、获取 request 、response、获取参数、获取请求 url;
- 切入点正常执行 -> 打印 url、时间、参数,返回统一返回类包装的数据;
- 切入点执行异常 -> 打印 url、时间、参数、异常信息,返回统一返回类包装的异常信息;
ps:注意这里是 controller 中返回 Object 类型数据的接口才会被接管,如需接管所有返回类型的接口,可用 * 代替 Object。
@Order(0)
@Slf4j
@Aspect
@Component
public class RequestAspect {
private static final String LOGPATTERN = "请求发起:[%s][%s]%s";
/**
* 统一异常处理
* @param joinPoint
* @return
*/
@Around("execution(public Object com.southgis.imap..controller..*.*(..))")
public Object twiceAsOld(ProceedingJoinPoint joinPoint){
// 开始时间,结束时间
Long start = System.currentTimeMillis();
Long end = System.currentTimeMillis();
String paramStr = "";
// request
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
// response
HttpServletResponse response = ((ServletRequestAttributes)requestAttributes).getResponse();
String uri = request.getRequestURI();
try {
// 获取参数
Enumeration<String> enumeration = request.getParameterNames();
Map<String,String> parameterMap = Maps.newHashMap();
while (enumeration.hasMoreElements()){
String parameter = enumeration.nextElement();
parameterMap.put(parameter,request.getParameter(parameter));
}
paramStr = JSONObject.toJSONString(parameterMap);
Object proceed = joinPoint.proceed();
end = System.currentTimeMillis();
if (log.isInfoEnabled()) {
log.info(String.format(LOGPATTERN, uri, (end-start), paramStr));
}
return formatResult(proceed, response);
} catch (ServiceException e) {
if (e.getSource() != null) {
log.error(String.format(LOGPATTERN, uri, (end-start), paramStr), e.getSource());
} else {
log.error(e.getMessage());
}
if (e.getCode() == 400) {
return AjaxRes.warnning(e.getMessage());
}
return AjaxRes.failMsg(e.getMessage());
} catch (Throwable e) { //NOSONAR 此处本来就是设计成捕获所有异常,sonar 不应该检测此处的 Throwable
log.error(String.format(LOGPATTERN, uri, (end-start), paramStr), e);
return AjaxRes.failMsg("服务器异常了:" + e.getMessage());
}
}
// 格式化特定的数据结构
private Object formatResult(Object result, HttpServletResponse response){
if (result instanceof AjaxRes) {
return result;
} else {
return AjaxRes.success(result);
}
}
}