二、统一异常处理
我们知道项目如果采用分层结构的话,异常需要一层层往上抛,直至到action层,然后在action处理异常,提示友好的异常信息给用户。如果在action的每个方法中都用try{}catch处理,那么类似的代码会很多,且如果需要在异常处理时新增一些逻辑,则需要更改的地方很多,工作量大,不易于维护。于是项目打算采用struts的拦截器机制,实现统一异常处理。
1、struts配置文件
首先自定义拦截器栈,配置如下:
<!-- 自定义拦截器栈 -->
<interceptors>
<interceptor name="defaultExceptionInterceptor" class="xxx.DefaultExceptionInterceptor" />
<interceptor-stack name="systemDefaultStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="defaultExceptionInterceptor" />
</interceptor-stack>
</interceptors>
<!-- 引用默认的拦截器栈 -->
<default-interceptor-ref name="systemDefaultStack" />
2、自定义枚举类(在需要被拦截的方法中加入)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionMeta {
public EOperStatus resultCode() default EOperStatus.FAILURE;
public String message();
}
3、拦截器类(暂时只对ajax请求进行处理)
public class DefaultExceptionInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = -1409945647583201366L;
private final static Logger logger = Logger.getLogger(DefaultExceptionInterceptor.class);
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result = "";
try {
result = invocation.invoke();
} catch(Exception e) {
logger.error(e.getMessage(), e);
// 异常处理
ActionContext actionContext = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
// 判断是否是ajax请求
if(this.isAjaxRequest(request)) {
// 获取请求action类
Class<?> clazz = invocation.getAction().getClass();
// 获取请求action对应的方法名
String methodName = invocation.getProxy().getMethod();
// 从缓存中查找异常对象是否已存在,若存在,则直接返回,否则将异常对象加入缓存中
ExceptionMeta exceptionMeta = this.putIfAbsent(clazz, methodName);
if(exceptionMeta != null) {
// 将异常错误码和异常消息添加到map中
Map<String, Object> operateMap = new HashMap<String, Object>(2);
operateMap.put("resultCode", exceptionMeta.resultCode().id());
operateMap.put("message", exceptionMeta.message());
// 将map放入值栈,然后在xml中将map数据以json格式返回给前台
ValueStack stack = invocation.getStack();
stack.set("operateMap", operateMap);
}
result = "ajaxException";
}
}
return result;
}
/**
* 判断缓存中是否有指定key对应的ExceptionMeta对象,如果有,直接取出缓存中的数据,否则将ExceptionMeta对象加入缓存中
* @param clazz action的class
* @param methodName action对应的方法名
* @return ExceptionMeta
* @throws Exception 异常
*/
private ExceptionMeta putIfAbsent(Class<?> clazz, String methodName) {
try {
String exceptionKey = clazz.getName() + "." + methodName;
ExceptionMeta exceptionMeta = ExceptionCache.get(exceptionKey);
if(exceptionMeta == null) {
Method method = clazz.getMethod(methodName);
if(method != null) {
exceptionMeta = method.getAnnotation(ExceptionMeta.class);
ExceptionCache.put(exceptionKey, exceptionMeta);
}
}
return exceptionMeta;
} catch(Exception e) {}
return null;
}
/**
* 判断请求是否是ajax请求
* @param request HttpServletRequest
* @return true or false
*/
private boolean isAjaxRequest(HttpServletRequest request) {
String header = request.getHeader("X-Requested-With");
if(header != null && "XMLHttpRequest".equals(header)) {
return true;
}
return false;
}
}
4、action方法
@ExceptionMeta(resultCode = EOperStatus.FAILURE, message = "xxx")
public String post() throws Exception {
。。。
}
其中resultCode表示错误码,message为自定义的错误消息,用于提示给用户。