基于Struts2 Result Type为chain 的Action之间数据传递

合集下载

struts2中的action

struts2中的action

Action的数据4.3.1 数据来源在helloworld示例里面,在运行Action的execute方法的时候,你会神奇般的发现,Action的属性是有值的,而这正是Action进行请求处理所需要的数据。

那么,这些数据从何而来呢?很明显,这些数据就是你在登录页面填写的数据,换句话说,这些数据来源于用户请求对象,也就是request对象。

可是,Struts2怎么知道,页面上的值如何和Action的属性进行对应呢?这就涉及到如何把页面的数据和Action进行对应的问题了,接下来就来讨论页面的数据和Action的三种基本对应方式。

4.3.2 基本的数据对应方式在Struts2中,页面的数据和Action有两种基本对应方式,分别是:属性驱动(FieldDriven)和模型驱动(ModelDriven)。

属性驱动又有两种情况:一种是基本数据类型的属性对应;另外一种是JavaBean风格的属性对应。

为了区分它们,我们约定称呼如下:称呼“基本数据类型的属性对应”为属性驱动,而“JavaBean风格的属性对应”为直接使用域对象。

下面就分别来看看它们都什么意思,都如何实现。

1:属性驱动FieldDriven(基本数据类型的属性对应)基本数据类型的属性对应,就是web页面上要提交的html控件的name属性,和Action的属性或者与属性相应的getter/setter相对应,这种做法就是基本数据类型的属性对应的属性驱动。

事实上,我们已经使用过这种方式了,前面HelloWorld示例,就是采用的这种方式来把值对应到Action中的。

