为什么这个 <servlet-mapping> 破坏了我在 Jersey 的 REST API?
Why this <servlet-mapping> breaks my REST API in Jersey?
我有以下 web.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>jersey sample</display-name>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.myproject</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
效果很好,如果我转到 localhost:8080/myproject/api/ping,我会收到回复。
但是,如果我将 "url-pattern" 更改为“/api/*”,则请求相同 URL returns 404.
你知道为什么会发生这种情况吗?
这是我的其余配置。
build.gradle:
group 'myproject'
version '0.0'
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'jetty'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.14'
testCompile 'org.testng:testng:5.14.2'
}
test {
...
}
我的代码:
package org.myproject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/api")
public class Api {
@GET
@Path("/ping")
@Produces(MediaType.TEXT_PLAIN)
public String ping() {
return "Pong!";
}
}
我运行应用程序使用以下命令:
./gradlew clean jettyRunWar
url-模式是 前缀 或 servlet 的基础,在本例中为 Jersey servlet。这是 servlet 容器知道将请求发送到哪个 servlet 的方式。
因此 /api/*
您告诉 servlet 容器 Jersey 应用程序的基础是 /api
。这个基础实际上只对 servlet 容器重要。 Jersey handles/maps 之后的所有内容。
因此,对 /api/ping
的请求首先会被 /api
切断,因为它只是应用程序基础。然后 Jersey 尝试将 /ping
定位为 root 资源 class,这意味着它应该是 class带有 @Path("ping")
的注释。由于找不到它,您会收到 404。
因此,如果您使用当前代码添加 /api/*
,则请求应该是 /api/api/ping
不过,通常您不希望资源 class 上有应用程序基本名称。您应该只在资源 class 上设置 @Path("ping")
,并在映射中保留 /api/*
。只需从 ping()
中取出 @Path
注释
我有以下 web.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>jersey sample</display-name>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.myproject</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
效果很好,如果我转到 localhost:8080/myproject/api/ping,我会收到回复。
但是,如果我将 "url-pattern" 更改为“/api/*”,则请求相同 URL returns 404.
你知道为什么会发生这种情况吗?
这是我的其余配置。
build.gradle:
group 'myproject'
version '0.0'
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'jetty'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.14'
testCompile 'org.testng:testng:5.14.2'
}
test {
...
}
我的代码:
package org.myproject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/api")
public class Api {
@GET
@Path("/ping")
@Produces(MediaType.TEXT_PLAIN)
public String ping() {
return "Pong!";
}
}
我运行应用程序使用以下命令:
./gradlew clean jettyRunWar
url-模式是 前缀 或 servlet 的基础,在本例中为 Jersey servlet。这是 servlet 容器知道将请求发送到哪个 servlet 的方式。
因此 /api/*
您告诉 servlet 容器 Jersey 应用程序的基础是 /api
。这个基础实际上只对 servlet 容器重要。 Jersey handles/maps 之后的所有内容。
因此,对 /api/ping
的请求首先会被 /api
切断,因为它只是应用程序基础。然后 Jersey 尝试将 /ping
定位为 root 资源 class,这意味着它应该是 class带有 @Path("ping")
的注释。由于找不到它,您会收到 404。
因此,如果您使用当前代码添加 /api/*
,则请求应该是 /api/api/ping
不过,通常您不希望资源 class 上有应用程序基本名称。您应该只在资源 class 上设置 @Path("ping")
,并在映射中保留 /api/*
。只需从 ping()
@Path
注释