2007年8月21日星期二


项目需要,在原来Struts的基础上,配了Spring,数据库访问也用JDBC代替,由于Spring出色的控制反转,JDBC连接的工作基本上不需要考虑,只要专注于数据抽取就可以了,下边把代码贴一下,顺便说说一些小细节。

Spirng和Struts结合,主要有三种方式:
1,使用ActionSupport类
2,覆盖RequestProcessor
3,将Action委托给Spring
文章<使用 Spring更好地处理Struts动作>中,对这三种方法都分析得比较详细,我在这里归纳一下.
使 用第一种方法,是最简单的,不需要其他任何配置,只需要在把继承Action,改成继承ActionSupport,带来的问题就是Struts与 Spring,紧耦合,以后不使用Spring配置时,需要修改代码.但其实,我目前觉得使用此方法,有一个好处是可以方便的得到 WebApplicationContext对象,不然,就需要使用ClassPathXmlApplicaiton("...")来取得Context 对象,不是很方便.其实,看DelegationActionUtils的源码,applicationContext对象也只是,这样子通过 sturts的plugin取得的.
actionServlet.getServletContext().getAttribute(
ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + modulePrefix)

第二种方法,所有Action的分发都是通过ActionServlet的,而实际上的操作是由RequestProcessor 完成的,因此,可以把它覆盖,引入Spring
The RequestProcessor is where the majority of the core processing occurs for each request. Since version 1.3, the default Request Processor (ComposableRequestProcessor) is composed using Jakarta Commons Chain, which is an implementation of the Chain of Responsibility pattern (CoR).

The <controller> element allows you to configure the ActionServlet. Many of the controller parameters were previously defined by servlet initialization parameters in your web.xml file but have been moved to this section of struts-config.xml in order to allow different modules in the same web application to be configured differently.

第三种是最推荐的方法
顺便说一下,plugin在struts的概念,来自UserGuide:
The PlugIn interface extends Action and so that applications can easily hook into the ActionServlet lifecycle. This interface defines two methods, init() and destroy(), which are called at application startup and shutdown, respectively. A common use of a Plugin Action is to configure or load application-specific data as the web application is starting up.
其中Spring中的ContextLoaderPlugIn就是继承此PlugIn ,从而引入了Spring


基本上这样子就可以把Spring+Struts配置好,然后Spring+JDBC,关键就是配置好DataSource,然后通过JdbcTemplate类,就可以很方便的进行配置.以下部分为代码:

web.xml
<web-app>


<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-*.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>

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

<struts-config>
<data-sources />
<form-beans>
<form-bean name="reportBaseForm"
type
="com.sjtu.wgq.framework.controller.ReportBaseActionForm">
</form-bean>
</form-beans>
<global-exceptions />
<global-forwards />
<action-mappings>
<action name="reportBaseForm" path="/reportBaseAction"
type
="org.springframework.web.struts.DelegatingActionProxy">
<forward name="success" path="/success.jsp"></forward>
<forward name="fail" path="/fail.jsp"></forward>
</action>
</action-mappings>
<message-resources
parameter="com.sjtu.wgq.framework.ApplicationResources" />
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value
="/WEB-INF/action-servlet.xml" />
</plug-in>
</struts-config>

action-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/reportBaseAction" class="com.sjtu.wgq.framework.controller.ReportBaseAction"></bean>
</beans>


applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource"
class
="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value
="oracle.jdbc.driver.OracleDriver">
</property>
<property name="url"
value
="jdbc:oracle:thin:@IP:端口:SIN">
</property>
<property name="username" value=""></property>
<property name="password" value=""></property>
</bean>
</beans>


applicatoinContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="userDAO" class="com.sjtu.wgq.dao.jdbc.UserJdbcTemplateDAO">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
</beans>

UserDAO.java
public interface UserDAO ...{
public List getUser(String uid);
}

User.java
public class User ...{

String name;
String pwd;

public String getName() ...{
return name;
}

public void setName(String name) ...{
this.name = name;
}

public String getPwd() ...{
return pwd;
}

public void setPwd(String pwd) ...{
this.pwd = pwd;
}

}


