chain:基本用途是构造成一条动作链。前一个Action将控制权转交给后一个Action,而前一个Action的状态在后一个Action里仍然保持着。
我现在有一个场景,FirstAction 通过chain的方式,将控制权交给SecondAction。FirstAction对应的页面代码为first.ftl,SecondAction对应的页面代码为second.ftl。
假设我们的FirstAction如下定义:
public class SecondAction extends ActionSupport{
private CustomUser user = null;
public String execute() throws Exception {
// 利用user做事情或显示在页面上
}
// getter setter
}
意思很明确了,通过first.ftl的输入,到DB中或其他,生成了我们的CustomUser对象,这个CustomUser对象将要在SecondAction使用。
于是我们想到了要配置FirstAction 的name为toSecond的Result type为chain,将生成的CustomUser对象传递到SecondAction中,
我们也这样做了,但是经过调试,发现在SecondAction中没有得到FirstAction中的CustomUser对象。
SecondAction是这样实现的:
public class SecondAction extends ActionSupport{
private CustomUser user = null;
public String execute() throws Exception {
// 利用user做事情或显示在页面上
}
// getter setter
}
看一下ChainingInterceptor.java的实现,发现有这样的注释:
An interceptor that copies all the properties of every object in the value stack to t he currently executing object.
在FirstAction 中CustomUser user 并没有在value stack 中,所以没有拷贝到SecondAction中。
知道了问题所在,就要解决。首先是想换一种方式去做,将我们要传递的参数通过其他Result type 如redirectAction去传递。
例如:
SecondAction
execute
${user}
但这样做的缺点是,
1.我们要在浏览器上看到很长很乱的URL(如果超过URL长度限制那就更悲剧了)。
2.暴露这些参数总感觉很不爽。
3.自定义的对象不能用这种方式传递,要么传String、或JsonObject等。
另外一个解决办法:
因为Result type为chain时,在执行SecondAction时,它的上一个Action,也就是FirstAction的实例并没有被销毁,FirstAction的实例被加入到了ValueStack中。
所以,实现的思路就是,增加一个拦截器,在执行Actioin前判断一下,当前Action是否需要从前面的Action实例中获取数据。
这个可以通过注解的方式告诉拦截器,当前的action需要什么样的对象。
思路明确了,来看看代码:
注解类:ChainTransParam.java
import https://www.wendangku.net/doc/0a15684589.html,ng.annotation.Documented;
import https://www.wendangku.net/doc/0a15684589.html,ng.annotation.ElementType;
import https://www.wendangku.net/doc/0a15684589.html,ng.annotation.Retention;
import https://www.wendangku.net/doc/0a15684589.html,ng.annotation.RetentionPolicy;
import https://www.wendangku.net/doc/0a15684589.html,ng.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChainTransParam {
String fieldName() default "";
}
拦截器实现:ChainParameterInterceptor.java
/**
* Result type 为chain时可通过注解的方式实现参数传递此参数为前置Action的成员变量、并提供getter方法
* 此参数并不要求一定要在值栈中
*
* @author liming
*/
public class ChainParameterInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = -8279316685527646358L;
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ValueStack stack = invocation.getStack();
CompoundRoot root = stack.getRoot();
// 值栈不为null 且已经有前置Action
// 栈最顶层(index = 0)为当前Action、紧接着(index = 1) 为前置Action if (root == null || root.size() <= 2) {
return invocation.invoke();
}
// 当前Action对象
Object target = invocation.getAction();
Field[] fields = target.getClass().getDeclaredFields();
// 遍历此Action对象的属性是否有RecieveData注解
for (Field field : fields) {
if (field.isAnnotationPresent(ChainTransParam.class)) {
ChainTransParam rData = field.getAnnotation(ChainTransParam.clas s);
// 取得源数据字段名
String fromName = rData.fieldName();
fromName = StringUtils.isEmpty(fromName) ? field.getName() : fro mName;
// 取得最近的前置Action
Object srcAction = root.get(1);
// 取得对应字段的值
Object value = ReflectionUtils.getFieldValue(srcAction, srcAction.get Class(), field.getName());
// 设定值
ReflectionUtils.setFieldValue(target, field.getName(), field.getType (), value);
}
}
return invocation.invoke();
}
@SuppressWarnings("unused")
private Object findFieldValue(CompoundRoot root, Field field) {
Object value = null;
int size = root.size();
// 按顺序遍历前置Action
for (int index = 1; index < size; index++) {
Object srcAction = root.get(index);
Object tmp = ReflectionUtils.getFieldValue(srcAction, srcAction.getClass
(), field.getName());
// 取得对应字段的值则返回
// 问题:如果前置Action中该字段本身就为null 则无法处理
if (tmp != null) {
break;
}
}
return value;
}
}
在拦截器的实现中,我是只取得前一个Action中的数据,并没有迭代寻找整个ValueStack的Action,也是可以这样实现的,请看我的findFieldValue方法的实现,但这个方法在此拦截器中并没有使用上。因为我不想这样做。
代码完毕之后,配置好拦截器,
我们只要在SecondAction中这样定义即可:
public class SecondAction extends ActionSupport{
@ChainTransParam
private CustomUser user = null;
public String execute() throws Exception {
// 利用user做事情或显示在页面上
}
// getter setter
}
当在执行SecondAction之前,拦截器会去查找FirstAction,是否有user 对象,有则将值拷贝到SecondAction 中。
ChainTransParam 注解允许输入参数名,没有输入则默认根据变量名去查找。
注:Struts2 Reference里的意思是不提倡使用Result Type Chain。
另:ReflectionUtils.java 实现:
import https://www.wendangku.net/doc/0a15684589.html,ng.reflect.Field;
import https://www.wendangku.net/doc/0a15684589.html,ng.reflect.InvocationTargetException;
import https://www.wendangku.net/doc/0a15684589.html,ng.reflect.Method;
import https://www.wendangku.net/doc/0a15684589.html,ng.StringUtils;
import https://www.wendangku.net/doc/0a15684589.html,mons.logging.Log;
import https://www.wendangku.net/doc/0a15684589.html,mons.logging.LogFactory;
public abstract class ReflectionUtils {
private static final Log logger = LogFactory.getLog(ReflectionUtils.class);
public static void setFieldValue(Object target, String fname, Class> ftyp e, Object fvalue) {
setFieldValue(target, target.getClass(), fname, ftype, fvalue);
}
public static void setFieldValue(Object target, Class> clazz, String fnam e, Class> ftype, Object fvalue) {
if (target == null || fname == null || "".equals(fname)
|| (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass()))) { return;
}
try {
Method method = clazz.getDeclaredMethod(
"set" + Character.toUpperCase(fname.charAt(0)) + fname.substri ng(1), ftype);
//if (!Modifier.isPublic(method.getModifiers())) {
method.setAccessible(true);
//}
method.invoke(target, fvalue);
}
catch (Exception me) {
if (logger.isDebugEnabled()) {
logger.debug(me);
}
try {
Field field = clazz.getDeclaredField(fname);
//if (!Modifier.isPublic(field.getModifiers())) {
field.setAccessible(true);
//}
field.set(target, fvalue);
}
catch (Exception fe) {
if (logger.isDebugEnabled()) {
logger.debug(fe);
}
}
}
}
public static Object getFieldValue(Object target, String fname) {
return getFieldValue(target, target.getClass(), fname);
}
public static Object getFieldValue(Object target, Class> clazz, String fna me) {
if (target == null || fname == null || "".equals(fname)) {
return null;
}
boolean exCatched = false;
try {
String methodname = "get" + StringUtils.capitalize(fname);
Method method = clazz.getDeclaredMethod(methodname);
//if (!Modifier.isPublic(method.getModifiers())) { method.setAccessible(true);
//}
return method.invoke(target);
}
catch (NoSuchMethodException e) {
exCatched = true;
}
catch (InvocationTargetException e) {
exCatched = true;
}
catch (IllegalAccessException e) {
exCatched = true;
}
if (exCatched) {
try {
Field field = clazz.getDeclaredField(fname);
//if (!Modifier.isPublic(field.getModifiers())) { field.setAccessible(true);
//}
return field.get(target);
}
catch (Exception fe) {
if (logger.isDebugEnabled()) {
logger.debug(fe);
}
}
}
return null;
}
}
2012年第11卷第6期 产业与科技论坛2012.(11).6 Industrial &Science Tribune Struts2框架工作原理及应用体会 □宋 君 张家爱 【摘要】通过针对特定用户的分析,搭建以Struts2为技术核心的旅行社管理系统。本文简单的介绍了MVC 、 Struts2的工作原理,同时总结了在项目制作过程中所得到的心得。 【关键词】 Struts2;MVC ;FilterDispatcher ;Action 【基金项目】本文为大学生科技创新院级基金项目(编号:2011070)成果 【作者单位】宋君,吉林农业科技学院信息工程学院;张家爱,吉林农业科技学院信息工程学院教师 本着锻炼自我与积极参与到实用性技术的目标,以发掘自身创新意识为前提。利用空闲时间,在老师的指导下,进行了一次大学生创新项目的实践性活动。本着实用原则,以某中小旅行社为客户(根据用户需求,匿名),以Struts2框架为基点,进行了一次旅行社管理系统的开发。在项目结束之余, 特将在项目过程中经历的种种认识进行了简单的总结,希望让阅读本文的朋友们,更多的参与到此类活动中。 一、基础思想— ——MVC 简述作为时下经典框架之一, MVC 具有其独特的价值。MVC 框架简单的说,就是将数据模型与用户视图进行分离。通过控制器进行协调处理的一种结构是框架。同时,也是本文中要讨论的Sturts2框架的基础思想。 M 是指模型层(Model ),V 是指用户视图(View ),C 则是指控制器 (Controller )。这种划分方式是以将模型层与视图层进行代码分离,从而降低两者之间的耦合性,使同一程序可以使用不同形式进行表现。不同层之间的修改不会或尽量少的印象到其他层功能的史前为前提。有效的提高的代码的维护性和设计难度。 图1 二、 Struts2工作原理(一)Struts2框架组成。Struts2框架由三个主要部分组成:核心控制器、业务控制器,以及由用户实现的业务逻辑组件。这里我们将侧重于核心控制器与业务控制器的理解与说明。 (二)核心控制器:FilterDispatcher 。FilterDispatcher 是Struts2框架的核心控制器,在此,我们可以将FilterDispatcher 看作一个类似于过滤网的过滤器。当用户发出请求,并到达Web 硬哟那种时,该过滤器会过滤用户请求。如果用户请求的结尾为action ,则将该请求转入Struts2框架进行处理。当Struts2框架获得了*.actio 请求后,会根据请求前面“*”的那部分内容,决定调用哪个业务逻辑组件作为响应单位。这里需要说明的是Struts2用来处理用户请求的Action 实例并不是业务控制器,而是作为Action 的代理———正因为Struts2的一大特点,与Servlet API 的非耦合性,使得用户实现的业务控制器无法直接处理用户请求。有效的提高了后期调试维护的效率。而Struts2框架再次提供了了一系列的拦截器。这些拦截器负责将HttpServletRequest 请求的参数解析出来,传入Action 中,并毁掉Action 的Execute 方法来处理用户请求。用户实现的Action 类仅作为Struts2的Action 代理的代理目标。用户实现的业务控制器则包含了对用户请求的处理。用户的请求数据包含在HttpServletRequest 对象中,而用户的Action 类无需访问HttpServletRequest 对象。拦截器负责将HttpServletRequest 里的请求数据解析出来,并传给业务逻辑组件Action 实例。 (三)业务控制器。业务控制器就是前文提到的用来实现用户Action 的实力,这里的每个Action 类通常包含有一个execute 方法,当业务控制器处理完用户的请求后,该方法将会针对此次处理返回一个字符串— ——该字符串就是一个逻辑树图名。当程序开发人员开发出系统所需要的业务控制器后,还需要针对性的配置Struts2的Action ,即需要配置Ac- tion 的以下三个部分:(1)Action 所处理的URl 。(2)Action 组件所对应的实现类。(3)Action 里包含的逻辑试图和物理资源之间的对应关系。每个Action 都要处理一个用户请求,而用户请求则总是包含有指定的URL 。当核心控制器过滤用户请求,并调用后,根据请求的URL 和Action 处理URL 之间的对应关系来处理转发。 · 342·
Struts 2作业 1.简述什么是MVC? 答:MVC 的全称为model-view-controller(模型-视图-控制器)。MVC 是一种开发应用程序的模式,这个模式已经具有了很好的框架架构,并且十分容易维护。使用MVC 开发出来的应用程序一般包括以下几块内容:·控制器(Controller):控制器类处理客户端向Web 应用程序发出的请求,获取数据,并指定返回给客户端,用来显示处理结果的视图。·模型(Model):模型类代表了应用程序的数据,这些数据通常具有一个数据验证逻辑,用来使得这些数据必须符合业务逻辑。·视图(View):视图类是Web 应用程序中用来生成并显示HTML 格式的服务器端对客户端请求的响应结果的模板文件 2.Struts 2以(WebWork)为核心,采用(拦截器)的机制来处理用户的 请求。 3.简述一个请求在Struts 2框架中的处理流程,请按自己对框架的理解叙述。答:1-用户提交自己的请求;2-由web.xml拦截,转发到action进行处理;3- Struts.xml根据相应的action配置,调用相应的方法来处理,并根据结果转发到不同的页面。 4.不属于Action接口中定义的字符串常量是( B )? A)SUCCESS B)FAILURE C)ERROR D)INPUT 5.资源文件的后缀名为(D)? A)txt B)doc C)property D)properties 6.在JSP页面中可以通过Struts 2提供的(D)标签来输出国际化信息。 A)
第一章Struts2的起源和发展 说到网络应用很难让人不联想到网络信息的浏览,自从Internet进入民用领域之后,上网成为了越来越多的人闲暇时光的消磨手法。于是网络系统的开发也变得越来越总要。 1.1 Web技术的发展 随着Internet技术的大面积应用和发展,传统的静态HTML页面由于缺乏足够的用户交互能力已经无法满足日益膨胀的网络需求。人们希望Web应用中能够包含更多的动态交互功能,于是为了应对拥有更广泛用户群的动态Web开发,软件开发商分别推出的ASP和JSP两款动态网站开发解决方案。但是当时的JSP 开发并没有很科学的层次设计,最初的JSP开发中逻辑代码和前端代码杂合在一起。虽然在最初开发时这样的做法使得开发非常的容易,然而随着Web系统的使用越来越广泛,应用规模的日益增长,如果继续使用传统的简单的JSP + Servlet 结构进行Web系统的开发,则会由于系统层次混乱而导致系统的开发难度和维护成本越来越大,最终使开发过程陷入困境。 1.2 MVC思想进入Web系统开发 面对开发过程中所出现的困难,开发者们试图寻找一种能够使得开发结构更加具有条理性的开发模式。根据以往面向对象系统设计的经验,开发者开始将MVC开发模式引入Web系统的开发。MVC模式将一个应用分为三个基本部分:Model(模型)、View(视图)、Controller(控制器)。在此模式中触发事件由控制器捕获,并根据事件的类型来改变模型和视图。这样既可将系统模型与视图分离,从而使各部分能够工作在最小的耦合状态下协同工作,从来提高系统的扩展性和可维护性。将其引入Web系统开发后,系统模式由传统的JSP完成用户请求和响应改变为由控制器捕获用户请求,JavaBean完成模型操作,而JSP专门负责响应用户需求。老一代的开发框架Struts1便是这时的产物。
Struts2中数据标签使用示例 S truts2提供了大量丰富的标签供使用,它不再像S truts1中一样,将种类标签进行分门列别,但可以根据其使用的用途用以区别。本文通过对S truts2中数据标签的学习,来对S truts2中标签的学习起到一个抛砖引玉的作用。 文中将介绍Action标签、Bean标签、Data标签、Include标签、P aram标签、Set标签、T ext标签、P roperty 标签等标签。 代码下载:https://www.wendangku.net/doc/0a15684589.html,/y1ps2Mjpc3NiLKuetMOpCsZOOypD6KSdo8-46Zy2wpoMcABeo4vOC NJXtWDEO93-TXgZogwAF YxSOni5BEG2EoN65OFwHdG71v-/St ruts2DataTags.rar?download 一、