将@PathParam传递给Jersey中的Sub Resource定位器类

时间:2015-10-22 07:10:54

标签: java rest 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
    }
}

但路径参数为空。我究竟做错了什么?有更正确的方法吗?

5 个答案:

答案 0 :(得分:9)

以下是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
        }
    }
    

    缺点:

  • 使用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
        }
    }
    

    缺点:

  • @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
        }
    }
    

    缺点:

  • 请求返回类型为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
        }
    }
    

    缺点:

  • @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
        }
    }
    

    缺点:

  • @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
        }
    }
    

    缺点:

另见:

答案 1 :(得分:4)

我无法重现null id,但有几点要指出

    应该从@GET方法中删除
  • EmployeeResource getEmployees()。子资源定位器不应具有HTTP方法注释。请参阅Sub-resources
  • @Path上的EmployeeResource也会被忽略(不需要)。没问题,只是认为你应该知道。

使用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();
    }
}

答案 2 :(得分:1)

我像这样使用路径参数

@GET
public List<Employee> getEmployees(@PathParam("idCompany") String id ) {
    // here "idCompany" is null
    //some code
}

答案 3 :(得分:-1)

这就是我通常的做法:

if (rotationOption.ROTATION_Y_AXIS) {
    var timer = Date.now() * 0.0001;

    camera.position.x = Math.cos( timer ) * 200;
    camera.position.z = Math.sin( timer ) * 200;
    camera.lookAt( scene.position );

    renderer.render( scene, camera );
}

@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() { // } } 为null,因为为了将其注入字段,服务类上的@PathParam注释必须有一个声明@Path {{1 }}

答案 4 :(得分:-1)

如果任何解决方案无效,请尝试此作为最后的手段。

private ViewPager.OnPageChangeListener pageListener = new        
ViewPager.OnPageChangeListener() {

    @Override
    public void onPageSelected(int arg0) {
        Log.i("SCROLL", "onPageSelected");
        fab.show()
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        Log.i("SCROLL", "onPageScrolled");
        if(fab.isShown()) {
            fab.hide();
        }
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
        Log.i("SCROLL", "onStateChanged: "+arg0);
        fab.show();

    }
};