将 @PathParam 传递给 Jersey 中的子资源定位器 class
Passing @PathParam to Sub Resource locator class in Jersey
我想这样调用我的 api 端点:
http://.../companies/1/employees
并使用代码 1 检索公司的员工。我有这个代码:
@Path("companies")
public class CompanyResource {
@Context
ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
和
@Path("/employees")
public class EmployeeResource {
@PathParam("idCompany")
String idCompany;
@GET
public List<Employee> getEmployees() {
// here "idCompany" is null
//some code
}
}
但是路径参数为空。我究竟做错了什么?有更正确的方法吗?
我这样使用路径参数
@GET
public List<Employee> getEmployees(@PathParam("idCompany") String id ) {
// here "idCompany" is null
//some code
}
我通常是这样做的:
@Path("companies")
public class CompanyResource {
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees(@PathParam("idCompany") String idCompany) {
// ...
}
}
或
@Path("companies/{idCompany}/employees")
public class EmployeeResource {
@PathParam("idCompany")
String idCompany;
@GET
public List<Employee> getEmployees() {
//
}
}
第二个示例中的 @PathParam
为空,因为为了将其注入字段,服务 class 上的 @Path
注释必须有一个部分声明 {idCompany}
@PathParam
.
我无法重现 null id,但有几点需要指出
@GET
应该从 EmployeeResource getEmployees()
方法中删除。子资源定位器不应该有 HTTP 方法注释。参见 Sub-resources
EmployeeResource
上的 @Path
也被忽略(不需要)。没问题,只是觉得你应该知道。
下面是使用 Jersey Test Framework 的完整工作示例。这是我使用的测试依赖项
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
您可以运行它像任何其他 JUnit 测试一样
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static junit.framework.Assert.*;
public class LocatorTest extends JerseyTest {
public static class Employee {
public String firstName;
public String lastName;
public Employee(){}
public Employee(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
public static class Company {
public String companyId;
public List<Employee> employees;
public Company(){}
public Company(String companyId, List<Employee> employees) {
this.companyId = companyId;
this.employees = employees;
}
}
@Path("companies")
public static class CompanyResource {
@Context
private ResourceContext resourceContext;
@Path("{companyId}/employees")
public EmployeeResource getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
public static class EmployeeResource {
@PathParam("companyId")
public String companyId;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Company getCompanyEmployees() {
List<Employee> emps = new ArrayList<>();
emps.add(new Employee("pee", "skillet"));
emps.add(new Employee("Stack", "Overflow"));
Company co = new Company(companyId, emps);
return co;
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(CompanyResource.class);
}
@Test
public void doit() {
Response response = target("companies/1234/employees").request().get();
assertEquals(200, response.getStatus());
Company co = response.readEntity(Company.class);
assertNotNull(co.companyId);
assertEquals("1234", co.companyId);
assertEquals(2, co.employees.size());
response.close();
}
}
以下是 JAX-RS 2.0 可能解决方案的总结:
使用构造函数请求范围内的子资源:
@Path("companies")
public class CompanyResource {
@Path("{idCompany}/employees")
public EmployeeResource getEmployees(@PathParam("idCompany") String companyId) {
return new EmployeeResource(companyId);
}
}
public class EmployeeResource {
private String companyId
public EmployeeResource(String companyId) {
this.companyId = companyId;
}
@GET
public List<Employee> getEmployees() {
//some code
}
}
缺点:
- 没有依赖注入
请求范围子资源 ResourceContext#initResource(Class):
@Path("companies")
public class CompanyResource {
@Context
private ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees(@PathParam("idCompany") String companyId) {
EmployeeResource employeeResource = new EmployeeResource(companyId);
return resourceContext.initResource(employeeResource);
}
}
public class EmployeeResource {
@Context
private Request request;
private String companyId
public EmployeeResource(String companyId) {
this.companyId = companyId;
}
@GET
public List<Employee> getEmployees() {
//some code
}
}
缺点:
- 没有依赖注入 JSR-330
请求范围子资源 ResourceContext#getResource(Class):
@Path("companies")
public class CompanyResource {
@Context
private ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees(@PathParam("idCompany") String companyId) {
EmployeeResource employeeResource = resourceContext.getResource(EmployeeResource.class);
employeeResource.setCompanyId(companyId);
return employeeResource;
}
}
public class EmployeeResource {
@Context
private Request request;
private String companyId
public setCompanyId(String companyId) {
this.companyId = companyId;
}
@GET
public List<Employee> getEmployees() {
//some code
}
}
缺点:
- 没有依赖注入 JSR-330
以@PathParam
作为字段请求范围子资源:
@Path("companies")
public class CompanyResource {
@Context
private ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
public class EmployeeResource {
@Context
private Request request;
@PathParam("idCompany")
private String companyId;
@GET
public List<Employee> getEmployees() {
// some code
}
}
缺点:
- 没有依赖注入 JSR-330
请求 return 类型的子资源 Class<T>
:
@Path("companies")
public class CompanyResource {
@GET
@Path("{idCompany}/employees")
public Class<EmployeeResource> getEmployees() {
return EmployeeResource.class;
}
}
public class EmployeeResource {
@Context
private Request request;
@PathParam("idCompany")
private String companyId;
@GET
public List<Employee> getEmployees() {
// some code
}
}
缺点:
- 没有依赖注入 JSR-330
使用@PathParam
作为方法参数请求范围子资源:
@Path("companies")
public class CompanyResource {
@Context
private ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public Class<EmployeeResource> getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
public class EmployeeResource {
@Context
private Request request;
@GET
public List<Employee> getEmployees(@PathParam("idCompany") String companyId) {
// some code
}
}
缺点:
- 没有依赖注入 JSR-330
方法参数为@PathParam
的单例子资源:
@Path("companies")
public class CompanyResource {
@Context
private ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public Class<EmployeeResource> getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
@Singleton
public class EmployeeResource {
@Context
private Request request;
@GET
public List<Employee> getEmployees(@PathParam("idCompany") String companyId) {
// some code
}
}
缺点:
- 没有依赖注入 JSR-330
另请参阅:
我想这样调用我的 api 端点:
http://.../companies/1/employees
并使用代码 1 检索公司的员工。我有这个代码:
@Path("companies")
public class CompanyResource {
@Context
ResourceContext resourceContext;
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
和
@Path("/employees")
public class EmployeeResource {
@PathParam("idCompany")
String idCompany;
@GET
public List<Employee> getEmployees() {
// here "idCompany" is null
//some code
}
}
但是路径参数为空。我究竟做错了什么?有更正确的方法吗?
我这样使用路径参数
@GET
public List<Employee> getEmployees(@PathParam("idCompany") String id ) {
// here "idCompany" is null
//some code
}
我通常是这样做的:
@Path("companies")
public class CompanyResource {
@GET
@Path("{idCompany}/employees")
public EmployeeResource getEmployees(@PathParam("idCompany") String idCompany) {
// ...
}
}
或
@Path("companies/{idCompany}/employees")
public class EmployeeResource {
@PathParam("idCompany")
String idCompany;
@GET
public List<Employee> getEmployees() {
//
}
}
第二个示例中的 @PathParam
为空,因为为了将其注入字段,服务 class 上的 @Path
注释必须有一个部分声明 {idCompany}
@PathParam
.
我无法重现 null id,但有几点需要指出
@GET
应该从EmployeeResource getEmployees()
方法中删除。子资源定位器不应该有 HTTP 方法注释。参见 Sub-resourcesEmployeeResource
上的@Path
也被忽略(不需要)。没问题,只是觉得你应该知道。
下面是使用 Jersey Test Framework 的完整工作示例。这是我使用的测试依赖项
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
您可以运行它像任何其他 JUnit 测试一样
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static junit.framework.Assert.*;
public class LocatorTest extends JerseyTest {
public static class Employee {
public String firstName;
public String lastName;
public Employee(){}
public Employee(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
public static class Company {
public String companyId;
public List<Employee> employees;
public Company(){}
public Company(String companyId, List<Employee> employees) {
this.companyId = companyId;
this.employees = employees;
}
}
@Path("companies")
public static class CompanyResource {
@Context
private ResourceContext resourceContext;
@Path("{companyId}/employees")
public EmployeeResource getEmployees() {
return resourceContext.getResource(EmployeeResource.class);
}
}
public static class EmployeeResource {
@PathParam("companyId")
public String companyId;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Company getCompanyEmployees() {
List<Employee> emps = new ArrayList<>();
emps.add(new Employee("pee", "skillet"));
emps.add(new Employee("Stack", "Overflow"));
Company co = new Company(companyId, emps);
return co;
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(CompanyResource.class);
}
@Test
public void doit() {
Response response = target("companies/1234/employees").request().get();
assertEquals(200, response.getStatus());
Company co = response.readEntity(Company.class);
assertNotNull(co.companyId);
assertEquals("1234", co.companyId);
assertEquals(2, co.employees.size());
response.close();
}
}
以下是 JAX-RS 2.0 可能解决方案的总结:
使用构造函数请求范围内的子资源:
@Path("companies") public class CompanyResource { @Path("{idCompany}/employees") public EmployeeResource getEmployees(@PathParam("idCompany") String companyId) { return new EmployeeResource(companyId); } } public class EmployeeResource { private String companyId public EmployeeResource(String companyId) { this.companyId = companyId; } @GET public List<Employee> getEmployees() { //some code } }
缺点:
- 没有依赖注入
请求范围子资源 ResourceContext#initResource(Class):
@Path("companies") public class CompanyResource { @Context private ResourceContext resourceContext; @GET @Path("{idCompany}/employees") public EmployeeResource getEmployees(@PathParam("idCompany") String companyId) { EmployeeResource employeeResource = new EmployeeResource(companyId); return resourceContext.initResource(employeeResource); } } public class EmployeeResource { @Context private Request request; private String companyId public EmployeeResource(String companyId) { this.companyId = companyId; } @GET public List<Employee> getEmployees() { //some code } }
缺点:
- 没有依赖注入 JSR-330
请求范围子资源 ResourceContext#getResource(Class):
@Path("companies") public class CompanyResource { @Context private ResourceContext resourceContext; @GET @Path("{idCompany}/employees") public EmployeeResource getEmployees(@PathParam("idCompany") String companyId) { EmployeeResource employeeResource = resourceContext.getResource(EmployeeResource.class); employeeResource.setCompanyId(companyId); return employeeResource; } } public class EmployeeResource { @Context private Request request; private String companyId public setCompanyId(String companyId) { this.companyId = companyId; } @GET public List<Employee> getEmployees() { //some code } }
缺点:
- 没有依赖注入 JSR-330
以
@PathParam
作为字段请求范围子资源:@Path("companies") public class CompanyResource { @Context private ResourceContext resourceContext; @GET @Path("{idCompany}/employees") public EmployeeResource getEmployees() { return resourceContext.getResource(EmployeeResource.class); } } public class EmployeeResource { @Context private Request request; @PathParam("idCompany") private String companyId; @GET public List<Employee> getEmployees() { // some code } }
缺点:
- 没有依赖注入 JSR-330
请求 return 类型的子资源
Class<T>
:@Path("companies") public class CompanyResource { @GET @Path("{idCompany}/employees") public Class<EmployeeResource> getEmployees() { return EmployeeResource.class; } } public class EmployeeResource { @Context private Request request; @PathParam("idCompany") private String companyId; @GET public List<Employee> getEmployees() { // some code } }
缺点:
- 没有依赖注入 JSR-330
使用
@PathParam
作为方法参数请求范围子资源:@Path("companies") public class CompanyResource { @Context private ResourceContext resourceContext; @GET @Path("{idCompany}/employees") public Class<EmployeeResource> getEmployees() { return resourceContext.getResource(EmployeeResource.class); } } public class EmployeeResource { @Context private Request request; @GET public List<Employee> getEmployees(@PathParam("idCompany") String companyId) { // some code } }
缺点:
- 没有依赖注入 JSR-330
方法参数为
@PathParam
的单例子资源:@Path("companies") public class CompanyResource { @Context private ResourceContext resourceContext; @GET @Path("{idCompany}/employees") public Class<EmployeeResource> getEmployees() { return resourceContext.getResource(EmployeeResource.class); } } @Singleton public class EmployeeResource { @Context private Request request; @GET public List<Employee> getEmployees(@PathParam("idCompany") String companyId) { // some code } }
缺点:
- 没有依赖注入 JSR-330
另请参阅: