struts2 异常处理3板斧

板斧1:找不到action的错误

在struts.xml中参考如下配置

 1 <struts>
 2
 3     ...
 4     <package name="default" namespace="/" extends="struts-default">
 5
 6         ...
 7
 8         <default-action-ref name="index" />
 9
10         ...
11
12         <action name="index">
13             <result type="redirectAction">
14                 <param name="actionName">HelloWorld</param>
15                 <param name="namespace">/home</param>
16             </result>
17         </action>
18
19     </package>
20
21     <include file="struts-home.xml" />
22
23 </struts>

View Code

这样,如果输入不存在的.action 路径,会直接重定向到index这个Action上,而index中指定的HelloWorld这个Action,在struts-home.xml中

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3         "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
 4         "http://struts.apache.org/dtds/struts-2.0.dtd">
 5 <struts>
 6
 7     <package name="home" namespace="/home" extends="default">
 8
 9         <action name="HelloWorld_*" method="{1}" class="HelloWorldAction">
10             <result>/WEB-INF/views/home/HelloWorld.jsp</result>
11         </action>
12
13     </package>
14 </struts>

View Code

注:struts.xml中节点出现的顺序,是有严格约定的,如果弄错顺序了,启动时,就会看到类似下面的异常

org.xml.sax.SAXParseException: The content of element type "package" must match

"(result-types?,interceptors?,default-interceptor-ref?,default-action-ref?,default-class-ref?,global-results?,global-exception-mappings?,action*)".

即各节点的顺序为:

result-types -> interceptors -> default-interceptor-ref -> default-action-ref -> default-class-ref -> global-results -> global-exception-mappings -> action

 

板斧2:404/500之类的常规错误

呃,这个struts2处理不了,得靠web.xml搞定

1     <error-page>
2         <error-code>404</error-code>
3         <location>/WEB-INF/common/error/404.jsp</location>
4     </error-page>
5
6     <error-page>
7         <error-code>500</error-code>
8         <location>/WEB-INF/common/error/500.jsp</location>
9     </error-page>

View Code

 

板斧3:业务异常/常规(运行)异常

a) 定义业务异常 (这里简单弄一个土鳖的MyException意思一下)

package com.cnblogs.yjmyzz.exception;

public class MyException extends Exception {

    private static final long serialVersionUID = -8315871537638142775L;

    public MyException() {
        super();
    }

    public MyException(String message) {
        super(message);
    }
}

View Code

b) Action中,直接向外抛异常即可

 1     public String execute() throws Exception, MyException {
 2
 3         //testException();
 4
 5         testMyException();
 6
 7         return SUCCESS;
 8     }
 9
10     /*private void testException() throws Exception {
11         throw new Exception("normal exception");
12     }*/
13
14     private void testMyException() throws MyException {
15         throw new MyException("my exception");
16     }

View Code

c) 定义拦截器,处理异常

struts2中所有action的方法执行会先经常拦截器,所以拦截器是处理异常的好机机(比如:记录异常到日志文件、转换成友好异常信息)

 1 package com.cnblogs.yjmyzz.Interceptor;
 2
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5
 6 import com.cnblogs.yjmyzz.exception.MyException;
 7 import com.opensymphony.xwork2.ActionInvocation;
 8 import com.opensymphony.xwork2.interceptor.*;
 9
10 public class ExceptionInterceptor extends AbstractInterceptor {
11
12     private static final long serialVersionUID = -6827886613872084673L;
13     protected Logger logger = LoggerFactory.getLogger(this.getClass());
14     protected Logger myexLogger = LoggerFactory.getLogger("my-exception");
15
16     @Override
17     public String intercept(ActionInvocation ai) throws Exception {
18         String result = null;
19         try {
20             logger.debug("ExceptionInterceptor.intercept() is called!");
21             result = ai.invoke();
22         } catch (MyException e) {
23             // 捕获自定义异常
24             myexLogger.error(ai.toString(), e);
25             ai.getStack().push(new ExceptionHolder(e));
26             result = "error";
27         } catch (Exception e) {
28             // 其它异常
29             logger.error(ai.toString(), e);
30             ai.getStack().push(new ExceptionHolder(e));
31             result = "error";
32         }
33         return result;
34     }
35
36 }

View Code

解释一下:

ai.getStack().push(new ExceptionHolder(e)); 这一行的用途是将异常信息放入stack,这样后面的异常处理页面,就能显示异常详细信息

上面只是演示,将"业务异常MyException"与"常规异常Exception"分开处理,并且用不同的Logger实例来记录,这样就能将"业务异常"与"常规异常"分别记到不同的log文件中,对应的logback.xml参考配置:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <configuration scan="true" scanPeriod="1800 seconds"
 3     debug="false">
 4
 5     <property name="USER_HOME" value="logs" />
 6     <property scope="context" name="FILE_NAME" value="test-logback" />
 7
 8     <timestamp key="byDay" datePattern="yyyy-MM-dd" />
 9
10     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
11         <encoder>
12             <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
13             </pattern>
14         </encoder>
15     </appender>
16
17     <appender name="file"
18         class="ch.qos.logback.core.rolling.RollingFileAppender">
19         <file>${USER_HOME}/${FILE_NAME}.log</file>
20
21         <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
22             <fileNamePattern>${USER_HOME}/${byDay}/${FILE_NAME}-${byDay}-%i.log.zip
23             </fileNamePattern>
24             <minIndex>1</minIndex>
25             <maxIndex>10</maxIndex>
26         </rollingPolicy>
27
28         <triggeringPolicy
29             class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
30             <maxFileSize>5MB</maxFileSize>
31         </triggeringPolicy>
32         <encoder>
33             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level
34                 %logger{150} - %msg%n
35             </pattern>
36         </encoder>
37     </appender>
38
39
40     <appender name="exception-file"
41         class="ch.qos.logback.core.rolling.RollingFileAppender">
42         <file>${USER_HOME}/${FILE_NAME}_myexception.log</file>
43
44         <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
45             <fileNamePattern>${USER_HOME}/${byDay}/${FILE_NAME}-${byDay}-%i.log.zip
46             </fileNamePattern>
47             <minIndex>1</minIndex>
48             <maxIndex>10</maxIndex>
49         </rollingPolicy>
50
51         <triggeringPolicy
52             class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
53             <maxFileSize>5MB</maxFileSize>
54         </triggeringPolicy>
55         <encoder>
56             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level
57                 %logger{150} - %msg%n
58             </pattern>
59         </encoder>
60     </appender>
61
62     <logger name="com.cnblogs.yjmyzz" level="error" additivity="true">
63         <appender-ref ref="file" />
64     </logger>
65
66     <logger name="my-exception" level="error" additivity="true">
67         <appender-ref ref="exception-file" />
68     </logger>
69
70     <root level="error">
71         <appender-ref ref="STDOUT" />
72     </root>
73 </configuration>

View Code

运行后,会生成二个日志文件,类似下图:(业务日志记录在test-logback_myexception.log中,常规运行异常记录在test-logback.log中)

tips:如果还有更多的异常类型要处理(比如:SQL异常、Spring异常、网络连接异常等,参考上面的处理)。另:如果把3.b)中Action方法里的testMyException()注释掉,换成testException(),即抛出普通异常,则异常信息将记录到test-logback.log中

d) struts中拦截器配置,以及全局异常处理页面

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5
 6 <struts>
 7
 8     <constant name="struts.enable.DynamicMethodInvocation" value="false" />
 9     <constant name="struts.devMode" value="true" />
