Struts2自定义拦截器处理全局异常
今天在整理之前的项目的时候想着有的action层没有做异常处理,于是想着自定义拦截器处理一下未拦截的异常。
代码:
package cn.xm.exam.action.safeHat; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionSupport; @Controller @Scope("prototype") public class SafeHatAction extends ActionSupport { private static final Logger log = LoggerFactory.getLogger(SafeHatAction.class); private Map<String, Object> response; public SafeHatAction() { log.info("SafeHatAction init........."); } public String test1() { response = new HashMap(); response.put("ttt", "tttttt"); return SUCCESS; } public String test2() { response = new HashMap(); response.put("ttt", "tttttt"); int i = 1/0; return SUCCESS; } public Map<String, Object> getResponse() { return response; } public void setResponse(Map<String, Object> response) { this.response = response; } }
1.异常在Action层未做处理的情况:
由于在web.xml中定义了500错误的页面,因此跳转到500页面,如下:
<!-- 500页面 --> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page>
可是上面终究不够友好。
2.自定义拦截器处理全局异常
(1)自定义拦截器
package cn.xm.exam.interceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class ExceptionInterception implements Interceptor { private static final Logger log = LoggerFactory.getLogger(ExceptionInterception.class); /** * */ private static final long serialVersionUID = 2268867259828199826L; @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation arg0) throws Exception { log.info("enter ExceptionInterception intercept ... "); String result = ""; try { result = arg0.invoke(); log.info("result -> {}", result); } catch (Throwable e) { log.error("未处理的异常在拦截器被拦截,class:{}", arg0.getAction().getClass(), e); throw new Exception(e); } log.debug("exit ExceptionInterception intercept ... "); return result; } }
arg0.invoke();是调用我们的action的方法,其返回值就是action的返回值,相当于放行;捕捉到异常之后进行一个简单的异常记录之后再次抛出异常,再次抛出异常是为了跳到500页面;如果有需要可以自己再写一个页面提示错误已经被记录等信息,捕捉到异常之后返回到此页面。
(2)struts.xml中定义拦截器
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.i18n.encoding" value="utf-8"></constant> <constant name="devMode" value="true"></constant> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <!-- 配置拦截的后缀 --> <constant name="struts.action.extension" value="action,do" /> <!-- 与spring整合 --> <constant name="struts.objectFactory" value="spring"></constant> <package name="interceptPackage" extends="json-default"> <!-- 拦截器 --> <interceptors> <!-- 定义刚才的拦截器 --> <interceptor name="exceptionInterceptor" class="cn.xm.exam.interceptor.ExceptionInterception"></interceptor> <!-- 定义拦截器栈 --> <interceptor-stack name="myStack"> <!-- 拦截器栈里面可以引用另外一个拦截器,也可以引用另外一个拦截器栈 --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="exceptionInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 这句是设置所有Action自动调用的拦截器堆栈 --> <default-interceptor-ref name="myStack" /> </package> <!-- 2018-11-11引入的二开action --> <include file="struts/safeHat.xml"></include> </struts>
自定义的package继承上面的package(package具有多重继承的特性,safeHalt会继承其所有父类),例如:safeHat.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="safeHalt" namespace="/" extends="interceptPackage"> <!-- 全局结果集,将response转换为json传到前台 --> <global-results> <result name="success" type="json"> <param name="root">response</param> </result> </global-results> <action name="safeHat_*" class="safeHatAction" method="{1}"></action> </package> </struts>
(3)继续访问上面的错误action进行测试:
查看记录的错误日志:
2018-11-01 23:09:30 [cn.xm.exam.interceptor.ExceptionInterception]-[ERROR] 未处理的异常在拦截器被拦截,class:class cn.xm.exam.action.safeHat.SafeHatAction
java.lang.ArithmeticException: / by zero
at cn.xm.exam.action.safeHat.SafeHatAction.test2(SafeHatAction.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:871)
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294)
at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117)
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108)
at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
........
至此实现了简单的全局异常处理。
3.补充:根据ajax请求与普通请求回传不同数据 (捕捉到异常之后进行提示)
3.1首先明白ajax请求与普通请求的不同:
AJAX请求头会多一个x-requested-with参数,值为XMLHttpRequest
String requestType = request.getHeader("X-Requested-With");
3.2修改上面的拦截器
package cn.xm.exam.interceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class ExceptionInterception implements Interceptor { private static final Logger log = LoggerFactory.getLogger(ExceptionInterception.class); /** * */ private static final long serialVersionUID = 2268867259828199826L; @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation arg0) throws Exception { log.info("enter ExceptionInterception intercept ... "); String result = ""; try { result = arg0.invoke(); log.info("result -> {}", result); } catch (Throwable e) { log.error("未处理的异常在拦截器被拦截,class:{}", arg0.getAction().getClass(), e); return "interceptorError"; } log.debug("exit ExceptionInterception intercept ... "); return result; } }
struts全局结果集:
<package name="interceptPackage" extends="json-default"> <!-- 拦截器 --> <interceptors> <!-- 定义刚才的拦截器 --> <interceptor name="exceptionInterceptor" class="cn.xm.exam.interceptor.ExceptionInterception"></interceptor> <!-- 定义拦截器栈 --> <interceptor-stack name="myStack"> <!-- 拦截器栈里面可以引用另外一个拦截器,也可以引用另外一个拦截器栈 --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="exceptionInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 这句是设置所有Action自动调用的拦截器堆栈 --> <default-interceptor-ref name="myStack" /> <!-- 拦截器拦截的全局异常 --> <global-results> <result name="interceptorError">/interceptorError.jsp</result> </global-results> </package>
错误JSP:interceptorError.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% if (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) { response.setContentType("application/javascript;charset=utf-8"); out.write("错误提醒:系统发生错误,系统已经记录错误日志"); } else { response.setContentType("text/html;charset=\"utf-8\""); out.write( "<html><head><meta charset=\"utf-8\" /><title>错误提醒</title></head><body><br /><span style=\"font-weight: bold;font-size: 20px;margin: 20px;\">系统发生错误!日志已经记录!</span> <br /></body></html>"); } %>
测试:
(1)普通页面访问:
(2)ajax请求测试:
js代码:
<script> +function(){ $.post("/Exam/safeHat_test2.do",function(response){ alert(response); },"text"); }(); </script>
结果:
拦截器的使用参考我另一篇博客:https://www.cnblogs.com/qlqwjy/p/7190784.html
【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】