比如在登录页面上,我们是这么写的:java代码:查看复制到剪贴板打印1.<form action="/helloworld/helloworldAction.action" method="post">2. <input type="hidden" name="submitFlag" value="login"/>3.账号:<input type="text" name="account"><br>4.密码:<input type="password" name="password"><br>5. <input type="submit" value="提交">6.</form>在Action中是这么写的:java代码:查看复制到剪贴板打印1.public class HelloWorldAction extends ActionSupport {2.private String account;3.private String password;5.public String getAccount() {6.return account;7. }8.public void setAccount(String account) {9.this.account = account;10. }11.public String getPassword() {12.return password;13. }14.public void setPassword(String password) {15.this.password = password;16. }17.public String getSubmitFlag() {18.return submitFlag;19. }20.public void setSubmitFlag(String submitFlag) {21.this.submitFlag = submitFlag;22. }23.//其他部分暂时省略掉,好让大家看清楚数据的对应关系24.}你会发现,在页面上input的name属性,和Action的属性是同一个名称,这样一来,当页面提交的时候,Struts2会自动从request对象里面把数据取出来,然后按照名称进行对应,自动设置到Action的属性里面去。

struts2 strus.xml中result类型及含义

struts2 strus.xml中result类型及含义

struts2strus.xml中result类型及含义一个提交到服务器的处理通常可以分为两个阶段,第一个阶段查询服务器状态(查询或者更新数据库),第二个阶段选择一个合适的结果页面其返回给用户(这里要讲的Result的内容)。

Struts2提供了对不同种类返回结果的支持,常见的有JSP,FreeMarker,Velocity等。

Struts2支持的不同类型的返回结果为:名字说明Chain Result用来处理Action链Dispatcher Result用来转向页面,通常处理JSPFreeMarker Result处理FreeMarker模板HttpHeader Result用来控制特殊的Http行为Redirect Result重定向到一个URLRedirect Action Result重定向到一个ActionStream Result向浏览器发送InputSream对象,通常用来处理文件下载Velocity Result处理Velocity模板XLS Result处理XML/XLST模板PlainText Result显示原始文件内容,例如文件源代码结合Tile使用S2PLUGINS:TilesResult另外第三方的Result类型还包括JasperReports Plugin,专门用来处理JasperReport类型的报表输出。

在struts-default.xml文件中已经有了对于所有类型Result的定义:<result-types><result-type name="chain"class="com.opensymphony.xwork2.ActionChai nResult"/><result-type name="dispatcher"class="org.apache.struts2.dispatcher.Serv letDispatcherResult"default="true"/><result-type name="freemarker"class="org.apache.struts2.views.freemarke r.FreemarkerResult"/><result-type name="httpheader"class="org.apache.struts2.dispatcher.Http HeaderResult"/><result-type name="redirect"class="org.apache.struts2.dispatcher.Serv letRedirectResult"/><result-type name="redirectAction"class="org.apache.struts2.dispatcher.Serv letActionRedirectResult"/><result-type name="stream"class="org.apache.struts2.dispatcher.Stre amResult"/><result-type name="velocity"class="org.apache.struts2.dispatcher.Velo cityResult"/><result-type name="xslt"class="org.apache.struts2.views.xslt.XSLT Result"/><result-type name="plainText"class="org.apache.struts2.dispatcher.Plai nTextResult"/><!--Deprecated name form scheduled for removal in Struts 2.1.0.The camelCase versions are preferred.See ww-1707--><result-type name="redirect-action"class="org.apache.struts2.dispatcher.Serv letActionRedirectResult"/><result-type name="plaintext"class="org.apache.struts2.dispatcher.Plai nTextResult"/></result-types>从上述代码中可以看出在不指定Result类型的时候使用dispatcher类型。

struts2 从一个action 跳转到另一个action的两种方法

struts2 从一个action 跳转到另一个action的两种方法

从action1直接跳转到action2,有两种方法:1. 需要保存前一个action的属性信息时使用,保存住action1的request对象:<result type= "chain " name="a2">action2</result>2. 不保存前一个action的参数可以用这种方法:<result type= "redirectAction "> action2</result>Struts.xmlJava代码1.<?xml version="1.0" encoding="UTF-8" ?>2.<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD StrutsConfiguration 2.1//EN""/dtds/struts-2.1.dtd">3.<struts>4.5.<!--一个action跳转到另一个action 跳转方式为chain 会保留request对象redirectAction 则不能保留-->6.<package name="limin"extends="struts-default">7.<action name="sa1_*"class="com.Action.StrAction1" method="{1}">8.<!--<result type="chain" name="sa2">sa2_sa2</result> -->9.<result type="redirectAction" name="sa2">sa2_sa2</result>10.</action>11.12.<action name="sa2_*"class="com.Action.StrAction2" method="{1}">13.<result>/index.jsp</result>14.</action>15.</package>16.17.</struts>[java]view plain copyprint?1.<?xml version="1.0" encoding="UTF-8" ?>2.<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN""http://stru /dtds/struts-2.1.dtd">3.<struts>4.5.<!--一个action跳转到另一个action 跳转方式为chain 会保留request对象 redirectAction 则不能保留-->6.<package name="limin"extends="struts-default">7.<action name="sa1_*"class="com.Action.StrAction1" method="{1}">8.<!--<result type="chain" name="sa2">sa2_sa2</result> -->9.<result type="redirectAction" name="sa2">sa2_sa2</result>10.</action>11.12.<action name="sa2_*"class="com.Action.StrAction2" method="{1}">13.<result>/index.jsp</result>14.</action>15.</package>16.17.</struts>action1Java代码1.public class StrAction1 {2. String a ="liminhappygirl";3.public String getA() {4.return a;5. }6.public void setA(String a) {7.this.a = a;8. }9.public String sa1() {10. HttpServletRequest request = (HttpServletRequest)ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);11. request.setAttribute("limin", "happygirl");12. System.out.println("sal已经执行");13.return"sa2";14. }15.16.}[java]view plain copyprint?1.public class StrAction1 {2. String a ="liminhappygirl";3.public String getA() {4.return a;5. }6.public void setA(String a) {7.this.a = a;8. }9.public String sa1() {10. HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);11. request.setAttribute("limin", "happygirl");12. System.out.println("sal已经执行");13.return"sa2";14. }15.16.}action2Java代码1.public class StrAction2 {2.public String sa2() {3. HttpServletRequest request = (HttpServletRequest)ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);4.//当type="chain" 时能保存住request对象5. System.out.println(request.getAttribute("limin"));6.return Action.SUCCESS;7. }8.}[java]view plain copyprint?1.public class StrAction2 {2.public String sa2() {3. HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);4.//当type="chain" 时能保存住request对象5. System.out.println(request.getAttribute("limin"));6.return Action.SUCCESS;7. }8.}。

struts2中使用注解配置Action方法详解

struts2中使用注解配置Action方法详解

struts2中使⽤注解配置Action⽅法详解使⽤注解来配置Action可以实现零配置,零配置将从基于纯XML的配置转化为基于注解的配置。

使⽤注解,可以在⼤多数情况下避免使⽤struts.xml⽂件来进⾏配置。

struts2框架提供了四个与Action相关的注解类型,分别为ParentPackage、Namespace、Result和Action。

ParentPackage:ParentPackage注解⽤于指定Action所在的包要继承的⽗包。

该注解只有⼀个value参数。

⽤于指定要继承的⽗包。

⽰例:使⽤ParentPackage注解,其value值为mypackage,表⽰所在的Action需要继承mypackage包,@ParentPackage(value="mypackage")public class UserAction extends ActionSupport{}如果注解中只有⼀个value参数值,或者其他参数值都使⽤默认值时,则可以对value参数设置进⾏简写,⽐如上述的代码:@ParentPackage("mypackage")public class UserAction extends ActionSupport{}把struts2-convention-pligin-2.x.x.jar包导⼊到web应⽤中,才能在Action类中使⽤注解。

Namespace:Namespace注解⽤于指定Action所在的包的命名空间。

该注解只有⼀个value参数,⽤于指定ACtion所属于的命名空间。

当使⽤Namespace注解时,在为命名空间取名需要使⽤斜杠(/)开头。

使⽤Namespace注解,指定其Action所在的包的命名空间为/user:@Namespace("/user")public class UserAction extends ActionSupport{}Result:Result注解⽤于定义⼀个Result映射,该注解包含四个参数,1)name:可选参数,⽤于指定Result的逻辑名,默认值为success2)location:必选参数,⽤于指定Result对应资源的URL3)type:可选参数,⽤于指定Result的类型,默认值为NullResult.class4)params:可选参数,⽤于为Result指定要传递的参数,格式为:{key1,value1,key2,value2,...}如果type参数的值为NullResult.class,那么struts2框架在解析Result配置时,会使⽤默认的结果类型(即ServletDispatcherResult)来替换NullResult。