10
11     <package name="default" namespace="/" extends="struts-default">
12
13         <interceptors>
14             <interceptor name="myinterceptor"
15                 class="com.cnblogs.yjmyzz.Interceptor.ExceptionInterceptor">
16             </interceptor>
17
18             <interceptor-stack name="myStack">
19                 <interceptor-ref name="myinterceptor" />
20             </interceptor-stack>
21         </interceptors>
22
23         <default-interceptor-ref name="myStack" />
24         <default-action-ref name="index" />
25
26         <global-results>
27             <result name="error">/WEB-INF/common/error.jsp</result>
28         </global-results>
29
30         <global-exception-mappings>
31             <exception-mapping exception="java.lang.Exception"
32                 result="error" />
33         </global-exception-mappings>
34
35         <action name="index">
36             <result type="redirectAction">
37                 <param name="actionName">HelloWorld</param>
38                 <param name="namespace">/home</param>
39             </result>
40         </action>
41
42     </package>
43
44     <include file="struts-home.xml" />
45     <include file="struts-mytatis.xml" />
46
47 </struts>

View Code

解释一下:
13-21行,注册了自定义的拦截器,如果有更多的拦截器,19行后继续加即可。
23行,指定了默认的拦截器栈
26-28行,指定了全局的error返回页面
30-33行,指定了处理的异常类型

e) 通用error.jsp 代码 

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <%@ taglib prefix="s" uri="/struts-tags" %>
 3
 4 <html>
 5 <head><title>Simple jsp page</title></head>
 6 <body>
 7     <h3>Exception:</h3>
 8     <s:property value="exception"/>
 9
10     <h3>Stack trace:</h3>
11     <pre>
12         <s:property value="exceptionStack"/>
13     </pre>
14 </body>
15 </html>

View Code

这样运行时,就会显示给用户一个很"低俗但通用"的错误页面:

显然,直接把底层异常展示给用户是不好的做法(相当于直接告诉别人,今天你底裤的颜色),可以稍微装一下笔,只要改下拦截器:

 1 package com.cnblogs.yjmyzz.Interceptor;
 2
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5
 6 import com.cnblogs.yjmyzz.exception.MyException;
 7 import com.opensymphony.xwork2.ActionInvocation;
 8 import com.opensymphony.xwork2.interceptor.*;
 9
10 public class ExceptionInterceptor extends AbstractInterceptor {
11
12     private static final long serialVersionUID = -6827886613872084673L;
13     protected Logger logger = LoggerFactory.getLogger(this.getClass());
14     protected Logger myexLogger = LoggerFactory.getLogger("my-exception");
15
16     @Override
17     public String intercept(ActionInvocation ai) throws Exception {
18         String result = null;
19         try {
20             logger.debug("ExceptionInterceptor.intercept() is called!");
21             result = ai.invoke();
22         } catch (MyException e) {
23             // 捕获自定义异常
24             myexLogger.error(ai.toString(), e);
25             // 转换成友好异常,并放入stack中
26             ai.getStack().push(
27                     new ExceptionHolder(new Exception("业务繁忙,让我喘口气先!")));
28             result = "error";
29         } catch (Exception e) {
30             // 其它异常
31             logger.error(ai.toString(), e);
32             // 转换成友好异常,并放入stack中
33             ai.getStack().push(
34                     new ExceptionHolder(new Exception("系统太累了,需要休息一下!")));
35             result = "error";
36         }
37         return result;
38     }
39
40 }

View Code

这样,用户看到的信息就变了(当然,实际应用中,下面这个页面,建议请艺术大师美化一下)

当然,也可以改变拦截器的返回string,比如业务错误,返回"biz-error",定位到业务错误的专用展示页面,常规错误返回"sys-error",返回 另一个专用错误处理页面(对应的struts.xml的全局错误配置也要相应修改)

 

小结:

经过以上处理,常见的异常(错误),比如:404/500、action路径不对、运行异常、业务异常等,即分门别类记录了详细日志(便于日后分析),也转换为友好信息提示给用户,同时还保证了系统健壮性。最后,对于程序员更重要的是,不用手动写try/catch之类的代码了,干活更轻松 (妈妈再也不担心我的异常了)

 

附:ajax的统一异常处理,请移步 Struts2、Spring MVC4 框架下的ajax统一异常处理

