今天看了包中的showcase例子,发现了一种新的配置action方法:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> < action name ="edit-*" class ="org.apache.struts2.showcase.action.EmployeeAction" >
< param name ="empId" > {1} </ param >
< result > /empmanager/editEmployee.jsp </ result >
< interceptor-ref name ="crudStack" >
< param name ="validation.excludeMethods" > execute </ param >
</ interceptor-ref >
</ action >
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> < action name ="BookAction" class ="com.sigon.crud.action.BookAction" >
< result type ="redirect" > List.action </ result >
</ action >
< action name ="Edit*" class ="com.sigon.crud.action.BookAction" method ="load" >
< param name ="isbn" > {1} </ param >
< result > Edit.jsp </ result >
</ action >
而在实际项目中,一个Action处理多个控制逻辑是家常便饭,如果还想用这种形式,就要在声明isbn时赋初值,本例中是
private String isbn = "2";
很明显,不稳妥。所以如何取舍,颇为困扰。
如果有哪位大侠有好的方法,敬请赐教。
Struts2的Preparable接口
Struts2的Action在实现com.opensymphony.xwork2.Preparable接口后,就可以重写prepare()方法
此时在Action中,prepare()方法的执行点是在:setXxx()和execute()的执行之前
比如需求:在执行Action的方法前,接收前台隐藏域传过来的值,再根据该值执行相应逻辑
如前台传过来ID,我们根据ID查找数据库对应的用户信息,再跳转到modify()中修改信息
但实际的运行过程中发现,通过Debug断点调试得知prepare()方法接收到的ID值是零
即前台隐藏域中的ID值没有传过来,事实上问题就出在默认的defaultStack拦截器栈上
其实defaultStack无法接收prepare()需要的数据,而应借助paramsPrepareParamsStack拦截器栈
事实上使用prepare拦截器之前,应先调用params拦截器,prepare()才能接收到表单数据
基于这个思路,于是可以通过各种手段将params拦截器放置在prepare拦截器之前即可
比如将defaultStack中的所有拦截器拷贝到struts.xml的我们自定义的myStack拦截器栈中
再按照paramsPrepareParamsStack拦截器栈中的params和prepare顺序修改二者位置即可
最近读starting struts2 online,里面有一节Move CRUD Operations into the same Action,提供了Move CRUD Operations into the same Action大概的sample,于是进行了补充,记录下来,以备使用。
一、思路
在这本书里,lan roughley提到在结合preparable和ModenDriven拦截器实现Move CRUD Operations into the same Action,采用通配符的方式为所有的crud只写一个action配置,当然,这也要求相关文件的命名和目录组织的时候要遵循一定的要求,示例如下:
<action name="**" 的形式似乎不行,不得以改成了"*_*"了,哈哈,要是能改成"^_^"就更好了
注:在struts.xml中增加<constant name="struts.enable.SlashesInActionNames" value="true" />,可以使用"*
}
PersonListAction.java
package com.work.action.person;
import java.util.List;
import com.work.action.BaseSupport;
import com.work.model.Person;
import com.work.service.PersonService;
public class PersonListAction extends BaseSupport {
}
paramsPrepareParamsStack
这里需要说一下关键的paramsPrepareParamsStack
下面是paramsPrepareParamsStack
An example of the params-prepare-params trick. This stack
This is useful for when you wish to apply parameters directly to an object that you wish to load externally (such as a DAO or database or service layer), but can't load that object
<interceptor-stack name="paramsPrepareParamsStack
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>
PersonServiceImpl.java
package com.work.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.work.model.Person;
public class PersonServiceImpl implements PersonService {
}
下面就是jsp文件了,就只贴部分了:edit.jsp:
<s:form action="Person_update.action" >
</s:form>
view.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>person view</title>
</head>
<body>
<s:actionerror />
<table>
</table>
<ul>
</ul>
</body>
</html>
三、总结
优点:适用与crud比较的应用程序,大幅减少action的配置信息
其他:
1、也可以不实现modeldriven接口,只不过要在jsp中加上model.properity
2、这种方式在某种程度上透露了action中的方法名称给客户端,是否会带来安全性的问题
使用场景:
如果action针对每次请求都要执行一些相同的业务逻辑, 那么可以实现Preparable接口, 将预处理业务逻辑写在prepare()方法里
Preparable 接口定义:
public interface Preparable {
void prepare() throws Exception;
}
prepare何时被执行:
prepare方法由PrepareInterceptor拦截器调用执行
com.opensymphony.xwork2.interceptor.PrepareInterceptor
public String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof Preparable) {
try {
String[] prefixes;
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
}
catch (InvocationTargetException e) {
// just in case there's an exception while doing reflection,
// we still want prepare() to be able to get called.
LOG.warn("an exception occured while trying to execute prefixed method", e);
}
catch (IllegalAccessException e) {
// just in case there's an exception while doing reflection,
// we still want prepare() to be able to get called.
LOG.warn("an exception occured while trying to execute prefixed method", e);
} catch (Exception e) {
// just in case there's an exception while doing reflection,
// we still want prepare() to be able to get called.
LOG.warn("an exception occured while trying to execute prefixed method", e);
}
// 必须执行或初始化的一些业务操作 action prepare()方法
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
使用方法:
使用basicStack拦截器栈
<action name="list" class="org.apache.struts2.showcase.action.SkillAction" method="list">
<result>/empmanager/listSkills.jsp</result>
<interceptor-ref name="basicStack" /> <!-- 使用basicStack拦截器栈, 该拦截器栈在 struts-default.xml 已配置, 包括了prepare -->
</action>
(注: struts-default.xml 里定义的 basicStack拦截器栈
<!-- Basic stack -->
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
)
或者直接指定prepare拦截器
<action name="list" class="org.apache.struts2.showcase.action.SkillAction" method="list">
<result>/empmanager/listSkills.jsp</result>
<interceptor-ref name="prepare" /> <!-- 直接指定prepare拦截器 -->
</action>