Struts2配置Result

Struts2配置Result

配置Result一个result代表了一个可能的输出。

当一个Action类的方法执行完成时,它返回一个字符串类型的结果码,框架根据这个结果码选择对应的result,向用户输出。

Results配置由两部分组成:一部分是result映射,另一部分是result类型。

1.结果映射在struts.xml文件中,使用result元素来配置result映射。

result元素有两个可选的属性:在Struts2中允许定义一个默认的Result类型,这是通过result-type元素来定义的。

在框架的默认配置文件struts-default.xml中,在struts-default.xml包中有如下的一个配置:<result-types><result-type name="dispatcher"class="org.apache.struts2.dispatcher.ServletDispatcherResult"default="true"/></result-types>result-type元素的default属性指定名为dispatcher的结果类型,dispatcher结果类型使用ServletAPI中的ResultDispatcher将请求导向到目标资源(通常是JSP页面)。

如果在使用result元素配置result映射时,没有使用type类型,那么框架就将使用默认的dispatcher类型。

由于Struts2中的包是可以继承的,所以我们定义的package只要继承了struts-default包,因此也继承了默认的结果类型,所以可以省略result元素的type属性。

如果没有指定result元素的name属性,那么框架将把它命名为”success”。

2.结果类型在框架调用Action对请求进行处理之后,就要向用户呈现一个结果视图,Struts2支持多种类型的视图,这些视图是由不同的结果类型来管理的。

Struts2中 struts.xml的Action配置详解

Struts2中 struts.xml的Action配置详解

Struts2中struts.xml的Action配置详解使用package可以将逻辑上相关的一组Action,Result,Interceptor等组件分为一组,Package 有些像对象,可以继承其他的Package,也可以被其他package继承,甚至可以定义抽象的Package。

由于struts.xml文件是自上而下解析的,所以被继承的package要放在继承package的前边。

Namespace将action分成逻辑上的不同模块,每一个模块有自己独立的前缀。

使用name space可以有效的避免action重名的冲突,例如每一个package都可以有自己独立的Men u和Help action,但是事项方式各有不同。

Struts2标签带有namespace选项,可以根据namespace的不同向服务器提交不同的package的action的请求。

“/”表示根namespace,所有直接在应用程序上下文环境下的请求(Context)都在这个pa ckage中查找。

“”表示默认namespace,当所有的namespace中都找不到的时候就在这个namespace中寻找。

例如,有如下配置:CODE:<package name="default"><action name="foo" class="mypackage.simpleAction><result name="success" type="dispatcher">greeting.jsp</result></action><action name="bar" class="mypackage.simpleAction"><result name="success" type="dispatcher">bar1.jsp</result></action></package><package name="mypackage1" namespace="/"><action name="moo" class="mypackage.simpleAction"><result name="success" type="dispatcher">moo.jsp</result></action></package><package name="mypackage2" namespace="/barspace"><action name="bar" class="mypackage.simpleAction"><result name="success" type="dispatcher">bar2.jsp</result></action></package>1 如果请求为/barspace/bar.action查找namespace:/barspace,如果找到bar则执行对应的action,否则将会查找默认的n amespace,在上面的例子中,在barspace中存在名字为bar的action,所以这个action 将会被执行,如果返回结果为success,则画面将定为到bar2.jsp2 如果请求为/moo.action根namespace('/')被查找,如果moo action存在则执行,否则查询默认的namespace,上面的例子中,根namespace中存在moo action,所以该action被调用,返回success 的情况下画面将定位到moo.jsp、Action配置在struts2框架中每一个Action是一个工作单元。