UserJdbcTemplateDAO.java
public class UserJdbcTemplateDAO extends JdbcDaoSupport implements UserDAO...{

public List getUser(String uid)...{
if(uid!=null&& !uid.equals(""))...{
String sql
= "select ba.USER_ID id ,ba.PSWD_NO no from Ba.Ba9040 ba where ba.USER_ID= " +uid;
//this.getJdbcTemplate().queryForList(sql);
return this.getJdbcTemplate().query(sql,new UserRowMapper());
}

return null;
}


private class UserRowMapper implements RowMapper...{
public Object mapRow(ResultSet rs,int index)throws SQLException...{
User user
=new User();
user.setName(rs.getString(
"id"));
user.setPwd(rs.getString(
"no"));
return user;
}

}

}

ReportBaseAction.java
public abstract class BaseAction extends ActionSupport {

/** 继承与ActionSupport,
*
@see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public final ActionForward execute(ActionMapping mapping,ActionForm actionForm,
HttpServletRequest request, HttpServletResponse response) {
ApplicationContext ctx
= this.getWebApplicationContext();
//Spring完成注入和初始化.
UserDAO userDao = (UserDAO)ctx.getBean("UserDAO");
//调用UserDAO接口声明的方法.
//userDAO.getUser("1");
}
}

ActionForm的部分就省略了.
另外提一下就是,ActionSupport的getWebApplicatoinContext()方法载入的xml文件,是要在web.xml的<context-param>声明的,否则如果只在struts-config.xml声明会找不到的.因为两个声明的不是一个概念,在getWebApplicatoinContext是通过servlet.getContext 的方法找到的,而在struts-config.xml配置的只是action-servlet.xml,即action的内容.具体原因,我还没有去查.

另外就是关于多个applicationContext的问题,可以参考web.xml的配置就可以了.
还有,applicationContext-dao.xml中的UserDao引用了dataSource,因为不在同一文件中,所以用<bean ref="">的格式,如果在同一文件可以用<bean local="">来引用.

通过Spring,使得Struts更加灵活,JDBC的配置很简单,但配置文件多,而且因为applicatonContext配置不正确的话,web工程是无法启动的,报linstener的错误,但不会具体指出是什么错.

还有以下问题要看看资料:
1,为什么在plugin里配置的xml,无法在getWebApplication中得到,按道理应该是一致的,因为都是通过actoinservlet去取得信息.
2,RequestProcessor具体是怎么工作的.

下次把<程序员面试指南>的体会说一下.

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1559803


首先是一个基类BaseAction
=================================================================
public class BaseAction extends ActionSupport {
/** 简单的得到spring bean的方法*/
public Object getBean(String beanName) {
return this.getWebApplicationContext().getBean(beanName);
}

/** 由子类Action对象调用, 可以在初始化时反射自身的结构, 形成一个映射, 用来日后dispatchSubaction.
*
* @return 存放了methods对象的Map
*/
protected Map getMethodMap() {
......
}

/** 将Action转移给子动作.
* 在子类中调用时,只需要新建一个Object[] {参数1, 参数2, ...} 一般为 {form, request, dao}
* 然后调用dispatchSubAction(String, objects) 即可
*
* @param action 字符串,决定子动作的方法名
* @param objs 参数对象列表
* @param methods 由getMethodMap得到的Map
* @return 用来findForward的别名
*/
protected String dispatchSubAction(String action, Object[] objs, Map methods) throws Exception {
......
}

之后是子类的写法:
================================================================
public class SomeAction extends BaseAction {
protected Map methods = getMethodMap(); //各线程公用
//--------- 下面是此Action中公用的一些对象,线程安全?
XxxDAO xxxDao=(XxxDAO) getBean("xxxDao");
XxxService xxxService = (XxxService) getBean("xxxService");

public ActionForward execute(......) throws Exception {
// ===================== 初始化环境 ===================== \
XxxForm form = (XxxForm) actionForm;
ActionErrors errors = new ActionErrors();

// ==================== 获取用户参数 ==================== \
//主要是进行数据转换如:form.setXxx() = form.getXxx().split("..");

// ==================== 调用业务逻辑 ==================== \
Object[] params = {form, request, errors};
//这里的params要和下面定义的所有子程序的参数对应起来
String forward = dispatchSubAction(form.getSubaction(), params, methods);

// ==================== 设置回传参数 ==================== \
saveErrors(request,errors);
return mapping.findForward(forward);
}

//所有的子程序的参数声明都应该相同, 但是每个Action可以根据自己的情况有所区别
public String show(MonthDayExecuteForm form, HttpServletRequest request, ActionErrors errors) {
......
return "show";
}

public String edit(MonthDayExecuteForm form, HttpServletRequest request, ActionErrors errors) {
......
return "edit";
}

public String save(MonthDayExecuteForm form, HttpServletRequest request, ActionErrors errors) {
......
return "show";
}
}
================================================================
归纳:我知道struts有lookupDispatchAction,1.2还有MappedAction,但是那些东西使用起来都不太方便。
1. 有的需要在MessageResources里面进行Submit按钮文字定义。
2. 有的需要在config中有特殊的配置
3. 必须使用和execute完全相同的冗长的函数声明
4. 各方法之间没有交集,难以实现统一的log处理,代码重复写的太多,例如一个简单的XxxForm form = (XxxForm) actionForm; 就必须写在所有的子方法中。

不知道我这样做能不能较好的解决上面的问题?虽然会带来一些初始化的负担,但是实际运行时应该不会怎么影响效率。我主要关心的是,这个结构还可不可以优化?另外有没有什么安全/效率方面的硬伤?望高手们多多指点!

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月05日 23:50 回复
SportsBaby1980 发表文章: 244/ 注册时间: 2004年06月09日 16:52
没看明白

是自己写的mvc实现?

还是在struts上作的一些方便开发的功能?

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月06日 11:39 回复
banq 发表文章: 8120/ 注册时间: 2002年08月03日 17:08
一个建议:
将 Object[] params = {form, request, errors};
包装成对象,其实这是DTO对象,可参考Jdon框架中的EventModel。

一个疑问:
show、edit等重要方法是如何激活的? 这里是性能的关键点。

如果使用struts的dispatchAction,它根据参数parameter的值来直接映射的,比较方便。

在Jdon框架中,BaseAction(SomeAction ) 相当于ModelHandler,但是这部分代码在通常情况下可自动生成,通过配置完成。

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月09日 23:03 回复
zyhalj 发表文章: 10/ 注册时间: 2003年10月29日 16:22
为了确保线程安全在一个应用的生命周期中,struts框架只会为每个action类创建一个action实例,所有的用户共请求共享同一个action 实例,并且所有的请求线程可以同时执行action实例的execute()方法。所以你的小框架中的xxxDao 变量是实例变量,肯定是线程不安全的。采用同步方法也是不能解决线程安全的问题的。同样还是会出现“脏读”现象。

banq说的对,你为什么不用dispatchAction呢,config配置并不复杂呀。这点灵活性

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月11日 14:47 回复
zyhalj 发表文章: 10/ 注册时间: 2003年10月29日 16:22
ThreadLocal 是解决多线程内部数据的,你可以在网上看看相关例子

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月11日 20:45 回复
yuzs2000 发表文章: 3/ 注册时间: 2003年11月14日 21:34
楼主的想法有点从新制造轮子的嫌疑了.
dispatchAction的确非常实用,MappingDispatchAction 解决了dispatchAction的不足之处,这两个类已经非常完善了,简单配置下文件就可以了,完全没有必要再去做重复的工作.

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月13日 22:49 回复
markyang 发表文章: 16/ 注册时间: 2004年07月19日 22:33
问一个小问题
楼主为什么用GETBEAN 而不用SETDAO方法?

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月13日 22:51 回复
markyang 发表文章: 16/ 注册时间: 2004年07月19日 22:33
把SERVICE 与DAO放在同一层是不是有些混乱呢?

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月15日 10:33 回复
vcshcn 发表文章: 36/ 注册时间: 2003年12月28日 23:11
没看懂
建议下次能否先说明一下思路,然后在把代码贴出来

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月15日 10:36 回复
vcshcn 发表文章: 36/ 注册时间: 2003年12月28日 23:11
大概看了一下,不知道对不对
这种结构我好象在sun的demo里,要不就是在ibatis的demo里见到过,没什么发明的,参考一下就可以了

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月20日 12:02 回复
warbaby 发表文章: 11/ 注册时间: 2005年01月29日 18:24
不知道有没有人在实际中使用过struts的DispatchAction系列? 谁又能给我明白的讲讲DispatchAction, LookupDispatchAction, MappingDispatchAction各自的用法和区别呢?

1) DispatchAction就是在struts-config中用parameter参数配置一个表单字段名,这个字段的值就是最终替代execute 被调用的方法. 例如parameter="method"而request.getParameter("method")="save",其中"save"就是 MethodName。struts的请求将根据parameter被分发到"save"或者"edit"或者什么。但是有一点,save()或者 edit()等方法的声明和execute必须一模一样。

2) LookupDispatchAction继承DispatchAction, 用于对同一个页面上的多个submit按钮进行不同的响应。其原理是,首先用MessageResource将按钮的文本和ResKey相关联,例如 button.save=保存;然后再复写getKeyMethodMap(), 将ResKey和MethodName对应起来, 例如map.put("button.save", "save"); 其配置方法和DispatchAction是一样的, 使用时要这么写:
<html:submit property="method">
<bean:message key="button.save"/>
</html:submit>

3) MappingDispatchAction是1.2新加的, 也继承自DispatchAction. 它实现的功能和上面两个区别较大, 是通过struts-config.xml将多个action-mapping映射到同一个Action类的不同方法上, 典型的配置就是:
<action-mappings>
<action path="/saveUser" type="logic.UserAction" parameter="save"></action>
<action path="/editUser" type="logic.UserAction" parameter="edit"></action>
</action-mappings>
然后UserAction继承MappingDispatchAction,其中有:
public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
等方法

可以看到, 不管怎么变化, 其实这些类都是把execute给分解开, 不管是save, edit还是其他什么方法, 其实都是和原来的execute是等价的, save和edit之间没有任何直接的关系, 而事实呢,它们是同一个业务模型的两种不同操作。 我觉得这就是一个问题,对于save和edit这两种请求, 我后台逻辑有可能只是调用service的方法那一句不一样,其他代码是完全一致的(例如错误处理, 日志记录等)。因此我想出了这个小东西,在execute方法内部进行局部分解。

