You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:57:21