如何将控制台输出字符串流式传输至其他类(Apache Commons Exec场景)
我来帮你搞定这个问题!核心就是把Commons Exec捕获到的控制台输出,实时传递到负责推送客户端的类里,而不是只打印到本地控制台。下面是具体的实现方案和修改后的代码:
核心思路
- 让捕获输出的
LogOutputStream和客户端推送类建立关联,每捕获一行就立刻传递过去 - 客户端推送逻辑改成流式输出,因为Jar执行的输出是实时产生的,不能用死循环检查固定字符串,要动态接收每一行并推送
修改后的代码实现
第一步:调整Jar执行的流处理逻辑
我们先实例化推送类,然后在processLine里把每一行输出传给它:
// 假设你的HttpExchange对象是he,先实例化推送处理器 ClientPushHandler pushHandler = null; try { pushHandler = new ClientPushHandler(he); } catch (IOException e) { e.printStackTrace(); return; // 初始化失败直接返回 } DefaultExecutor executor = new DefaultExecutor(); executor.setWorkingDirectory(dir); executor.setStreamHandler(new PumpStreamHandler(new LogOutputStream() { @Override protected void processLine(String line, int level) { System.out.println("[LOL]" + line); // 把捕获到的行实时传给推送类 pushHandler.sendLineToClient(line); } })); // 执行你的Jar命令(这里假设你已经有CommandLine对象) try { executor.execute(command); } catch (ExecuteException | IOException e) { e.printStackTrace(); } finally { // 执行完成后关闭客户端连接 if (pushHandler != null) { pushHandler.closeStream(); } }
第二步:重写客户端推送类(ClientPushHandler)
把原来的死循环逻辑改成动态接收行的方式,并且用Chunked编码实现流式推送:
import java.io.IOException; import java.io.OutputStream; import java.net.HttpExchange; import java.nio.charset.StandardCharsets; public class ClientPushHandler { private final HttpExchange he; private final OutputStream responseOs; public ClientPushHandler(HttpExchange he) throws IOException { this.he = he; // 设置响应头为Chunked编码(长度设为-1),支持实时流式输出 he.sendResponseHeaders(200, -1); this.responseOs = he.getResponseBody(); } // 线程安全地接收输出行并推送给客户端 public synchronized void sendLineToClient(String line) { try { // 把行转成字节,加上换行符让客户端能区分每一行(可选,根据需求调整) byte[] lineBytes = (line + "\n").getBytes(StandardCharsets.UTF_8); responseOs.write(lineBytes); // 强制刷新缓冲区,确保客户端立刻收到数据 responseOs.flush(); } catch (IOException e) { e.printStackTrace(); // 客户端断开连接时,关闭流释放资源 closeStream(); } } // 关闭流和HttpExchange public void closeStream() { try { responseOs.close(); he.close(); } catch (IOException e) { e.printStackTrace(); } } }
关键细节说明
- Chunked编码:设置
sendResponseHeaders的长度为-1,告诉服务器和客户端我们要流式发送数据,不需要提前知道总长度,这是实时推送的关键 - 线程安全:
processLine是由Commons Exec的内部线程调用的,而推送操作可能在不同线程,所以用synchronized保证写入流的线程安全 - 实时刷新:每次写完一行都调用
flush(),避免数据留在缓冲区里,客户端才能实时看到输出 - 异常处理:如果推送时出现IO异常(比如客户端断开),及时关闭流,避免资源泄漏
这样修改后,Jar执行过程中产生的每一行输出都会实时推送给客户端,完美解决你的需求!
内容的提问来源于stack exchange,提问作者LegitAsDuck
相关产品推荐
相关产品推荐

