文件下载接口里,日期日期直接拼进路径,为路这事我干过,径下后来差点被运维骂死。日期Struts2的为路Action里写个getDownloadFile(),返回InputStream,径下路径写成"/upload/" + new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + fileName——上线当天没事,日期第二天凌晨零点一过,为路全线报404。径下
为什么?日期因为日期路径是动态的,但服务器上根本没有预创建目录。为路Struts2的径下FileInputStream不会帮你建目录,它只会老老实实去读,日期读不到就抛异常。为路你看着代码逻辑没错,径下可磁盘上就是没有那个文件夹。更坑的是,有些部署环境里,File.separator和URL里的斜杠混用,Windows上反斜杠被转义,Linux上直接拼错路径。
我踩过的坑是这样的:项目里有个定时任务,每天凌晨把前一天的数据打包成zip,存到/data/backup/20240115/这种结构。下载接口写得挺美,前端传个日期参数,后端拼路径,返回文件。测试的时候用的当天日期,一切正常。结果第二天早上用户投诉,说下载失败。查日志,FileNotFoundException,路径没错,文件也确实生成了,可就是读不到。
最后发现是时区问题。服务器用的UTC,定时任务按UTC跑,凌晨2点生成的是20240115的文件,但用户在前端选的是北京时间,传过来的是20240116。差了8小时,路径对不上,文件当然找不到。
解决办法其实不复杂。别在Action里直接拼日期路径,改成先查数据库或配置文件,拿到真正的存储路径。或者用File.separator拼接,别写死斜杠。再或者,干脆把日期参数校验一遍,用LocalDate.parse()解析,解析失败就返回400,别让用户瞎传。
还有个更隐蔽的坑:Struts2的下载流如果没关闭,文件被占用,第二天定时任务想删旧文件删不掉,磁盘越积越多。我见过生产环境磁盘100%报警,一查全是这种日期目录下的临时文件。
说实话,用日期做路径本身没毛病,文件归档按时间分目录很合理。但你要确保三件事:第一,目录必须存在,没有就主动创建;第二,日期字符串的时区要和存储逻辑一致,别一个UTC一个东八区;第三,下载完成后务必关流,最好用try-with-resources。
现在让我写,我会在Action里加个判断:File dir = new File(basePath + File.separator + dateStr); if (!dir.exists()) { dir.mkdirs(); },然后下载前检查文件是否存在,不存在就返回一个自定义的JSON错误,而不是让Struts2抛一堆堆栈信息给前端。用户看到“文件不存在”和看到500错误,体验完全两样。
日期路径下载,核心不是路径怎么写,而是你知不知道文件在哪儿、什么时候生成的、谁在什么时候删。搞明白这三个,路径随便拼。