时间: 2024-12-02 12:15:26

struts2 异常处理3板斧的相关文章

16.如何自学Struts2之Struts2异常处理[视频]

16.如何自学Struts2之Struts2异常处理[视频]   之前写了一篇"打算做一个视频教程探讨如何自学计算机相关的技术",优酷上传不了,只好传到百度云上:   http://pan.baidu.com/s/1kTDsa95 有问题可以直接回复这篇文章.

Struts2异常处理机制

任何成熟的MVC框架都应该提供成就的异常处理机制,Strut2也不例外.Struts2提供了一种声明式的异常处理方式,Struts2也是通过配置的拦截器来实现异常处理机制的. 一.  异常处理机制1. 配置 Struts2的异常处理机制是:通过在struts.xml文件中配置﹤exception-mapping -﹥元素完成的,配置该元素时,需要指定两个属性: exception:此属性指定该异常映射所设置的异常类型. result:此属性指定Action出现该异常时,系统转入result属性所

struts2 异常处理 404错误

struts.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"     "http://struts.apache.org/dtds/struts-2.0.dtd"> <st

Struts2异常处理的使用例子

最通俗的做法 比如,现在让你来为Struts2框架设计一个异常处理机制,你会怎么设计?大多数人会这样来实现:  代码如下 复制代码 public class LoginAction {     public String execute()     {         try         {             ...         }         catch (异常1 e)         {             return 结果1         }         ca

Struts2 异常处理页面 exceptionStack的值取不到

问题描述 如题Struts2搭建的框架,在Windows上进行开发,采用异常统一处理,出异常后返回到一个error.jsp页面用<s:propertyvalue="exceptionStack"/>显示异常信息开发测试时都是好用的,就是说代码是没有错误的但是系统移植到Linux后,就取不到exceptionStack的值了请问有大神遇到过类似情况么,求助~ 解决方案 解决方案二:先看看全部的代码吧解决方案三:引用1楼ciazzp_java的回复: 先看看全部的代码吧 我的工

Struts2、Spring MVC4 框架下的ajax统一异常处理

本文算是struts2 异常处理3板斧.spring mvc4:异常处理 后续篇章,普通页面出错后可以跳到统一的错误处理页面,但是ajax就不行了,ajax的本意就是不让当前页面发生跳转,仅局部刷新,从而改善用户体验,基本思路是:把异常转换成json数据返回,这样ajax的回调函数,就能解析出错误原因.   一.如何区分ajax请求与普通请求 打开firefox的调试工具观察一下: 普通的页面请求 jquery发起的ajax请求 对比一下,可以发现jquery发生的ajax请求,Request

struts2.0-在struts2中用什么替代&amp;amp;lt;logic:notPresent&amp;amp;gt;

问题描述 在struts2中用什么替代<logic:notPresent> <logic:notPresent name="class${classSingle.classId}"><li>aaaaaaa</li></logic:notPresent> 在struts2中用什么替代,主要是name="class${classSingle.classId}"这个怎么替换?求解?? 解决方案 logic:not

spring mvc4:异常处理

前面学习过struts2的异常处理,今天来看下spring mvc4的异常处理: 一.Servlet配置文件修改 1 <bean id="exceptionResolver" 2 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 3 <property name="defaultErrorView" value=&quo

【JAVA秒会技术之秒杀面试官】JavaEE常见面试题(一)

[前言]别人都在你看不到的地方暗自努力,在你看得到的地方,他们也和你一样显得游手好闲,和你一样会抱怨,而只有你自己相信这些都是真的,最后,也只有你一个人继续不思进取 --   [下载]个人结合诸多资料,总结的一些JavaEE常见面试题,主要针对初/中级程序员.想要word完整版下载的,评论里留言留下你的邮箱! 1.Struts2中,Action通过什么方式获取用户从页面输入的数据,又是通过什么方法把数据传给视图层显示的? 答:(1)Action从页面获取数据的方式有三种: