悠悠楠杉
基于Struts的CSV动态生成与FTP上传实战方案
基于Struts的CSV动态生成与FTP上传实战方案
需求背景与实现思路
在电商后台管理系统中,我们经常需要将订单数据以CSV格式定期同步到FTP服务器供第三方物流系统读取。传统做法是手动导出再上传,而通过Java Struts框架可以实现自动化流程:
- 动态构建CSV:根据订单数据实时生成
- 内存流处理:避免产生临时文件
- FTP传输:通过Apache Commons Net实现
- 结果反馈:返回操作状态给前端
核心代码实现(Struts 1.x版本)
1. Action类设计
java
public class ExportOrderCSVAction extends Action {
private static final Logger LOG = Logger.getLogger(ExportOrderCSVAction.class);
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
// 1. 获取订单数据(示例伪代码)
List<Order> orders = orderService.getRecentOrders(7); // 获取近7天订单
try {
// 2. 生成CSV内存流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "GBK"); // 中文编码
// 写入CSV头部
writer.write("\uFEFF"); // BOM头解决中文乱码
writer.write("订单ID,客户姓名,商品名称,数量,金额,下单时间\n");
// 写入数据行
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
for (Order order : orders) {
writer.write(String.format("\"%s\",\"%s\",\"%s\",%d,%.2f,\"%s\"\n",
order.getId(),
escapeCsvField(order.getCustomerName()),
escapeCsvField(order.getProductName()),
order.getQuantity(),
order.getAmount(),
sdf.format(order.getCreateTime())
));
}
writer.flush();
// 3. 上传FTP服务器
FTPClient ftp = new FTPClient();
try {
ftp.connect("ftp.yourdomain.com", 21);
ftp.login("username", "password");
ftp.setFileType(FTP.BINARY_FILE_TYPE);
InputStream input = new ByteArrayInputStream(outputStream.toByteArray());
boolean success = ftp.storeFile("orders/"+getFileName(), input);
input.close();
if(success) {
request.setAttribute("message", "CSV文件上传成功");
} else {
request.setAttribute("error", "FTP存储失败");
}
} finally {
if(ftp.isConnected()) {
try { ftp.disconnect(); }
catch (IOException e) { /* 忽略 */ }
}
}
} catch (Exception e) {
LOG.error("CSV导出异常", e);
request.setAttribute("error", "系统错误:" + e.getMessage());
}
return mapping.findForward("result");
}
private String escapeCsvField(String field) {
return field.replace("\"", "\"\"");
}
private String getFileName() {
return "orders_" + System.currentTimeMillis() + ".csv";
}
}
2. struts-config.xml配置
xml
<action path="/exportOrderCSV"
type="com.your.pkg.ExportOrderCSVAction"
scope="request">
<forward name="result" path="/WEB-INF/jsp/exportResult.jsp"/>
</action>
关键技术点解析
CSV生成优化方案
- 内存效率:使用
ByteArrayOutputStream
避免磁盘IO - 中文处理:添加BOM头解决Excel打开乱码
- 特殊字符转义:处理字段中的逗号和引号
- 批处理:大数据量时建议分页生成
FTP传输增强项
- 断点续传:通过
FTPClient.setRestartOffset()
实现 - 被动模式:
ftp.enterLocalPassiveMode()
解决防火墙问题 - 连接池管理:推荐使用FTP连接池提升性能
生产环境建议
异常恢复机制:
java // 重试逻辑示例 int retry = 0; while(retry < 3) { try { // FTP操作代码 break; } catch (FTPConnectionClosedException e) { retry++; Thread.sleep(1000 * retry); } }
性能监控:
- 记录CSV生成耗时
- 监控FTP传输速度
- 设置超时时间:ftp.setDefaultTimeout(30000);
- 安全加固:
java // 使用SFTP替换FTP(需引入JSch库) ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp"); sftp.put(new ByteArrayInputStream(csvData), "remote.csv");
扩展应用场景
该方案稍作修改即可适用于:
- 定时生成财务对账单
- 用户数据批量导出
- 系统间数据交换中间件
通过Struts框架的MVC分离特性,我们可以轻松将业务逻辑、数据格式转换和传输协议分层处理,使系统更易于维护和扩展。对于现代系统,建议将FTP操作部分改造为异步任务,通过消息队列实现削峰填谷。
作者经验谈:在实际项目中,我们曾遇到200MB大CSV文件上传失败的问题,最终通过分块传输(每10MB一个分片)解决。关键是要处理好网络中断后的状态恢复,建议在数据库中记录文件传输进度。