上面有人说看iBATIS的代码看到过类似的。的确, iBATIS实现了一个BeanAction,将ActionForm和Acion写到了一个类里,然后通过一个ThreadLocal的局部变量在各个 方法之间传递actionMapping, request, response这些参数。其每个方法的声明变得非常简单,返回的也是字符串forward名。

我在很大程度上是受了Clinton Begin的一些启发,但是BeanAction实现的框架稍微有些大,改写了struts的根本模式。而且作者也说,该框架没有经过实际应用的测试,所以我不想用。

楼顶的帖子我是想说的尽量全面些,所以把service,dao什么的都写进去了。有人说为什么不用setDao, 我不太明白是什么意思。是不是用spring直接注入呢?那样的话,必须用spring的代理,感觉不是很稳定而且大大增加了配置工作。
有 人说xxxDao是局部变量,线性不安全。我也是想问问这个,象这种DAO和Service类,其本身一旦建立,是不会进行任何修改的(但是因为要从 spring取,所以不能声明为final)。是不是可以理解为提供一些静态方法(例如saveWorld)的工具类呢?这样的话,是不是就不存在线程不 安全的问题了?
究竟啥是线性不安全啊!!


下面是使用这个框架的例子。为了简便,去掉了接口层。BaseAction就不写了

===================== TestDAO,真正的业务逻辑实现 =============================
public class TestDAO {
public void editWorld() {
System.out.println("Editing the world");
}

public void saveWorld() {
System.out.println("Saving the world");
}
}

