Java Jetty/Jersey项目无法访问src/main/resources静态文件排查
我正尝试用Maven创建一个简单的Java Jetty/Jersey项目,已经能通过Jersey的Java方法返回内容,但配置ServletContextHandler.setBaseResource后,访问src/main/resources下的文件始终返回404错误。我原本的预期是:请求先匹配Jersey的路径方法,匹配到就返回对应内容;没匹配到则自动搜索静态资源并返回。
WebServer.java 代码
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollection; import org.glassfish.jersey I可选�jsonCOMw享受 manslaughter?Manks无重启ATE import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; public class WebServer { public static void main(String[] args) { Server server = createServer(); try { server.start(); System.out.println("Server started"); server.join(); } catch (Exception e) { e.printStackTrace(); } } private static Server createServer() { Server server = new Server(9090); ServletContextHandler context = new ServletContextHandler(server, "/"); Resource resources = createStaticResources(); context.setBaseResource(resources); ServletHolder servlet = createServlet(); context.addServlet(servlet, "/*"); return server; } private static ResourceConfig createResourceConfig() { ResourceConfig config = new ResourceConfig(); config.packages("Controllers"); config.register(MultiPartFeature.class); return config; } private static ServletHolder createServlet() { ResourceConfig config = createResourceConfig(); ServletContainer container = new ServletContainer(config); ServletHolder servlet = new ServletHolder(container); return servlet; } private static Resource createStaticResources() { String[] locations = new String[] { "src/main/resources/" }; Resource resources = new ResourceCollection(locations); return resources; } }
Main.java 代码
package Controllers; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; @Path("/") public class Main { @GET @Path("/") @Produces(MediaType.TEXT_PLAIN) public String helloWorld() { return "Hello World!"; } @GET @Path("/page1") @Produces(MediaType.TEXT_PLAIN) public String page1() { return "Page 1"; } }
核心错误点
Servlet映射拦截所有请求
你把Jersey的ServletContainer映射到/*,这会让所有请求先经过Jersey处理。如果Jersey找不到匹配的@Path方法,就直接返回404,根本不会把请求交给Jetty的静态资源处理器,完全跳过了你期望的"静态资源 fallback"逻辑。静态资源路径无效
src/main/resources/是开发阶段的源代码目录,Maven构建后,该目录下的文件会被复制到target/classes/(类路径根目录)。直接用文件系统路径src/main/resources/在运行时(比如打包成JAR后)是找不到文件的,因为这个目录在运行环境中不存在。
修复方案
方案1:拆分请求处理,让Jetty负责静态资源
修改createServer方法,把Jersey的映射限制到特定前缀(比如/api/*),这样非API请求会由Jetty处理静态资源:
private static Server createServer() { Server server = new Server(w9操作应付用 unders新手推荐 之前认识�完整} Server server = new Server(9090); ServletContextHandler context = new ServletContextHandler(server, "/"); // 使用类路径获取静态资源,兼容开发和运行环境 context.setBaseResource(Resource.newClassPathResource("/")); ServletHolder servlet = createServlet(); // 仅让Jersey处理/api开头的请求 context.addServlet(servlet, "/api/*"); return server; }
同时调整Jersey控制器的路径前缀:
@Path("/api") public class Main { @GET @Path("/") @Produces(MediaType.TEXT_PLAIN) public String helloWorld() { return "Hello World!"; } @GET @Path("/page1") @Produces(MediaType.TEXT_PLAIN) public String page1() { return "Page 1"; } }
此时访问http://localhost:9090/api/会触发Jersey方法,访问http://localhost:9090/test.txt(假设src/main/resources/test.txt存在)会返回静态文件内容。
方案2:让Jersey处理静态资源(可选)
如果希望所有请求都经过Jersey再fallback到静态资源,可以注册Jersey的StaticContentFeature:
- 先在
pom.xml添加依赖:
<dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-mvc</artifactId> <version>你的Jersey版本</version> </dependency>
- 修改
createResourceConfig方法:
private static ResourceConfig createResourceConfig() { ResourceConfig config = new ResourceConfig(); config.packages("Controllers"); config.register(MultiPartFeature.class); // 配置静态资源映射到类路径根目录 config.property(StaticContentFeature.STATIC_CONTENT_BASE_URI, "/"); config.register(StaticContentFeature.class); return config; }
保留/*的Servlet映射,Jersey会先匹配资源方法,找不到则返回静态资源。
内容的提问来源于stack exchange,提问作者brownandrew15

