板斧1:找不到action的错误

在struts.xml中参考如下配置

 <struts>

     ...
<package name="default" namespace="/" extends="struts-default"> ... <default-action-ref name="index" /> ... <action name="index">
<result type="redirectAction">
<param name="actionName">HelloWorld</param>
<param name="namespace">/home</param>
</result>
</action> </package> <include file="struts-home.xml" /> </struts>

这样,如果输入不存在的.action 路径,会直接重定向到index这个Action上,而index中指定的HelloWorld这个Action,在struts-home.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">
<struts> <package name="home" namespace="/home" extends="default"> <action name="HelloWorld_*" method="{1}" class="HelloWorldAction">
<result>/WEB-INF/views/home/HelloWorld.jsp</result>
</action> </package>
</struts>

注: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搞定

     <error-page>
<error-code>404</error-code>
<location>/WEB-INF/common/error/404.jsp</location>
</error-page> <error-page>
<error-code>500</error-code>
<location>/WEB-INF/common/error/500.jsp</location>
</error-page>

板斧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);
}
}

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

     public String execute() throws Exception, MyException {

         //testException();

         testMyException();

         return SUCCESS;
} /*private void testException() throws Exception {
throw new Exception("normal exception");
}*/ private void testMyException() throws MyException {
throw new MyException("my exception");
}

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

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

 package com.cnblogs.yjmyzz.Interceptor;

 import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.cnblogs.yjmyzz.exception.MyException;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.*; public class ExceptionInterceptor extends AbstractInterceptor { private static final long serialVersionUID = -6827886613872084673L;
protected Logger logger = LoggerFactory.getLogger(this.getClass());
protected Logger myexLogger = LoggerFactory.getLogger("my-exception"); @Override
public String intercept(ActionInvocation ai) throws Exception {
String result = null;
try {
logger.debug("ExceptionInterceptor.intercept() is called!");
result = ai.invoke();
} catch (MyException e) {
// 捕获自定义异常
myexLogger.error(ai.toString(), e);
ai.getStack().push(new ExceptionHolder(e));
result = "error";
} catch (Exception e) {
// 其它异常
logger.error(ai.toString(), e);
ai.getStack().push(new ExceptionHolder(e));
result = "error";
}
return result;
} }

解释一下:

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

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

 <?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="1800 seconds"
debug="false"> <property name="USER_HOME" value="logs" />
<property scope="context" name="FILE_NAME" value="test-logback" /> <timestamp key="byDay" datePattern="yyyy-MM-dd" /> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender> <appender name="file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${USER_HOME}/${FILE_NAME}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${USER_HOME}/${byDay}/${FILE_NAME}-${byDay}-%i.log.zip
</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy> <triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level
%logger{150} - %msg%n
</pattern>
</encoder>
</appender> <appender name="exception-file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${USER_HOME}/${FILE_NAME}_myexception.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${USER_HOME}/${byDay}/${FILE_NAME}-${byDay}-%i.log.zip
</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy> <triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level
%logger{150} - %msg%n
</pattern>
</encoder>
</appender> <logger name="com.cnblogs.yjmyzz" level="error" additivity="true">
<appender-ref ref="file" />
</logger> <logger name="my-exception" level="error" additivity="true">
<appender-ref ref="exception-file" />
</logger> <root level="error">
<appender-ref ref="STDOUT" />
</root>
</configuration>

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

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

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

 <?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.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <interceptors>
<interceptor name="myinterceptor"
class="com.cnblogs.yjmyzz.Interceptor.ExceptionInterceptor">
</interceptor> <interceptor-stack name="myStack">
<interceptor-ref name="myinterceptor" />
</interceptor-stack>
</interceptors> <default-interceptor-ref name="myStack" />
<default-action-ref name="index" /> <global-results>
<result name="error">/WEB-INF/common/error.jsp</result>
</global-results> <global-exception-mappings>
<exception-mapping exception="java.lang.Exception"
result="error" />
</global-exception-mappings> <action name="index">
<result type="redirectAction">
<param name="actionName">HelloWorld</param>
<param name="namespace">/home</param>
</result>
</action> </package> <include file="struts-home.xml" />
<include file="struts-mytatis.xml" /> </struts>

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

e) 通用error.jsp 代码

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %> <html>
<head><title>Simple jsp page</title></head>
<body>
<h3>Exception:</h3>
<s:property value="exception"/> <h3>Stack trace:</h3>
<pre>
<s:property value="exceptionStack"/>
</pre>
</body>
</html>

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

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

 package com.cnblogs.yjmyzz.Interceptor;

 import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.cnblogs.yjmyzz.exception.MyException;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.*; public class ExceptionInterceptor extends AbstractInterceptor { private static final long serialVersionUID = -6827886613872084673L;
protected Logger logger = LoggerFactory.getLogger(this.getClass());
protected Logger myexLogger = LoggerFactory.getLogger("my-exception"); @Override
public String intercept(ActionInvocation ai) throws Exception {
String result = null;
try {
logger.debug("ExceptionInterceptor.intercept() is called!");
result = ai.invoke();
} catch (MyException e) {
// 捕获自定义异常
myexLogger.error(ai.toString(), e);
// 转换成友好异常,并放入stack中
ai.getStack().push(
new ExceptionHolder(new Exception("业务繁忙,让我喘口气先!")));
result = "error";
} catch (Exception e) {
// 其它异常
logger.error(ai.toString(), e);
// 转换成友好异常,并放入stack中
ai.getStack().push(
new ExceptionHolder(new Exception("系统太累了,需要休息一下!")));
result = "error";
}
return result;
} }

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

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