===================== TestService 业务逻辑的facade, 通过spring将testDao注入 =============================
public class TestService {
private TestDAO testDao;

public void setTestDao(TestDAO testDao) { this.testDao = testDao; }

public void editWorldTest() {
testDao.editWorld();
}

public void saveWorldTest() {
testDao.saveWorld();
}
}

===================== TestAction =============================
public class TestAction extends BaseAction {

private TestService getTestService() { return (TestService) getBean("testService"); };

public ActionForward execute(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception {
TestActionForm form = (TestActionForm) actionForm;
ActionErrors errors = new ActionErrors();

Object[] params={form, request, errors};
// 上面是关键!Object[]不能设置为对象,因为有可能Test2Action的这一行是{form,request,response,messages,context}。这是这个框架灵活性的体现
String forward = dispatchSubAction(form.getMethod(), params, methods);
// 通过method进行分发, 可以采用其他任何变量

saveErrors(request, errors);
return mapping.findForward(forward);
}

//edit,save等方法的参数要和上面的Object[]相对照
public String edit(TestActionForm form, HttpServletRequest request, ActionErrors errors) {
log.info("现在是在edit子动作中");
getTestService().editWorldTest();
return "edit";
}

public String save(TestActionForm form, HttpServletRequest request, ActionErrors errors) {
log.info("现在是在save子动作中");
getTestService().saveWorldTest();
return "save";
}
}

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月20日 12:06 回复
warbaby 发表文章: 11/ 注册时间: 2005年01月29日 18:24
中间格式有点问题:重发前边几段

不知道有没有人在实际中使用过struts的DispatchAction系列? 谁又能给我明白的讲讲DispatchAction, LookupDispatchAction, MappingDispatchAction各自的用法和区别呢?

1) DispatchAction就是在struts-config中用parameter参数配置一个表单字段名,这个字段的值就是最终替代execute 被调用的方法. 例如parameter="method"而request.getParameter("method")="save",其中"save"就是 MethodName。struts的请求将根据parameter被分发到"save"或者"edit"或者什么。但是有一点,save()或者 edit()等方法的声明和execute必须一模一样。

2) LookupDispatchAction继承DispatchAction, 用于对同一个页面上的多个submit按钮进行不同的响应。其原理是,首先用MessageResource将按钮的文本和ResKey相关联,例如 button.save=保存;然后再复写getKeyMethodMap(), 将ResKey和MethodName对应起来, 例如map.put("button.save", "save"); 其配置方法和DispatchAction是一样的, 使用时要这么写:
<html:submit property="method">
<bean:message key="button.save"/>
</html:submit>

3) MappingDispatchAction是1.2新加的, 也继承自DispatchAction. 它实现的功能和上面两个区别较大, 是通过struts-config.xml将多个action-mapping映射到同一个Action类的不同方法上, 典型的配置就是:
<action-mappings>
<action path="/saveUser" type="logic.UserAction" parameter="save"></action>
<action path="/editUser" type="logic.UserAction" parameter="edit"></action>
</action-mappings>
然后UserAction继承MappingDispatchAction,其中有:
public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
等方法

可以看到, 不管怎么变化, 其实这些类都是把execute给分解开, 不管是save, edit还是其他什么方法, 其实都是和原来的execute是等价的, save和edit之间没有任何直接的关系, 而事实呢,它们是同一个业务模型的两种不同操作。 我觉得这就是一个问题,对于save和edit这两种请求, 我后台逻辑有可能只是调用service的方法那一句不一样,其他代码是完全一致的(例如错误处理, 日志记录等)。因此我想出了这个小东西,在execute方法内部进行局部分解。

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年04月20日 12:26 回复
warbaby 发表文章: 11/ 注册时间: 2005年01月29日 18:24
可能还是有些地方没说明白。
TestAction的配置和普通Action的配置完全一样。
TestActionForm里面有一个method属性。
运行结果:
http://localhost/webapp/test.do?method=save
在后台显示Saving the world.
http://localhost/webapp/test.do?method=edit
在后台显示Editing the world.

