Java项目部署服务器时如何定义相对路径读取文件?
这个问题我之前帮好几个开发者解决过——核心原因是你搞错了War包部署后文件的实际路径结构,以及Java Web应用运行时的工作目录!
首先,你用的....\WebContent\resources\dataSource\ppmsOrigin.XLSX路径完全不适合War部署场景:
- War包被服务器(比如Tomcat)解压后,WebContent这个目录会被直接展开成Web应用的根目录,也就是说,原来WebContent下的
resources文件夹会直接在你的应用根路径下,路径里根本不需要写WebContent。 - 更关键的是,Java Web应用运行时的当前工作目录是服务器的bin目录(比如Tomcat的
bin文件夹),而不是你的项目目录,所以你写的相对路径是相对于服务器bin目录找文件,自然会报找不到的错误。
下面给你两种最靠谱的解决方案,根据你的文件用途选:
方案1:通过ServletContext读取Web应用内的静态资源
如果这个Excel文件是和War包一起部署的静态资源(不需要外部修改),用ServletContext来获取是最稳妥的方式,它会自动适配服务器的部署路径:
如果你用Spring/Spring Boot:
直接注入ServletContext,然后从应用根路径读取资源:
@Autowired private ServletContext servletContext; public void loadExcelFile() throws IOException { // 路径从应用根目录开始,对应原来WebContent下的resources文件夹 InputStream excelStream = servletContext.getResourceAsStream("/resources/dataSource/ppmsOrigin.XLSX"); // 接下来用POI等工具处理Excel,比如: Workbook workbook = WorkbookFactory.create(excelStream); // ...你的业务逻辑 }
如果你用普通Servlet:
在Servlet里直接获取ServletContext:
public class ExcelReaderServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { InputStream excelStream = getServletContext().getResourceAsStream("/resources/dataSource/ppmsOrigin.XLSX"); // ...处理文件逻辑 } }
⚠️ 注意:不要用getRealPath()方法,它在某些服务器(比如War包不解压直接运行的场景)会返回null,用getResourceAsStream()直接获取输入流是更安全的方式。
方案2:通过类加载器读取类路径下的资源
如果你把Excel文件放在src/main/resources(Maven项目)或者src/resources(普通Web项目)下,打包后它会被放到WEB-INF/classes目录下,属于类路径资源,这时候可以用类加载器读取:
// 方式1:用当前类的类加载器,路径开头的/表示从类路径根目录开始 InputStream excelStream = getClass().getResourceAsStream("/dataSource/ppmsOrigin.XLSX"); // 方式2:用线程上下文类加载器,适合在工具类等没有Spring注入的场景 InputStream excelStream = Thread.currentThread().getContextClassLoader() .getResourceAsStream("dataSource/ppmsOrigin.XLSX");
这种方式适合那些不需要外部修改、和代码紧密绑定的配置文件或资源文件。
额外提醒
如果你的Excel文件需要经常被外部修改(比如运营人员要更新数据),那最好不要把它打包到War包里,而是放在服务器的某个独立目录下,然后通过配置文件(比如application.properties)指定绝对路径,或者通过环境变量传递路径,这样修改文件不需要重新部署War包:
# 在application.properties里配置 excel.file.path=/opt/app/data/ppmsOrigin.XLSX
然后在代码里读取这个配置值来获取文件。
内容的提问来源于stack exchange,提问作者user1836957