Struts2 两个Action之间动态传参数

Struts2 两个Action之间动态传参数

两个Action 动态传参数研究了近两天的时间,终于把一个很简单的问题给搞定了,那它是什么问题呢?就是Struts2的两个Action之间传参的问题。

需求功能是这样:Action1 获取数据库配置内容,得到相应Model的动态URL ,这里的URL 有的是Action有的是JSP页面。

1.使用result 类型中的redirect 类型,如下:<result name="success" type="redirect">${dynamic Url}?objectId=${obj ectId}&param1=${param1}</result>这样传参才能达到Action取参数的需要,如果要是加上:<param name="param1">${param1}</param><param nam e="item s">${item s}</param>那么param1 和item s 这两个参数都无法从目标Action里得到,如果想得到的话只能用objectId=${objectId}&param1=${param1} 这种方式,或者用session来实现,这样就有点复杂了,而且使用起来也相当的不方便。

后来又尝试了第二种方式:2.使用result类型中的redirect-action类型如下:<result nam e="success" type="redirect-action"><param name="actionName">${actionName}</param><param name="namespace">${namespace}</param></result>此时,result之间不能再设其它的自定义的参数了,因为redirect-action对应的是org.apache.struts2.dispatcher.ServletActionRedirectResult ,而actionName和name space是它的两个属性,还有一个重要属性就是methodName,如果要再加其它自己定的参数,只能扩展该类了。

struts2中的result的type类型

struts2中的result的type类型
<param name="charSet">字符规范(如GBK)</param>
</result>
缺点:redirect把一个http返回码(SUCCESS)以及返回的页面位置一起重新发给web服务器,容纳后由web服务器产生一个新的HTTP请求,就会产生一个新的线程,保存在原来Action执行的线程中的数据就无法访问。
所以,result需要包含Action的数据,那么redirect不是一个可行的办法。因为新的HTTP请求时在Servlet容器的新的线程中处理的,ActionContext中的所有状态都不会存在。
struts2 跳转类型 result type=chain、dispatcher、redirect(redirect-action)
dispatcher 为默认跳转类型,用于返回一个视图资源(如:jsp)
Xml代码 :
<result name="success">/main.jsp</result>
<result name="success" type="chain">step2.action</result>
</action>
<action name="step2" class="test.Step2Action">
<result name="success">finish.jsp</result>
Xml代码:
<result name="err" type="redirect-action">
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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去传递。

例如:<result type="redirectAction" name="toSecond"><param name="actionName">SecondAction</param><param name="method">execute</param><param name="user">${user}</param></result>但这样做的缺点是,1.我们要在浏览器上看到很长很乱的URL(如果超过URL长度限制那就更悲剧了)。

2.暴露这些参数总感觉很不爽。

3.自定义的对象不能用这种方式传递,要么传String、或JsonObject等。

另外一个解决办法:因为Result type为chain时,在执行SecondAction时,它的上一个Action,也就是FirstAction的实例并没有被销毁,FirstAction的实例被加入到了ValueStack中。

所以,实现的思路就是,增加一个拦截器,在执行Actioin前判断一下,当前Action是否需要从前面的Action实例中获取数据。

这个可以通过注解的方式告诉拦截器,当前的action需要什么样的对象。

思路明确了,来看看代码:注解类:ChainTransParam.javaimport ng.annotation.Documented;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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;@Overridepublic 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;// 取得最近的前置ActionObject 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();// 按顺序遍历前置Actionfor (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{@ChainTransParamprivate CustomUser user = null;public String execute() throws Exception {// 利用user做事情或显示在页面上}// getter setter}当在执行SecondAction之前,拦截器会去查找FirstAction,是否有user 对象,有则将值拷贝到SecondAction 中。

ChainTransParam 注解允许输入参数名,没有输入则默认根据变量名去查找。

注:Struts2 Reference里的意思是不提倡使用Result Type Chain。

另:ReflectionUtils.java 实现:import ng.reflect.Field;import ng.reflect.InvocationTargetException;import ng.reflect.Method;import ng.StringUtils;import mons.logging.Log;import 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;}}。

相关文档
最新文档