banq说关键是edit,save等methods是如何激活的。就是这句:
dispatchSubAction(form.getMethod(), params, methods);
根据请求的method值,从methods中选择一个java.lang.Method类,以params为参数调用。

这句是老版本,该贴发出后,经过优化,这里不需要使用methods来调用了。dispatchSubAction(form.getMethod(), params);就行了。在BaseAction里有一句
protected Map methods = getMethodMap();
在struts 初始化Action时,反射一次得到本Action的所有save,edit等等方法,Map里保存的是java.lang.Method,这样以后调用 应该能快些。子类中根本不需要看不到这一过程了,只要知道dispatchSubAction的第一个参数是方法名,第二个参数是调用方法的参数对象数组 即可。


Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年05月14日 10:34 回复
banq 发表文章: 8120/ 注册时间: 2002年08月03日 17:08
>反射一次得到本Action的所有save,edit等等方法,Map里保存的是java.lang.Method

最好不用用反射,反射是耗费性能的,或者使用缓存优化一下。

Re: 一个关于Struts Action的小框架, 请高手指点一下 发表: 2005年09月06日 10:04 回复
james_cn 发表文章: 24/ 注册时间: 2003年11月11日 21:04
//dongqi_zhao@hotmail.com


PublicForm继承自ActionForm,实现了当前登陆用户的统一获取(getUserId()),分页显示参数的统一传递(getStart(),getRange()),功能扩展参数(getDoType())。

PublicAction继承自Action,附加权限的判别,异常处理,日志纪录等功能
e.g.
<action name="stuentForm" type="com.virtual.test.action.StuentAddAction" scope="request" path="/test/stuentAddAction">
<forward name="list" path="/test/stuentListAction.do?doType=0" />
<forward name="add" path="/test/stuentAdd.jsp" />
<forward name="resource" path="2004105001002" />
<forward name="operator" path="201" />
</action>
通过resource,operator获取当前的资源,操作,进而进行权限鉴别


package org.open.struts;

import javax.servlet.http.*;

import org.apache.struts.action.*;
import org.open.util.*;

/**
* 所有actionForm的父类,提供登陆用户的统一获取,
* 分页参数的统一传递 *
*
*/
public class PublicForm
extends ActionForm {
/**
* 功能扩展用
*/
private int doType;
/**
* 当前用户id
*/
private String userId;
/**
* 开始记录数,分页用,从0开始
*/
private int start = 0;
/**
* 每页的记录数,
*/
private int range = 20;

public int getDoType() {
return doType;
}

public void setDoType(int doType) {
this.doType = doType;
}

public ActionErrors validate(ActionMapping actionMapping,
HttpServletRequest httpServletRequest) {

return null;
}

public void reset(ActionMapping actionMapping,
HttpServletRequest httpServletRequest) {
}

/**
* 获取公共信息,userID.....
*/
public void getCurrentDefine(ActionMapping actionMapping,
HttpServletRequest httpServletRequest) {

userId = PublicAction.LOGIN_NA;
Cookie cookie = CookieMgr.getCookie(httpServletRequest,
PublicAction.LOGIN_ACCOUNT_COOKIE);
if (cookie != null) {
userId = cookie.getValue();
}
}

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

public int getStart() {
return start;
}

public void setStart(int start) {
this.start = start;
}

public int getRange() {
return range;
}

public void setRange(int range) {
this.range = range;
}


}
















package org.open.struts;

import java.util.logging.*;
import javax.servlet.http.*;

import org.apache.struts.action.*;
import org.open.common.auth.logic.*;
import org.open.common.log.logic.*;

