Maven构建Tomcat Web项目Java类无法访问assets内的Access数据库
问题核心原因
你代码中写的相对路径.\\assets\\BC190201004.accdb里的.,指代的是JVM启动时的运行工作目录(对应Java系统属性user.dir的值),并不是你在NetBeans项目视图里看到的源码目录、webapp目录、WEB-INF目录这类开发阶段的文件路径。
你尝试在项目不同层级文件夹下放置assets目录却始终报文件找不到,本质是你放db文件的所有位置,都和当前JVM实际的运行工作目录不匹配。
从你提供的绝对路径结构可以判断,这是一个标准Maven结构的Java Web项目。哪怕你在NetBeans里点击运行启动项目,JVM的工作目录也通常是内置Tomcat插件的安装路径、项目构建输出目录,根本不是你写业务代码的项目根路径;等后续把项目打WAR包部署到外部Tomcat服务器时,JVM工作目录又会变成Tomcat的bin目录,相对路径的基准点会完全偏离你预设的位置。
而你之前写死的绝对路径能正常连接,是因为它直接指定了文件在磁盘上的真实位置,完全不依赖JVM工作目录的路径基准,所以不会触发文件找不到的异常。
可落地的排查与修复方案
- 第一步:先确认JVM真实的工作目录,不要靠经验猜。在数据库连接代码最前面加一行打印代码,运行程序后看控制台输出的真实路径,这个路径就是你写所有相对路径的起点:
System.out.println("JVM当前工作目录:" + System.getProperty("user.dir"));
把存放db文件的assets文件夹放到这个打印出来的路径下,原来的相对路径写法就能正常定位到文件。 - 第二步:针对Web项目的特性,放弃脆弱的硬编码路径(不管是相对路径还是写死的绝对路径),通过容器API自动获取文件的真实磁盘路径,适配开发、生产部署全场景。
既然你之前测试把db文件放在src/main/webapp/WEB-INF/assets/下能通过绝对路径正常访问,完全可以把这个目录作为db文件的标准存放位置——这个路径下的文件不会被web容器对外暴露,符合敏感文件的存放安全要求。代码里不需要写死路径,直接通过ServletContext自动获取真实磁盘路径即可:- 在Servlet类中,通过ServletContext拿到db文件的真实磁盘路径:
String dbDiskPath = getServletContext().getRealPath("/WEB-INF/assets/BC190201004.accdb"); - 把这个路径拼接到UCANACCESS的JDBC连接串中,替换原来的相对路径即可:
String url = "jdbc:ucanaccess://" + dbDiskPath;
- 在Servlet类中,通过ServletContext拿到db文件的真实磁盘路径:
- 备选适配方案(适用于静态工具类无法获取ServletContext的场景):
- 在NetBeans的项目运行配置里,手动固定JVM的工作目录:在VM启动参数中添加
-Duser.dir=你的项目根目录绝对路径,让相对路径的基准点和你存放assets文件夹的位置保持一致。 - 注意:不要直接把类路径(如
src/main/resources)下的db文件路径直接传给UCANACCESS。项目打包成WAR包后,类路径下的文件是存储在压缩包内部的,而UCANACCESS需要对db文件做带排他锁的读写操作,无法直接访问压缩包内部的文件。这种场景下需要先把db文件从类路径拷贝到系统临时目录,再用临时目录的路径拼接JDBC连接串。
- 在NetBeans的项目运行配置里,手动固定JVM的工作目录:在VM启动参数中添加
常见踩坑提醒
- 不要拿IDE的项目文件浏览视图判断相对路径的基准:IDE展示的是开发阶段的源码结构,和运行阶段JVM的工作目录没有必然对应关系。
- 不要在生产环境使用硬编码绝对路径:更换运行服务器、更换操作系统登录用户时,硬编码的路径会直接失效。
- 存放db文件的目录需要保证运行程序的用户有读写权限,否则就算路径定位正确,UCANACCESS也会因为无法创建db文件的锁文件抛出权限类异常。
内容的提问来源于stack exchange,提问作者Usman Khan
相关产品推荐
相关产品推荐

