使用 Jersey 2.21 的 REST API 请求中的可选参数
Optional params in REST API request using Jersey 2.21
我正在研究 Jersey 2.21
,我想知道是否可以有一个 "optional" 参数,它可以或不可以出现在对服务器的请求中.
我想成功访问这两个方法:
http://localhost:8080/my_domain/rest/api/myMethod/1
http://localhost:8080/my_domain/rest/api/myMethod
如您所见,我正在尝试使整数 (id
) 参数成为可选参数。
我已声明 myMethod
如下:
@GET
@Path("myMethod/{id}")
@Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
public String myMethod(@PathParam("id") Integer id, @Context HttpHeaders hh)
这个有效:
http://localhost:8080/my_domain/rest/api/myMethod/1
这也有效:
http://localhost:8080/my_domain/rest/api/myMethod/
但是这行不通,我不明白为什么。它抛出 404 Not Found
错误:
http://localhost:8080/my_domain/rest/api/myMethod
你能指出正确的方向来解决这个问题吗?我不喜欢在我的所有 REST 方法调用中强制使用斜杠,并且希望尽可能禁止使用它。
所以在对Optional @PathParam in Jax-RS中的一些答案进行了一些尝试之后,问题是使用这个
@Path("/myMethod{id: (/\d+)?}")
public Response get(@PathParam("id") int id) {}
使 /
位于捕获组中。所以当 Jersey 试图解析 /1
时,它会得到一个异常并发送一个 404。我们可以使用一个字符串,但是它变得丑陋,因为我们需要摆脱领先的 /
和自己解析。
@Path("/myMethod{id: (/\d+)?}")
public Response get(@PathParam("id") String id) {
id = id.replace("/", "");
int parsed = Integer.parseInt(id);
}
我提出的另一个解决方案(适用于 OP 的解决方案)是将 /
从数字中分离为两个不同的路径表达式,因此前导 /
是未在实际 id 中捕获并且在解析时不会失败
@Path("/method{noop: (/)?}{id: ((?<=/)\d+)?}")
public Response get(@PathParam("id") int id) {}
{noop: (/)?}
捕获可选的 /
。而 {id: ((?<=/)\d+)?}
使用 positive lookbehind,表示数字 (\d+
) 是允许的,当且仅当它前面有 /
((?<=/)
)。这是必需的,因为 /
是可选的。如果我们不使用这个断言,那么 /myMethod123
将被允许。
这是一个完整的测试用例,使用 Jersey Test Framework
public class OptionalParamTest extends JerseyTest {
@Path("optional")
public static class Resource {
@GET
@Path("/method{noop: (/)?}{id: ((?<=/)\d+)?}")
public String get(@PathParam("id") int id) {
return String.valueOf(id);
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(Resource.class);
}
@Test
public void should_return_id_1() {
Response response = target("optional/method/1").request().get();
System.out.println("status=" + response.getStatus());
assertEquals("1", response.readEntity(String.class));
}
@Test
public void should_return_id_0_with_no_id() {
Response response = target("optional/method").request().get();
assertEquals(200, response.getStatus());
assertEquals("0", response.readEntity(String.class));
}
@Test
public void should_return_404_with_numbers_and_no_slash() {
Response response = target("optional/method12").request().get();
assertEquals(404, response.getStatus());
}
@Test
public void should_return_404_with_numbers_and_letters() {
Response response = target("optional/method/12b").request().get();
assertEquals(404, response.getStatus());
}
@Test
public void should_return_404_with_only_letters() {
Response response = target("optional/method/ab").request().get();
assertEquals(404, response.getStatus());
}
}
这是测试的依赖项
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
编辑
对于测试,最好使用盒装 Integer
而不是 int
作为方法参数。使用前者,您将能够进行空检查,而不是接收原语的默认值 0
。
有一种方式更简单的方法:
@GET
@Path("myMethod/{id}")
public String myMethod(@PathParam("id") Integer id) {
}
@GET
@Path("myMethod")
public String myMethod() {
return myMethod(null);
}
不需要棘手的正则表达式。
我正在研究 Jersey 2.21
,我想知道是否可以有一个 "optional" 参数,它可以或不可以出现在对服务器的请求中.
我想成功访问这两个方法:
http://localhost:8080/my_domain/rest/api/myMethod/1
http://localhost:8080/my_domain/rest/api/myMethod
如您所见,我正在尝试使整数 (id
) 参数成为可选参数。
我已声明 myMethod
如下:
@GET
@Path("myMethod/{id}")
@Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
public String myMethod(@PathParam("id") Integer id, @Context HttpHeaders hh)
这个有效:
http://localhost:8080/my_domain/rest/api/myMethod/1
这也有效:
http://localhost:8080/my_domain/rest/api/myMethod/
但是这行不通,我不明白为什么。它抛出 404 Not Found
错误:
http://localhost:8080/my_domain/rest/api/myMethod
你能指出正确的方向来解决这个问题吗?我不喜欢在我的所有 REST 方法调用中强制使用斜杠,并且希望尽可能禁止使用它。
所以在对Optional @PathParam in Jax-RS中的一些答案进行了一些尝试之后,问题是使用这个
@Path("/myMethod{id: (/\d+)?}")
public Response get(@PathParam("id") int id) {}
使 /
位于捕获组中。所以当 Jersey 试图解析 /1
时,它会得到一个异常并发送一个 404。我们可以使用一个字符串,但是它变得丑陋,因为我们需要摆脱领先的 /
和自己解析。
@Path("/myMethod{id: (/\d+)?}")
public Response get(@PathParam("id") String id) {
id = id.replace("/", "");
int parsed = Integer.parseInt(id);
}
我提出的另一个解决方案(适用于 OP 的解决方案)是将 /
从数字中分离为两个不同的路径表达式,因此前导 /
是未在实际 id 中捕获并且在解析时不会失败
@Path("/method{noop: (/)?}{id: ((?<=/)\d+)?}")
public Response get(@PathParam("id") int id) {}
{noop: (/)?}
捕获可选的 /
。而 {id: ((?<=/)\d+)?}
使用 positive lookbehind,表示数字 (\d+
) 是允许的,当且仅当它前面有 /
((?<=/)
)。这是必需的,因为 /
是可选的。如果我们不使用这个断言,那么 /myMethod123
将被允许。
这是一个完整的测试用例,使用 Jersey Test Framework
public class OptionalParamTest extends JerseyTest {
@Path("optional")
public static class Resource {
@GET
@Path("/method{noop: (/)?}{id: ((?<=/)\d+)?}")
public String get(@PathParam("id") int id) {
return String.valueOf(id);
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(Resource.class);
}
@Test
public void should_return_id_1() {
Response response = target("optional/method/1").request().get();
System.out.println("status=" + response.getStatus());
assertEquals("1", response.readEntity(String.class));
}
@Test
public void should_return_id_0_with_no_id() {
Response response = target("optional/method").request().get();
assertEquals(200, response.getStatus());
assertEquals("0", response.readEntity(String.class));
}
@Test
public void should_return_404_with_numbers_and_no_slash() {
Response response = target("optional/method12").request().get();
assertEquals(404, response.getStatus());
}
@Test
public void should_return_404_with_numbers_and_letters() {
Response response = target("optional/method/12b").request().get();
assertEquals(404, response.getStatus());
}
@Test
public void should_return_404_with_only_letters() {
Response response = target("optional/method/ab").request().get();
assertEquals(404, response.getStatus());
}
}
这是测试的依赖项
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
编辑
对于测试,最好使用盒装 Integer
而不是 int
作为方法参数。使用前者,您将能够进行空检查,而不是接收原语的默认值 0
。
有一种方式更简单的方法:
@GET
@Path("myMethod/{id}")
public String myMethod(@PathParam("id") Integer id) {
}
@GET
@Path("myMethod")
public String myMethod() {
return myMethod(null);
}
不需要棘手的正则表达式。