/**
* 作为所有业务Action的父类,提供权限统一判别,异常集中处理
*
*/
public class PublicAction
extends Action {

/**
* java logger interface
*/
private Logger logger;
/**
* debug point
*/
private String debugPoint;
/**
* 系统异常,置于request中的属性名
*/
public static final String SYS_EXCEPTION = "sys.exception";

/**
* 系统信息提示,置于reqeust中的属性名
*/
public static final String SYS_MESG = "sys.mesg";
/**
* 系统登陆页面的forward名称
*/
public static final String F_LOGIN = "login";
/**
* 系统登陆错误的forward名称
*/
public static final String F_LOGIN_NO = "login.no";

/**
* 系统登陆成功页面的forward名称
*/
public static final String F_LOGIN_YES = "login.yes";

/**
* 系统登出成功页面的forward名称
*/
public static final String F_LOGOUT = "logout";

//系统异常的forward名称
public static final String F_ERROR = "error";


/**
* 当前用户置于session中的属性名
*/
public static final String LOGIN_ACCOUNT = "sys.account";
/**
* 当前用户置于COOKIE中的属性名
*/
public static final String LOGIN_ACCOUNT_COOKIE = "sys.account";
/**
* 未登陆时得到用户id
*/
public static final String LOGIN_NA = Auth.ACCOUNT_NA;

/**
* 执行成功
*/
public static final String EXECUTE_OK = "1";




/**
* Action的入口方法
*/
public ActionForward execute(ActionMapping actionMapping,
ActionForm actionForm,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) {

ActionForward af = null;
PublicForm form = new PublicForm();
try {
//所有actionForm必须继承自 PublicForm

form = (PublicForm) actionForm;

//统一获取userId等公共信息
form.getCurrentDefine(actionMapping, httpServletRequest);

//获取当前资源代码
String currentResource = "-1";
try {
currentResource = actionMapping.findForward("resource").getPath();
}
catch (Exception ex4) {
}

//获取当前操作代码
String operator = "-1";
try {
operator = actionMapping.findForward("operator").getPath();
}
catch (Exception ex3) {
}

//获取当前是否进行权限判别的标志
String identify = "false";
try {
identify = actionMapping.findForward("identify").getPath();
}
catch (Exception ex2) {
}

String userId = form.getUserId();

//需要判别
if (!identify.equalsIgnoreCase("false")) {

// if (userId.equalsIgnoreCase(LOGIN_NA)) {
// httpServletResponse.sendRedirect("/error/error.jsp?errCode=1");
// }

this.setDebugPoint("权限鉴别...");
boolean flag = Auth.checkPrivilegeBySession(userId, currentResource,
operator, httpServletRequest.getSession());

if (!flag) {
throw new Exception("当前用户(" + userId + ")没有相应的权限:" +
currentResource + "@" + operator);
}

}
this.setDebugPoint("逻辑执行...");
af = performLogic(actionMapping, actionForm, httpServletRequest,
httpServletResponse);
this.setDebugPoint("逻辑执行结束.");
}
catch (Exception ex) {
httpServletRequest.setAttribute(SYS_EXCEPTION, ex);
httpServletRequest.setAttribute(SYS_MESG, ex);
getLogger().log(Level.SEVERE, getDebugPoint(), ex);

try {
LogItemMaster.create(null, ex.getMessage(), ex + "n" + getDebugPoint(),
LogItemMaster.LEVEL_WARNING,
"SYSTEM", form.getUserId(), new java.util.Date());
}
catch (Exception ex1) {
System.out.println(" LogItemMaster.create():" + ex1);
}
return actionMapping.findForward(F_ERROR);
}
return af;

}

/**
* 业务逻辑调用,所有子类必须实现此方法
*/
public ActionForward performLogic(ActionMapping actionMapping,
ActionForm actionForm,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws
Exception

{
return null;
}

/**
*
*/
public java.util.logging.Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(this.getClass().getName());
}
return logger;
}

public String getDebugPoint() {
return this.getClass().getName() + " ->_debug_Point: " +
debugPoint;
}

public void setDebugPoint(String debugPoint) {
this.debugPoint = debugPoint;
}

}

这个主题有 14 回复 / 1 页 [ ]

上一篇: jbuilder2005生成安装文件 下一篇: 在hibernate中复杂的检索策略让我..