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

SpringBoot两个Controller间如何成功传递ArrayList数据

报错根因

你出现IndexOutOfBoundsException的核心原因有3个:

  1. 你在Spring MVC的Controller中直接new PageController()创建实例时,只执行了类的初始化逻辑,从未调用mainProgram()方法执行命令、填充runtime列表,新创建实例的runtime属性就是个空的ArrayList,直接调用get(0)必然越界。
  2. 你的PageController是独立的普通Java类,没有纳入Spring容器管理,和Web层的Controller没有任何数据共享机制,你写的main方法只有单独运行PageController类时才会执行,Web请求场景下根本不会触发。
  3. 现有代码还存在两个隐藏bug:一是runCMD方法读到命令输出的第一行就直接return,拿不到完整执行结果;二是配置文件读取写死了src/main/resources路径,项目打成jar包部署后该路径不存在,会读不到配置。
修复方案

1. 改造PageController为Spring管理的组件

去掉没用的main方法,把命令执行、数据加载的逻辑放到Bean初始化完成后自动执行,修正配置读取和命令执行的逻辑,修改后代码如下:

package org.monitor;

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.*;
import java.util.*;

@Component
public class PageController {
    private Properties prop = new Properties();
    private ArrayList<String> runtimeCommand = new ArrayList<>();
    private ArrayList<String> runtime = new ArrayList<>();

    // Bean初始化完成后自动执行配置加载、命令执行逻辑
    @PostConstruct
    public void init() throws IOException {
        loadProperty();
        mainProgram();
    }
    
    public void mainProgram() throws IOException{
        for (String cmd : runtimeCommand) {
            String output = runCMD(cmd);
            runtime.add(output);
        }
    }
    
    public String runCMD(String commandline) throws IOException {
        Process p;
        if(System.getProperty("os.name").toLowerCase().contains("windows")) {
            p = Runtime.getRuntime().exec("cmd.exe /C " + commandline); 
        } else {
            p = Runtime.getRuntime().exec(commandline);
        }
        
        // 修正读逻辑,读完所有输出再返回,不要读一行就退出
        StringBuilder outputBuilder = new StringBuilder();
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream(), "GBK"))) {
            String line;
            while((line = reader.readLine()) != null) {
                outputBuilder.append(line).append(System.lineSeparator());
            }
        }
        // 等待命令执行完成,避免产生僵尸进程
        try {
            p.waitFor();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("命令执行被中断", e);
        }
        return outputBuilder.toString().trim();
    }
    
    public void loadProperty() throws IOException {
        // 用类路径读取资源,兼容jar包部署场景
        try(InputStream input = PageController.class.getClassLoader().getResourceAsStream("properties/page.properties")) {
            if (input == null) {
                throw new FileNotFoundException("配置文件page.properties不存在");
            }
            prop.load(input);
            String cmdConfig = prop.getProperty("runtime.cmd");
            if (cmdConfig != null && !cmdConfig.isEmpty()) {
                runtimeCommand.addAll(Arrays.asList(cmdConfig.split(",")));
            }
        }
    }

    // 对外提供获取runtime列表的方法
    public List<String> getRuntimeList() {
        return Collections.unmodifiableList(runtime);
    }
}

2. 改造Web层Controller,注入PageController Bean

不要自己new PageController实例,直接通过Spring注入已经初始化完成、加载好数据的Bean,取数据前先判断非空,避免越界:

package org.boot;

import org.monitor.PageController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;

@RestController
public class Controller {

    @Autowired
    private PageController pageController;
        
    @GetMapping("/web")
    public String index() {
        return "Greetings from Spring Boot Quartz!";
    }
        
    @RequestMapping("/web/page")    
    public ModelAndView page() {
        ModelAndView model = new ModelAndView("page");
        List<String> runtimeList = pageController.getRuntimeList();
        // 把完整列表传给JSP用于表格渲染
        model.addObject("runtimeList", runtimeList);
        // 兼容原有${runtime}表达式,判断非空再传值
        model.addObject("runtime", runtimeList.isEmpty() ? "" : runtimeList.get(0));     
        return model;           
    }
}

3. JSP侧适配(渲染全量表格)

如果要基于ArrayList渲染完整表格,在JSP中引入JSTL标签遍历列表即可,示例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>运行状态</title>
</head>
<body>
    <table border="1">
        <tr>
            <th>命令执行结果</th>
        </tr>
        <c:forEach items="${runtimeList}" var="item">
            <tr>
                <td>${item}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>
注意事项
  • 如果你需要每次请求都重新执行命令获取最新数据,就把mainProgram()的调用从@PostConstruct方法移到Controller的page()方法里,不要在服务初始化时只执行一次。
  • 执行系统命令时要做好参数校验,避免命令注入安全风险。

内容的提问来源于stack exchange,提问作者Mainaqisyah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 18:31:23