Struts2如何实现两个Action类之间的对象数组值传递
开发过程中需要在两个Struts2 Action类之间传递自定义对象数组,请求流转路径为 Try1.java --> first.jsp --> Try2.java,但实际运行时Try2.java中始终无法获取到目标对象数组,取值结果恒为null。
涉及的项目代码如下:
User.java
package com.sham; public class User { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Try1.java
package com.sham; import java.util.ArrayList; import com.opensymphony.xwork2.ActionSupport; public class Try1 extends ActionSupport{ ArrayList<User> list=new ArrayList<User>(); public ArrayList<User> getList() { return list; } public void setList(ArrayList<User> list) { this.list = list; } public String execute(){ User user1=new User(); user1.setId(123); user1.setName("John"); list.add(user1); User user2=new User(); user2.setId(345); user2.setName("Jen"); list.add(user2); System.out.println("List " + list); return "success"; } }
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> <package name="default" extends="struts-default"> <action name="click" class="com.sham.Try1" > <result name="success">first.jsp</result> </action> <action name="next" class="com.sham.Try2" > <result name="success">second.jsp</result> </action> </package> </struts>
first.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <s:form action="next"> Hello <s:submit value="submit"/> </s:form> </body> </html>
Try2.java
package com.sham; import java.util.ArrayList; import com.opensymphony.xwork2.ActionSupport; public class Try2 extends ActionSupport { ArrayList<User> list; public ArrayList<User> getList() { return list; } public void setList(ArrayList<User> list) { this.list = list; } public String execute(){ System.out.println("List from Action class 2 " + getList()); return "success"; } }
点击first.jsp的提交按钮流转到Try2.java时,调用getList()返回值始终为null。已知普通类型传值时,给属性配置getter/setter配合隐藏域即可实现Action间传值,但对象数组场景下该方案不生效,需要实现Try1中存储的包含user1、user2的对象数组完整传递到Try2。
Struts2的Action是多例模式,每次请求对应一个全新的Action实例,请求生命周期结束后,当前Action存储的属性就会被回收。现有代码存在三个核心问题:
- Try1跳转至first.jsp时,list仅存在于当前请求的值栈中,响应返回客户端后本次请求的数据就会被销毁
- first.jsp的提交表单中没有携带任何和list相关的请求参数,提交到Try2时没有对应数据源,自然只能拿到null
- HTTP请求参数本质都是字符串,无法直接传递Java对象,不能把整个List对象直接塞到单个隐藏域里,必须按照Struts2的参数绑定规则拆分参数。你之前了解的「getter/setter+隐藏域」方案本身可行,只是没有针对对象数组做正确的参数配置。
根据不同的业务场景,可以选择以下三种实现方式:
方案1:表单隐藏域传值(最匹配当前交互流程)
不需要修改Action和struts.xml核心逻辑,只需要修改first.jsp,遍历页面拿到的list,按照list[下标].属性名的命名规则,给每个User对象的属性添加隐藏域。表单提交时Struts2会自动把这些参数封装成ArrayList<User>,注入到Try2的list属性中。
修改后的first.jsp代码:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <s:form action="next"> Hello <!-- 遍历list,按索引为每个对象的属性添加隐藏域 --> <s:iterator value="list" status="index"> <s:hidden name="list[%{#index.index}].id" value="%{id}"/> <s:hidden name="list[%{#index.index}].name" value="%{name}"/> </s:iterator> <s:submit value="submit"/> </s:form> </body> </html>
注意:这个方案要求自定义对象类必须有无参构造方法(现有User类没有写自定义构造,JVM会自动生成无参构造,满足要求),且所有需要传递的属性都有对应的getter/setter,现有User类的写法符合要求。
方案2:Session域暂存数据
如果对象数组元素多、属性复杂,全放到隐藏域会增大页面体积和请求传输量,可以在Try1处理完逻辑后把list存入Session域,Try2中直接从Session取值即可,取完记得手动移除,避免不必要的内存占用。
修改Try1的execute方法,存入Session:
// 先引入依赖包:import org.apache.struts2.ServletActionContext; public String execute(){ User user1=new User(); user1.setId(123); user1.setName("John"); list.add(user1); User user2=new User(); user2.setId(345); user2.setName("Jen"); list.add(user2); System.out.println("List " + list); // 将list存入Session ServletActionContext.getRequest().getSession().setAttribute("list", list); return "success"; }
修改Try2的execute方法,从Session取值:
// 先引入依赖包:import org.apache.struts2.ServletActionContext; public String execute(){ // 从Session取出list list = (ArrayList<User>) ServletActionContext.getRequest().getSession().getAttribute("list"); // 取完立刻移除,避免内存泄漏 ServletActionContext.getRequest().getSession().removeAttribute("list"); System.out.println("List from Action class 2 " + getList()); return "success"; }
方案3:Action链式跳转(仅适用于无用户交互场景)
如果业务不需要用户在first.jsp做任何操作,只是想从Try1直接跳转到Try2再渲染结果页,可以把struts.xml中Try1的结果类型改成chain,服务器端直接把Try1的值栈传递给Try2,不需要经过客户端传参。但这个方案不符合当前「用户点击first.jsp提交按钮再跳转」的交互流程,仅做参考。
struts.xml对应配置修改示例:
<action name="click" class="com.sham.Try1" > <result type="chain">next</result> </action>
内容的提问来源于stack exchange,提问作者Shambhavi R

