Struts2拦截器是Struts2中的一个很重要的功能。本文将从概念开始,为大家讲解Struts2拦截器的实现原理以及如何定义等等内容
一、理解Struts2拦截器
1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现.
2. 拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
struts.xml
<interceptor-stack name="portalMSInterceptorStack">
<interceptor-ref name="logInterceptor" />
<interceptor-ref name="fileUploadStack" />
<interceptor-ref name="json" />
<interceptor-ref name="i18n" />
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="ExTokenInterceptor" />
<interceptor-ref name="siteInterceptor" />
</interceptor-stack>
</interceptors>
<!-- 覆盖默认的拦截栈 -->
<default-interceptor-ref name="portalMSInterceptorStack" />
二、实现Struts2拦截器原理
Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的 拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器
三、定义Struts2拦截器。
Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。该接口声明了3个方法,
|
其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。
intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑。
不过,struts中又提供了几个抽象类来简化这一步骤。
public abstract class AbstractInterceptor implements Interceptor; public abstract class MethodFilterInterceptor extends AbstractInterceptor; |
都是模板方法实现的。
其中AbstractInterceptor提供了init()和destroy()的空实现,使用时只需要覆盖intercept()方法;
而MethodFilterInterceptor则提供了includeMethods和excludeMethods两个属性,用来过滤执行该过滤器的action的方法。可以通过param来加入或者排除需要过滤的方法。
一般来说,拦截器的写法都差不多。看下面的示例:
package interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class MyInterceptor implements Interceptor { public void destroy() { // TODO Auto-generated method stub } public void init() { // TODO Auto-generated method stub } public String intercept(ActionInvocation invocation) throws Exception { System.out.println("Action执行前插入 代码"); //执行目标方法 (调用下一个拦截器, 或执行Action) final String res = invocation.invoke(); System.out.println("Action执行后插入 代码"); return res; } } |
四、配置Struts2拦截器
Struts2拦截器需要在struts.xml中声明,如下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"> <struts> <constant name="struts.objectFactory" value="spring" /> |
拦截器 | 名字 | 说明 |
Alias Interceptor | alias | 在不同请求之间将请求参数在不同名字件转换,请求内容不变 |
Chaining Interceptor | chain | 让前一个Action的属性可以被后一个Action访问,现在和chain类型的result()结合使用。 |
Checkbox Interceptor | checkbox | 添加了checkbox自动处理代码,将没有选中的checkbox的内容设定为false,而html默认情况下不提交没有选中的checkbox。 |
Cookies Interceptor | cookies | 使用配置的name,value来是指cookies |
Conversion Error Interceptor | conversionError | 将错误从ActionContext中添加到Action的属性字段中。 |
Create Session Interceptor | createSession | 自动的创建HttpSession,用来为需要使用到HttpSession的拦截器服务。 |
Debugging Interceptor | debugging | 提供不同的调试用的页面来展现内部的数据状况。 |
Execute and Wait Interceptor | execAndWait | 在后台执行Action,同时将用户带到一个中间的等待页面。 |
Exception Interceptor | exception | 将异常定位到一个画面 |
File Upload Interceptor | fileUpload | 提供文件上传功能 |
I18n Interceptor | i18n | 记录用户选择的locale |
Logger Interceptor | logger | 输出Action的名字 |
Message Store Interceptor | store | 存储或者访问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。 |
Model Driven Interceptor | model-driven | 如果一个类实现了ModelDriven,将getModel得到的结果放在Value Stack中。 |
Scoped Model Driven | scoped-model-driven | 如果一个Action实现了ScopedModelDriven,则这个拦截器会从相应的Scope中取出model调用Action的setModel方法将其放入Action内部。 |
Parameters Interceptor | params | 将请求中的参数设置到Action中去。 |
Prepare Interceptor | prepare | 如果Acton实现了Preparable,则该拦截器调用Action类的prepare方法。 |
Scope Interceptor | scope | 将Action状态存入session和application的简单方法。 |
Servlet Config Interceptor | servletConfig | 提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方式访问。 |
Static Parameters Interceptor | staticParams | 从struts.xml文件中将中的中的内容设置到对应的Action中。 |
Roles Interceptor | roles | 确定用户是否具有JAAS指定的Role,否则不予执行。 |
Timer Interceptor | timer | 输出Action执行的时间 |
Token Interceptor | token | 通过Token来避免双击 |
Token Session Interceptor | tokenSession | 和Token Interceptor一样,不过双击的时候把请求的数据存储在Session中 |
Validation Interceptor | validation | 使用action-validation.xml文件中定义的内容校验提交的数据。 |
Workflow Interceptor | workflow | 调用Action的validate方法,一旦有错误返回,重新定位到INPUT画面 |
Parameter Filter Interceptor | N/A | 从参数列表中删除不必要的参数 |
Profiling Interceptor | profiling | 通过参数激活profile |
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">
<struts>
<!-- 后缀*.action(默认值为action) -->
<constant name="struts.action.extension" value="do,action" />
<constant name="struts.devMode" value="true" />
<constant name="struts.objectFactory" value="spring" />
<constant name="struts.multipart.maxSize" value="1048576000" />
<constant name="struts.locale" value="${localLanguage}" />
<!-- 配置Struts标签访问静态方法 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
<constant name="struts.custom.i18n.resources"
value="
ApplicationResources,
ApplicationResources_WebManage,
ApplicationResources_Publish,
ApplicationResources_ResourceManage,
ApplicationResources_Template,
ApplicationResources_Category,
ApplicationResources_SiteManage,
ApplicationResources_CommonJS
" />
<include file="struts-default.xml" />
<include file="struts-plugin.xml" />
<package name="defaults" extends="struts-default">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult"
default="false" />
</result-types>
<interceptors>
<!-- 日志拦截器 -->
<interceptor name="logInterceptor"
class="com.xxxxxx.dhm.portalMS.base.web.interceptor.LogInterceptor">
<param name="includeParams">查询,查找</param>
<param name="excludeClass">com.xxxxxx.sdp.rights.view.action.*</param>
</interceptor>
<!-- 站点信息拦截器(设置siteID) -->
<interceptor name="siteInterceptor"
class="com.xxxxxx.dhm.portalMS.base.web.interceptor.SiteInterceptor"></interceptor>
<interceptor name="json"
class="org.apache.struts2.json.JSONInterceptor" />
<!-- 防止重复提交拦截器 -->
<interceptor name="ExTokenInterceptor"
class="com.xxxxxx.dhm.portalMS.base.web.interceptor.ExTokenInterceptor" />
<!-- 自定义拦截栈 -->
<interceptor-stack name="portalMSInterceptorStack">
<interceptor-ref name="logInterceptor" />
<interceptor-ref name="fileUploadStack" />
<interceptor-ref name="json" />
<interceptor-ref name="i18n" />
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="ExTokenInterceptor" />
<interceptor-ref name="siteInterceptor" />
</interceptor-stack>
</interceptors>
<!-- 覆盖默认的拦截栈 -->
<default-interceptor-ref name="portalMSInterceptorStack" />
<!-- 全局错误页面配置 -->
<global-results>
<result name="error">/common/error.jsp</result>
<result name="global.error">/common/error.jsp</result>
<result name="global.error.window">/common/error_window.jsp</result>
</global-results>
</package>
<!-- 鉴权产品管理 -->
<include file="struts/authProduct.xml" />
<!-- 业务映射管理 -->
<include file="struts/business.xml" />
<!-- 系统管理 -->
<include file="struts/sysmanage.xml" />
<!--资源管理 -->
<include file="struts/resource.xml" />
<!--产品管理 -->
<include file="struts/product.xml" />
<!--站点管理 -->
<include file="struts/webmanage.xml" />
<!-- 网站资源管理-->
<include file="struts/noderesource.xml" />
<!-- 发布管理-->
<include file="struts/publishmanage.xml" />
<!-- 站点管理 -->
</struts>
/*
* 工程名: portalMS
* 包 名: com.xxx.dhm.portalMS.base.web.interceptor
* 文 件名: LogInterceptor.java
* 版 权: Copyright (c) 2009 Coship All Rights Reserved.
* 描 述: 日志拦截器,记录系统中所有Action的执行情况。
* 修 改 人:
* 修改时间:
* 跟踪单号:
* 修改单号:
* 修改内容:
*/
package com.xxxx.dhm.portalMS.base.web.interceptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import com.xxxx.ChineseCharacter;
import com.xxxx.dhm.common.config.impl.PropertiesFactory;
import com.xxxx.dhm.common.log.level.DHMLogLevel;
import com.xxxx.dhm.portalMS.base.dao.IBaseDAO;
import com.xxxx.dhm.portalMS.base.service.IService;
import com.xxxx.dhm.portalMS.base.web.action.BaseAction;
import com.xxxx.dhm.portalMS.common.Constants;
import com.xxxx.dhm.portalMS.common.SerConstants;
import com.xxxx.dhm.portalMS.common.util.RequestUtil;
import com.xxxx.dhm.portalMS.exception.PortalMSException;
import com.xxxx.sdp.rights.model.domain.Admin;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.LocaleProvider;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.TextProviderFactory;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
*
* 日志拦截器,可以拦截IEPG后台管理系统的所有struts的Action动作。该拦截器具备以下功能: 1、打印Action执行前、后的日志。
* 2、针对一些必须记录操作的Action,如(新增操作),根据操作码将操作信息写入数据库日志。如果 操作出现异常,那么将操作信息写入数据库日志和系统日志。
*
* @author liqi
* @version [V200R001, 2009-11-23]
* @since [DHM.Core.portalMS-V200R001]
*/
public class LogInterceptor extends AbstractInterceptor implements LocaleProvider
{
private static final long serialVersionUID = 8317600420657773448L;
/** IEPG系统日志 */
private static final Logger sysLogger = Logger.getLogger(LogInterceptor.class);
/** IEPG数据库日志 */
private static final Logger dbLogger = Logger.getLogger(LogInterceptor.class);
/** 操作码 */
private String logMessageId;
/**
* 排除不进行日志记录的class类,多个以分号隔开,支持正则表达式
*/
private String excludeClass;
private String[] excludeClassStr = {};
/** 错误码 */
private int errorCode;
/** 操作描述 */
private String operateDesc = "";
/** 操作结果 */
private boolean operateResult = true;
/** 获取错误代码的资源文件 */
TextProvider errorCodeProvider = null;
/** 获取操作码的资源文件 */
TextProvider operateCodePrivider = null;
/** IEPG后台Action基类 */
private BaseAction baseAction = null;
/** 传入拦截器的参数 */
private String includeParams = null;
/** 封装查询动作数组 */
private String[] filterActions = null;
/**
* 应用启动的时候,初始化拦截器
*/
public void init()
{
errorCodeProvider = new TextProviderFactory().createInstance(ResourceBundle.getBundle("ErrorCodeResources",
Locale.getDefault()), this);
operateCodePrivider = new TextProviderFactory().createInstance(ResourceBundle.getBundle("LogDefinitions",
Locale.getDefault()), this);
if (this.includeParams != null && this.includeParams.length() != 0)
{
String[] temp = this.includeParams.split(SerConstants.COMMA);
if (temp != null && temp.length != 0)
{
this.filterActions = temp;
}
}
// 判断是否存在不需要拦截的类
if (excludeClass != null && excludeClass.trim().length() > 0)
{
excludeClassStr = excludeClass.split(SerConstants.SEMICOLON);
}
}
/**
* 拦截器对Action进行拦截。
*
* 1、从Session中获取用户的登录对象,如果登录对象为空,直接执行拦截器后,返回登录页面。
* 2、从登录对象中获取用户ID,以及获取HTTP请求的IP地址,在执行拦截器。 3、获取操作描述、操作码。
* 4、如果Action执行异常,那么在异常处理中将执行信息写入系统日志、数据库日志。 5、如果Action执行成功,那么将执行信息写入数据库日志。
*
* @param invoke
* Action执行的状态
* @return 返回 String代表Action执行的执行结果
* @throws Exception
* 抛出拦截器执行的异常对象,由容器来捕获。
*
* @return String 返回 String代表Action执行的执行结果
* @exception throws Exception 抛出拦截器执行的异常对象
*/
@Override
public String intercept(ActionInvocation invoke) throws Exception
{
HttpServletRequest request = ServletActionContext.getRequest();
Map<String, Object> session = ServletActionContext.getContext().getSession();
Object obj = session.get(Constants.LOGIN_USER.getStringValue());
Admin userInfo = null;
String result = null;
String ipAddr = RequestUtil.getInstance().getIPAddress(request);
if (obj == null)
{
try
{
return invoke.invoke();
}
catch (Exception e)
{
String message = handleException(0, ipAddr, invoke, e);
request.setAttribute(Constants.ERROR_MESSAGE.getStringValue(), message);
return Action.INPUT;
}
}
else
{
userInfo = (Admin) obj;
}
// 获取登录用户的编号
int userId = -1;
if (userInfo != null)
{
userId = userInfo.getId();
}
String className = invoke.getAction().getClass().getName();
try
{
ActionProxy proxy = invoke.getProxy();
String actionMethod = proxy.getMethod();
sysLogger.log(Level.DEBUG, "method starts..." + className + "." + actionMethod);
result = invoke.invoke();
if (sysLogger.isDebugEnabled())
{
sysLogger.log(Level.DEBUG, printActionExceuteResult(proxy, invoke));
printValueStackAfterActionExceuted(proxy, invoke);
}
if (!needLog(className))
{
return result;
}
baseAction = (BaseAction) invoke.getAction();
// 获取描述
operateDesc = baseAction.getOperateDesc();
// 获取操作码
logMessageId = baseAction.getOperateCode();
// 获取不发生异常情况的操作结果
operateResult = baseAction.isOperateResult();
}
catch (Exception e)
{
if (!needLog(className))
{
return result;
}
String message = handleException(userId, ipAddr, invoke, e);
request.setAttribute(Constants.ERROR_MESSAGE.getStringValue(), message);
String errorPageWindow = request.getParameter("errorPageWindow");
// 是否采用打开新窗口来显示错误页面
if (errorPageWindow != null)
{
return Constants.GLOBAL_ERROR_WINDOW.getStringValue();
}
else
{
return Constants.GLOBAL_ERROR.getStringValue();
}
}
// 不发生异常情况的处理
return handleActionResult(userId, ipAddr, invoke, result);
}
private boolean needLog(String className)
{
// 判断是否需要写日志
if (excludeClassStr.length > 0)
{
for (int i = 0; i < excludeClassStr.length; i++)
{
String pattern = excludeClassStr[i];
boolean isMatch = Pattern.matches(pattern, className);
if (isMatch)
{
return false;
}
}
}
return true;
}
/**
* 向日志信息中写入Action执行结果的详细信息。
*
* @param proxy
* Action代理对象
* @param invoke
* Action执行对象
* @return [返回Action执行结果]
*
* @return String [返回Action执行结果]
*/
protected String printActionExceuteResult(ActionProxy proxy, ActionInvocation invoke)
{
StringBuilder buffer = new StringBuilder();
buffer.append("method ends...");
buffer.append(invoke.getAction().getClass().getName());
buffer.append(".");
buffer.append(proxy.getMethod());
buffer.append(", and the execute result is ").append(invoke.getResultCode());
return buffer.toString();
}
/**
* 打印Action执行后,ValueStack栈中的数据。
*
* @param proxy
* Action执行代理对象
* @param invoke
* Action执行对象
*/
protected void printValueStackAfterActionExceuted(ActionProxy proxy, ActionInvocation invoke)
{
String actionName = invoke.getAction().getClass().getName();
String actionMethod = proxy.getMethod();
StringBuilder buffer = new StringBuilder();
Object action = invoke.getAction();
Method[] methods = action.getClass().getMethods();
for (Method method : methods)
{
if (method.getParameterTypes() != null && method.getParameterTypes().length > 0)
{
continue;
}
printMethodInAction(buffer, method, action);
}
String result = buffer.toString();
int index = result.lastIndexOf(SerConstants.COMMA);
if (index != -1)
{
result = result.substring(0, index);
}
buffer = new StringBuilder();
buffer.append("invoke '");
buffer.append(actionName);
buffer.append(".");
buffer.append(actionMethod);
buffer.append("', and it's variables are: ");
buffer.append(result);
sysLogger.debug(buffer.toString());
}
protected boolean printMethodInAction(StringBuilder buffer, Method method, Object action)
{
boolean doProcess = true;
String methodName = method.getName();
if (methodName != null && methodName.startsWith("get"))
{
try
{
Object obj = method.invoke(action);
if (!isFilter(obj))
{
String fieldName = getFieldName(methodName);
boolean doOutput = cannotOutput(fieldName);
if (!doOutput)
{
String className = obj.getClass().getName().toLowerCase();
if (className.contains("service") || className.contains("dao"))
{
doProcess = false;
}
else
{
append(buffer, fieldName, obj);
}
}
}
}
catch (Exception e)
{
sysLogger.error(methodName, e);
}
}
return doProcess;
}
public boolean isFilter(Object obj)
{
if (obj == null)
{
return true;
}
else if (obj instanceof IService)
{
return true;
}
else if (obj instanceof IBaseDAO)
{
return true;
}
else
{
return false;
}
}
protected void append(StringBuilder buffer, String fieldName, Object object)
{
buffer.append(fieldName);
buffer.append("=");
buffer.append(Arrays.toString(new Object[] { object }));
buffer.append(SerConstants.COMMA);
}
protected boolean cannotOutput(String fieldName)
{
if (isReturnTrue(fieldName))
{
return true;
}
else
{
return false;
}
}
private boolean isReturnTrue(String fieldName)
{
return "locale".equalsIgnoreCase(fieldName) || "actionErrors".equalsIgnoreCase(fieldName)
|| "actionMessages".equalsIgnoreCase(fieldName) || "errorMessages".equalsIgnoreCase(fieldName)
|| "class".equalsIgnoreCase(fieldName) || "fieldErrors".equalsIgnoreCase(fieldName)
|| "errors".equalsIgnoreCase(fieldName) || "error".equalsIgnoreCase(fieldName);
}
protected String getFieldName(String methodName)
{
String firstChar = methodName.substring(3, 4);
String out = firstChar.toLowerCase() + methodName.substring(4);
return out;
}
/**
* 执行Action后没有发生异常的处理。 1、先根据操作码从操作码定义的资源文件获取内容,解析成Log实体。
* 2、再根据action执行的操作结果,设置该Log实体的操作结果属性。 3、插入一条数据库日志记录。
*
* 如果不存在操作,则不做任何处理,即:不会往数据库写入日志记录。
*
* @param userId
* 登录用户的编号
* @param ipAddr
* 登录用户的IP地址
* @param invoke
* 拦截器调用对象
* @param result
* 拦截器执行Action的返回结果
* @return 拦截器执行Action的返回结果
*
* @return String 拦截器执行Action的返回结果
*/
protected String handleActionResult(int userId, String ipAddr, ActionInvocation invoke, String result)
{
// 存在操作码,写入操作日志
if (logMessageId != null)
{
if (!"browse".equalsIgnoreCase(baseAction.getAction()))
{
// 如果返回的是“input”字符串,表明是校验没有通过,返回输入页面,因此不需要记录数据库日志。
String resultCode = invoke.getResultCode();
if (null == resultCode)
{
resultCode = "";
}
if ("input".equalsIgnoreCase(resultCode))
{
return result;
}
else if (resultCode.toLowerCase().contains("input"))
{
return result;
}
// 成功写入数据库日志
com.xxxx.dhm.portalMS.log.entity.BusinessLog log = createLog(userId, ipAddr);
if (log != null)
{
if (this.operateResult)
{
log.setResult(Constants.SUCCEED.getStringValue()); // 表示成功
}
else
{
log.setResult(Constants.FAILURED.getStringValue());// 不发生异常情况下,Action返回失败的状态码,并设置日志操作结果为失败。
}
dbLogger.log(DHMLogLevel.SERVICE, log);
}
}
}
return result;
}
/**
* 异常处理 首先判断异常类型,如果是portalMSExceptin,那么这样的处理:
* 1、从异常对象中获取错误代码,然后根据错误代码从资源文件中,读取该错误代码所对应的内容, 然后将内容和异常堆栈信息,写入系统日志。
* 2、从操作的Action中获取操作码和操作描述,根据操作码从资源文件中读取具体什么操作(操作名称、操作对象),写入数据库日志
* 如果不是portalMSExceptin,那么将错误信息和异常堆栈写入系统日志。
*
* @param userId
* 登录用户的编号
* @param ipAddr
* 登录用户的IP地址
* @param invoke
* 拦截器调用对象
* @param e
* 异常对象
* @return 返回错误信息
*
* @return String 返回错误信息
*/
protected String handleException(int userId, String ipAddr, ActionInvocation invoke, Exception e)
{
baseAction = (BaseAction) invoke.getAction();
// 获取描述
operateDesc = baseAction.getOperateDesc();
// 获取操作码
logMessageId = baseAction.getOperateCode();
// 错误信息
String message = null;
if (e instanceof PortalMSException)
{
PortalMSException iepg = (PortalMSException) e;
// 从异常中获取错误代码
int errorCodeTmp = (int) iepg.getErrorCode();
// 从拦截器中获取错误代码
if (errorCodeTmp != 0)
{
errorCode = errorCodeTmp;
}
if (errorCode != 0)
{
// 发生异常写入系统日志
message = errorCodeProvider.getText(Constants.MSG_PORTALMS
+ Constants.ERROR_CODE_PREFIX.getStringValue() + String.valueOf(errorCodeTmp),
new String[] { String.valueOf(errorCodeTmp) });
// 从错误定义的资源文件中没有获取相应的错误信息,则从异常堆栈中获取错误信息。
if ((Constants.ERROR_CODE_PREFIX.getStringValue() + errorCodeTmp).equalsIgnoreCase(message))
{
message = iepg.getMessage();
}
// 判断是否是增,删和改操作
boolean isManipulate = isDataBaseManipulateException(message);
// 发生异常写入操作描述
StringBuilder buffer = new StringBuilder();
buffer.append(message);
LogMessageBean logMessageBean = parseOperateContentAsLogMessageBean();
if (logMessageBean != null)
{
buffer.append("Operate:[OperateDescription=");
buffer.append(logMessageBean.getOperateModule());
buffer.append("]");
}
sysLogger.error(buffer.toString(), e);
// 无法与数据库建立连接
if (!isValidConnection(e))
{
message = getConnectDatabaseErrorMessage();
sysLogger.error("can't connect to database, please check the connection is valid!!");
}
else
{
// 获取异常信息,并处理异常信息
message = getExceptionMessageDisplayInErrorPage(message);
// 能够建立与数据库的连接
if (isManipulate)
{
// 发生异常写入数据库日志
com.xxxx.dhm.portalMS.log.entity.BusinessLog log = createLog(userId, ipAddr);
if (log != null)
{
String exceptionMessage = pareseExceptionMessage(iepg);
if (exceptionMessage != null)
{
String operateDesc = log.getDescription() + "\n<br/>Exception [" + exceptionMessage
+ "]";
log.setDescription(operateDesc);
}
log.setResult(Constants.FAILURED.getStringValue()); // 表示失败
dbLogger.log(DHMLogLevel.SERVICE, log, e);
}
}
}
}
else
{
// 从portalMSException中获取获取信息。
message = e.getMessage();
}
}
else
{
ActionProxy proxy = invoke.getProxy();
StringBuilder buffer = new StringBuilder();
buffer.append(invoke.getAction().getClass().getName());
buffer.append(".");
buffer.append(proxy.getMethod());
if (e.getMessage() == null)
{
return null;
}
// 发生异常写入系统日志
sysLogger.error(buffer.toString(), e);
// 将异常信息显示在错误页面
message = getExceptionMessageDisplayInErrorPage(e.getMessage());
}
return message;
}
protected String getExceptionMessageDisplayInErrorPage(String errorMessage)
{
String message = errorMessage;
int index = message.indexOf("portalMS-");
if (index == -1)
{
message = this.errorCodeProvider.getText(Constants.MSG_PORTALMS
+ Constants.ERROR_CODE_PREFIX.getStringValue()
+ String.valueOf(Constants.ERROR_CODE_ACCESS_DATABASE.getLongValue()), new String[] { String
.valueOf(Constants.ERROR_CODE_ACCESS_DATABASE.getLongValue()) });
}
if (message.equals(String.valueOf(Constants.ERROR_CODE_ACCESS_DATABASE.getLongValue())))
{
message = PropertiesFactory.getValueString(ChineseCharacter.ERROR_CONNECT_DB);
}
return message;
}
public boolean isDataBaseManipulateException(String exceptionMessage)
{
boolean isManipulate = true;
if (this.filterActions != null && this.filterActions.length != 0)
{
for (String action : this.filterActions)
{
if (exceptionMessage.contains(action.trim()))
{
isManipulate = false;
break;
}
}
}
return isManipulate;
}
public String pareseExceptionMessage(Exception e)
{
StringBuilder buffer = new StringBuilder();
String message = e.toString();
int start = message.indexOf("java.sql.SQLException");
int end = message.indexOf("at", 5000);
if (start != -1 && end != -1)
{
buffer.append(message.substring(start, end));
}
else if (start != -1 && end == -1)
{
buffer.append(message.substring(start));
}
else
{
buffer.append(e.getMessage());
}
StackTraceElement[] elements = e.getStackTrace();
for (int i = 0, size = elements.length; i < 5 && i < size; i++)
{
StackTraceElement element = elements[i];
buffer.append("\n<br/>");
buffer.append("at ");
buffer.append(element);
}
return buffer.toString();
}
protected String getConnectDatabaseErrorMessage()
{
StringBuilder buffer = new StringBuilder();
buffer.append("DHM.Studio-");
buffer.append(Constants.ERROR_CODE_CONNECT_DATABASE.getLongValue());
buffer.append(":");
buffer.append(this.errorCodeProvider.getText(Constants.MSG_PORTALMS + "cant.connected.db.message"));
return buffer.toString();
}
/**
* 根据异常对象,来判断该异常是否是由于无法连接到数据库产生的。
*
* @param e
* 异常对象
* @return 返回true表示能够正常连接到数据库,返回false无法连接到数据库
*
* @return boolean 返回true表示能够正常连接到数据库,返回false无法连接到数据库
*/
protected boolean isValidConnection(Exception e)
{
if (e == null)
{
return true;
}
boolean isValid = true;
String message = e.toString();
String cantConnectedMessage = this.errorCodeProvider.getText(Constants.MSG_PORTALMS
+ "cant.connected.db.message");
if (message != null && message.contains(cantConnectedMessage))
{
isValid = false;
}
return isValid;
}
/**
* 根据操作码解析出操作内容,并将操作内容解析成LogMessageBean对象
*
* @return 返回解析的LogMessageBean对象
*
* @return LogMessageBean 返回解析的LogMessageBean对象
*/
protected LogMessageBean parseOperateContentAsLogMessageBean()
{
if (logMessageId == null)
{
return null;
}
String messageContent = this.operateCodePrivider.getText(Constants.MSG_PORTALMS
+ Constants.OPERATE_CODE_PREFIX.getStringValue() + String.valueOf(logMessageId));
return LogMessageParser.convert2LogMessageBean(messageContent);
}
/**
* 创建日志实体,日志实体的信息来源与日志配置文件。
* 根据操作码,从LogDefinitions.properties读取操作信息,并将信息封装成LogMessageBean对象。
*
* @param userId
* 登录用户的ID号
* @param ipAddr
* 客户端请求的IP地址
* @return LogMessageBean对象,封装具体的操作信息。
*
* @return com.xxxx.dhm.portalMS.log.entity.BusinessLog
* LogMessageBean对象,封装具体的操作信息
*/
protected com.xxxx.dhm.portalMS.log.entity.BusinessLog createLog(int userId, String ipAddr)
{
if (logMessageId == null && userId != 0)
{
return null;
}
String messageContent = this.operateCodePrivider.getText(Constants.MSG_PORTALMS
+ Constants.OPERATE_CODE_PREFIX.getStringValue() + String.valueOf(logMessageId));
LogMessageBean messageBean = LogMessageParser.convert2LogMessageBean(messageContent);
if (messageBean != null)
{
com.xxxx.dhm.portalMS.log.entity.BusinessLog log = LogMessageParser.createLog(userId, ipAddr,
logMessageId, messageContent, this.operateDesc);
return log;
}
else
{
sysLogger.warn("there is no '" + logMessageId + "' define in LogDefinitions.xml");
return null;
}
}
/**
* 获取语言
*/
public Locale getLocale()
{
ActionContext ctx = ActionContext.getContext();
if (ctx != null)
{
return ctx.getLocale();
}
else
{
sysLogger.debug("Action context not initialized");
return null;
}
}
public String getLogMessageId()
{
return logMessageId;
}
public void setLogMessageId(String logMessageId)
{
this.logMessageId = logMessageId;
}
public int getErrorCode()
{
return errorCode;
}
public void setErrorCode(int errorCode)
{
this.errorCode = errorCode;
}
public String getIncludeParams()
{
return includeParams;
}
public void setIncludeParams(String includeParams)
{
this.includeParams = includeParams;
}
public String[] getFilterActions()
{
String[] temp = filterActions;
return temp;
}
public void setFilterActions(String[] filterActions)
{
this.filterActions = (String[]) filterActions.clone();
}
public String getExcludeClass()
{
return excludeClass;
}
public void setExcludeClass(String excludeClass)
{
this.excludeClass = excludeClass;
}
}
/*
* 工程名: XXXXX
* 包 名: com.XXX.dhm.portalMS.base.web.interceptor
* 文 件名: ExTokenInterceptor.java
* 版 权: Copyright (c) 2009 Coship All Rights Reserved.
* 描 述: 防止重复提交的拦截器
* 修 改 人:
* 修改时间:
* 跟踪单号:
* 修改单号:
* 修改内容:
*/
package com.XXXX.dhm.portalMS.base.web.interceptor;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.TokenInterceptor;
import org.apache.struts2.util.TokenHelper;
import com.XXX.dhm.portalMS.common.Constants;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
/**
*
* 防止重复提交的拦截器,通过扩展了struts2的重复提交的拦截器。
* 该拦截器的使用如下:
* 1、不进行重复提交校验,那么该拦截器将不做任何拦截操作。
* 2、如果进行重复提交校验,需要做的操作如下:
* 1)、在jsp页面中form中加入:<s:token />,那么就进行重复提交的校验操作。
* 2)、校验的规则是这样的,首先会重http请求参数中获取该token的值,然后再从
* session中获取同名的token值,然后两个值进行比较。
* 3)、如果两个一样,则校验通过,否则struts2将会将跳转到“input”配置的页面去。
*
*
*
* @version
* @since
*/
public class ExTokenInterceptor extends TokenInterceptor {
/**
* 序列化ID
*/
private static final long serialVersionUID = -6688464557536335754L;
/**日志记录对象*/
private static final Logger logger = Logger.getLogger( ExTokenInterceptor.class );
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
if (log.isDebugEnabled()) {
log.debug("Intercepting invocation to check for valid transaction token.");
}
HttpSession session = ServletActionContext.getRequest().getSession(true);
synchronized (session) {
String tokenName = getTokenName();
if( tokenName == null ) {
return handleValidToken(invocation);
}
if (!validToken()) {
return handleInvalidToken(invocation);
} else {
return handleValidToken(invocation);
}
}
}
@Override
protected String handleInvalidToken(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
String errorMessage = LocalizedTextUtil.findText(this.getClass(), Constants.MSG_PORTALMS+"struts.messages.invalid.token",
invocation.getInvocationContext().getLocale(),
"The form has already been processed or no token was supplied, please try again.", new Object[0]);
if (action instanceof ValidationAware) {
((ValidationAware) action).addActionError(errorMessage);
} else {
logger.warn(errorMessage);
}
return Action.INPUT;
}
public static boolean validToken() {
String tokenName = TokenHelper.getTokenName();
if ( tokenName == null ) {
return true;
}
String token = TokenHelper.getToken(tokenName);
if (token == null) {
return false;
}
Map<String, Object> session = ActionContext.getContext().getSession();
String sessionToken = (String) session.get(tokenName);
if (!token.equals(sessionToken)) {
logger.warn(LocalizedTextUtil.findText(TokenHelper.class, "struts.internal.invalid.token", ActionContext.getContext().getLocale(), "Form token {0} does not match the session token {1}.", new Object[]{
token, sessionToken
}));
return false;
}
// remove the token so it won't be used again
session.remove(tokenName);
return true;
}
public static String getTokenName() {
Map<String, Object> params = ActionContext.getContext().getParameters();
if (!params.containsKey( "struts.token.name" )) {
return null;
}
String[] tokenNames = (String[]) params.get("struts.token.name");
String tokenName;
if ((tokenNames == null) || (tokenNames.length < 1)) {
return null;
}
tokenName = tokenNames[0];
return tokenName;
}
}
/*
* 工 程 名: XXX
* 包 名: com.XXXX.dhm.portalMS.base.web.interceptor
* 文 件 名: SiteInterceptor.java
* 版 权: Copyright (c) 2010 XXXX All Rights Reserved.
* 描 述: <描述>
* 修 改 人:
* 修改时间:
* 跟踪单号: <跟踪单号>
* 修改单号: <修改单号>
* 修改内容: <修改内容>
*/
package com.XXX.dhm.portalMS.base.web.interceptor;
import java.util.Map;
import org.apache.struts2.ServletActionContext;
import com.XXX.dhm.portalMS.common.Constants;
import com.XXXX.dhm.portalMS.common.util.SessionUtil;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* ClassName:SiteInterceptor
* Function: TODO ADD FUNCTION
* Reason: TODO ADD REASON
*
* @author 903881
* @version V200R001
* @since DHM.Core.portalMS-V200R002
* @Date 2010-6-18 下午02:37:22
*
* @see
*/
/**
* 站点拦截器,用来设置每个请求时的siteID,当用户触发一个Action, 该拦截器从当前用户的Session中取出
* 正在操作的siteID并将其绑定到当前操作线程
*
* @author 903881
* @version [V200R002, 2010-6-18]
* @see [相关类/方法]
* @since [DHM.Core.portalMS-V200R002]
*/
public class SiteInterceptor extends AbstractInterceptor {
/**
* 注释内容
*/
private static final long serialVersionUID = -7194853807889275168L;
@Override
public String intercept(ActionInvocation invoke) throws Exception {
Map<String, Object> session = ServletActionContext.getContext().getSession();
Long siteID = (Long)session.get(Constants.CURRENT_SITE_ID.getStringValue());
if(siteID != null){
SessionUtil.setLocalSiteID(siteID);
}
return invoke.invoke();
}
}
<s:form theme="simple" validate="true" action="addApplication" namespace="/application" >
<s:token/>