小结:

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

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

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

  1. 16.怎样自学Struts2之Struts2异常处理[视频]

    16.怎样自学Struts2之Struts2异常处理[视频] 之前写了一篇"打算做一个视频教程探讨怎样自学计算机相关的技术",优酷上传不了,仅仅好传到百度云上: http://pa ...

  2. struts2异常处理及类型转换

    一.struts2对异常的处理 1.自定义局部异常: <action> <exception-mapping result="sonException" exce ...

  3. struts2异常处理机制

    一.处理一般异常(javaBean异常) struts2进行异常处理首先需要添加exception拦截器,而默认拦截器栈已经加入了这个拦截器,所以不用特意的声明.在Struts 2框架中,采用声明式异 ...

  4. Struts2 异常处理

    Struts提供了一个更简单的方式来处理未捕获的异常,并将用户重定向到一个专门的错误页面.您可以轻松地Struts配置到不同的异常有不同的错误页面. Struts的异常处理所使用的“exception ...

  5. Struts2 - 异常处理: exception-mapping 元素

    异常处理: exception-mapping 元素 在action方法中添加 int i=1/0; 请求action后,结果为: 在struts.xml中添加异常处理:exception-mappi ...

  6. struts2异常处理,global-results定义全局结果处理

    <global-results>定义全局结果处理 一般发生异常之后 结果返回errHandler 因为errHandler是由<global-exception-mappings&g ...

  7. Struts2异常处理配置

    <package name="lee" extends="struts-default"> <!--定义全局结构映射 --> <g ...

  8. struts2异常处理

    <global-results> <result name="nullException">/WEB-INF/exception/nullException ...

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

    本文算是struts2 异常处理3板斧.spring mvc4:异常处理 后续篇章,普通页面出错后可以跳到统一的错误处理页面,但是ajax就不行了,ajax的本意就是不让当前页面发生跳转,仅局部刷新, ...

随机推荐

  1. 17、文案人员 - IT软件人员书籍系列文章

    这里说的文案人员是软件项目中的一个角色.其主要负责相关文档的整理,用户使用说明书的编写等等,在项目中是一个辅助的角色. 文案人员所做的事情不错,但是她能够辅助软件配置管理工程师进行工作,更好的为维护文 ...

  2. SQLServer复合查询条件(AND,OR,NOT)对NULL值的处理方法

    在SQL的3值逻辑下,一个查询条件可以产生以下三种情况:TRUE,FALSE,NULL.只有那些满足WHERE子句的值是TRUE的记录才出现在结果表中. NULL值影响查询条件的结果,并且结果很微妙. ...

  3. java:comp/env/jdbc/ 的两种配置方法

    1. 在 META-INF 下建立文件: context.xml <?xml version="1.0" encoding="UTF-8"?> &l ...

  4. 使用数据库sqlite3 C语言实现登陆注册的功能

    //此代码为注册功能 void create_regtable() { int rc; //rc为返回值,判断函数是否执行成功 rc=0函数执行成功,rc !=0函数执行失败 sqlite3 *db; ...

  5. Linux shell if [ -n ] 正确使用方法

    if [ str1 = str2 ]  当两个串有相同内容.长度时为真 if [ str1 != str2 ] 当串str1和str2不等时为真 if [ -n str1 ] 当串的长度大于0时为真( ...

  6. java报表工具FineReport的JS编辑框和URL地址栏语法简介

    JS编辑框: 1.FineReport的js. 作为一款BS产品,browser端的JavaScript是必不可少的. FineReport中的js是已经调用了finereport.js的. 大家知道 ...

  7. MMORGP大型游戏设计与开发(客户端架构 part13 of vegine)

    一些数据是需要不断改动的,程序不可能因为这些改动而不厌其烦的去改动代码,早期的这种做法就成了程序员们最悲哀的痛苦.自从有了数据管理后,程序的世界逐渐清晰,这些烦恼也不再出现,不过若是要很好的管理数据可 ...

  8. ural Infernal Work

    Infernal Work Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Descr ...

  9. ural 1208 Legendary Teams Contest

    题意描述:给定K支队伍,每队三个队员,不同队伍之间队员可能部分重复,输出这些队员同时能够组成多少完整的队伍: DFS,利用DFS深度优先搜索,如果该队所有队员都没有被访问过,那么将该队计入结果,再去选 ...

  10. VIM的强大功能

    转发地址:http://coolshell.cn/articles/5426.html 简明 Vim 练级攻略   vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是 ...