Java中的URI识别使用类和方法级别的JAX-RS @Path注释

时间:2016-09-27 14:34:15

标签: java rest jax-rs websphere apache-wink

我在资源类中创建了一个情境,我收到了所有3个端点的404,并希望有人可以帮助解释原因。这是我的资源类:

@Path("/incidents")
public class RegistrationResource {

    @GET
    @Path("/{incidentId}/registration")
    public Response getRegisteredIncidents(@PathParam("incidentId") String incidentId) {
           ...
    }

    @GET
    @Path("/registration/download")
    public Response downloadRegistrationIncidentsReport() {
           ...
    }

    @GET
    @Path("/registration/email")
    public Response emailRegistrationIncidentsReport() {
           ...
    }
}

我还使用JAX-RS Application类来注册我的资源并设置基础"上下文"所有端点的路径:

@ApplicationPath("/context") 
public class AdminApplication extends Application { 

    @Override
    public Set<Class<?>> getClasses() { 

        Set<Class<?>> resources = new HashSet<Class<?>>();

        resources.add(RegistrationResource.class);

        ...

        return resources;
    }
}

现在,如果我将这些方法拆分为多个资源类,我可以让每个服务都能正常工作,但我的问题是为什么上面的设计不会起作用?我按照上述方法的顺序尝试调用的完整端点是:

/context/incidents/55/registration
/context/incidents/registration/download
/context/incidents/registration/email

为什么找不到上面的映射?通过这种设计,我为每个端点获得了404.

  

org.apache.wink.server.internal.RequestProcessor logException在调用处理程序链期间发生以下错误:WebApplicationException(404 - Not Found),消息&#39; null&#39;处理发送到http://localhost:9081/someapp/context/incidents/55/registration

的GET请求时

作为进一步的澄清点,我使用Wink 1.1作为我的JAX-RS实现,因为我此时已经绑定到WebSphere 8.5.5.5附带的打包版本。

谢谢你的时间!

-----------更新#1 -----------

根据以下评论,我修改了一些端点。但是,我仍然在某些端点上收到随机故障404或者有趣的是405错误。重要的是要注意,如果我重新部署,有时不同的端点会失败,或者也许一切都会起作用。然后,如果我再次重新部署,我会得到类似的,但某些端点的不同结果失败或全部工作。底线是它非常不一致。

因此,似乎有更多的端点与我原来的帖子相冲突,所以为了完整起见,我在这里粘贴所有端点。

/* Public Service Set */

@ApplicationPath("/public") 
public class PublicApplication extends Application { 

    @Override
    public Set<Class<?>> getClasses() { 

        Set<Class<?>> resources = new HashSet<Class<?>>();

        resources.add(IncidentResource.class);
        resources.add(IncidentDetailsResource.class);
        resources.add(TicketResource.class);
        resources.add(RegistrationResource.class);

        return resources;
    }
}

@Path("/incidents")
public class IncidentResource { 

    @GET
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidents() throws Exception {
    //...
    } 

@Path("/")
public class IncidentDetailsResource {

    @GET
    @Path("/v1/incidents/{incidentId}/details")
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidentDetails(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }

    @GET
    @Path("/v2/incidents/{incidentId}/details")
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidentDetailsAsJson(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }

}

@Path("/incidents/{incidentId}/tickets") 
public class TicketResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getTickets(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }
}


@Path("/incidents")
public class RegistrationResource {

    @POST
    @Path("/{incidentId}/registration")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response register(@PathParam("incidentId") String incidentId, BaseRequestMessage<IncidentRegistrationRequest> baseRequestMessage) throws Exception {
    //...
    }
}

/* Admin Service Set */

@ApplicationPath("/admin") 
public class AdminApplication extends Application { 

    @Override
    public Set<Class<?>> getClasses() { 

        Set<Class<?>> resources = new HashSet<Class<?>>();

        resources.add(AdminIncidentResource.class);
        resources.add(AdminIncidentDetailsResource.class);
        resources.add(AdminRegistrationResource.class);
        resources.add(AdminRegistrationReportResource.class);
        resources.add(AdminTicketResource.class);

        return resources;
    }
}

@Path("/incidents")
public class AdminIncidentResource { 

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response addIncident(BaseRequestMessage<IncidentRequest> baseRequestMessage) throws Exception {
    //...
    }

    @PUT 
    @Path("/{incidentId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response updateIncident(@PathParam("incidentId") String incidentId, BaseRequestMessage<IncidentRequest> baseRequestMessage) throws Exception {
    //...
    }

    @DELETE 
    @Path("/{incidentId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response deleteIncident(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }
}

@Path("/")
public class AdminIncidentDetailsResource {

    @PUT
    @Path("/v1/incidents/{incidentId}/details")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response updateIncidentDetails(@PathParam("incidentId") String incidentId, BaseRequestMessage<IncidentDetailRequest> baseRequestMessage) throws Exception {
    //...    
    }

    @PUT
    @Path("/v2/incidents/{incidentId}/details")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response updateIncidentDetailsAsJson(@PathParam("incidentId") String incidentId, BaseRequestMessage<JsonNode> baseRequestMessage) throws Exception {
    //...
    }
}

@Path("/incidents/{incidentId}/tickets")
public class AdminTicketResource {

    @POST
    @Consumes(MediaType.APPLICATION_JSON) 
    public Response addTicket(@PathParam("incidentId") String incidentId, BaseRequestMessage<TicketRequest> baseRequestMessage) throws Exception {
    //...   
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON) 
    public Response updateTicket(@PathParam("incidentId") String incidentId, BaseRequestMessage<TicketRequest> baseRequestMessage) throws Exception {
    //...    
    }

    @DELETE
    @Path("/{detailsUrn}")
    @Consumes(MediaType.APPLICATION_JSON) 
    public Response removeTicket(@PathParam("incidentId") String incidentId, @PathParam("detailsUrn") String detailsUrn) throws Exception {
    //...    
    }

}

@Path("/incidents/registration/report")
public class AdminRegistrationReportResource {

    @GET
    @Path("/download")
    @Produces("application/vnd.ms-excel")
    public Response downloadRegistrationReport() throws Exception { 
    //...    
    }

    @GET
    @Path("/email")
    @Produces(MediaType.APPLICATION_JSON)
    public Response emailRegistrationReport() throws Exception { 
    //...    
    }
}

@Path("/incidents/{incidentId}/registration")
public class AdminRegistrationResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getRegisteredUsers(@PathParam("incidentId") String incidentId) throws Exception { 
    //...    
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    public Response updateRegisteredUser(@PathParam("incidentId") String incidentId, BaseRequestMessage<IncidentRegistrationRequest> baseRequestMessage) throws Exception {
    //...    
    }
}

为了方便起见......上面的代码最终产生了这些uris:

  • GET / public / incidents
  • GET / public / v1 / events / {incidentId} / details
  • GET / public / v2 / incidents / {incidentId} / details
  • GET / public / incidents / {incidentId} / tickets
  • POST / public / incidents / {incidentId} / registration

  • POST / admin / events

  • PUT / admin / incidents / {incidentId}
  • DELETE / admin / incidents / {incidentId}
  • PUT / admin / v1 / incidents / {incidentId} / details
  • PUT / admin / v2 / incidents / {incidentId} / details
  • POST / admin / incidents / {incidentId} / tickets
  • PUT / admin / incidents / {incidentId} / tickets
  • DELETE / admin / incidents / {incidentId} / tickets / {detailsUrn}
  • GET / admin /事件/注册/报告/下载
  • GET / admin /事件/注册/报告/电子邮件
  • GET / admin / incidents / {incidentId} / registration
  • PUT / admin / incidents / {incidentId} / registration

这是很多代码;我本来想避免这种情况,但似乎有必要。而且,为了它的价值,在我添加AdminRegistrationResource类之前,事情似乎正在发挥作用。也许某个端点中的一个端点开始引发冲突?

再次......感谢您的时间!

-----------更新#2 -----------

我认为我在这里发布了我最近的一个特定错误,希望它可能有助于解决问题。当我打电话给这个终点时:

  

获取/公开/事件

我收到此错误消息:

00000203 ResourceRegis I org.apache.wink.server.internal.registry.ResourceRegistry filterDispatchMethods The system cannot find any method in the com.somewhere.unimportant.rest.resource.external.RegistrationResource class that supports GET. Verify that a method exists.

00000203 RequestProces I org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (405) with message 'null' while processing GET request sent to https://test.somewhere.com:88888/app777/public/events

现在更有趣的是,我在本地收到此错误,但我也将我的代码推送到有两个负载均衡服务器的测试环境。在测试环境中,我在其中一个服务器上始终收到此错误,但另一个一致地工作。因此,在一个成功的服务器和一个不成功的服务器上分离50%的故障率。

奇怪......为什么它会在那个类中查找我正在点击的端点?

-----------更新#3 -----------

好的,我已经完全在我的PublicApplication类中使用了@ApplicationPath注释(如下面的评论中所建议的),并将其替换为仅仅#34; /&#34;但在以下情况下仍然会收到404错误(请注意,对于此测试,我已完全删除了&#34; admin&#34;服务):

/* Public (and only) Service Set */

@ApplicationPath("/") 
public class PublicApplication extends Application { 

    @Override
    public Set<Class<?>> getClasses() { 

        Set<Class<?>> resources = new HashSet<Class<?>>();

        resources.add(IncidentResource.class);
        resources.add(IncidentDetailsResource.class);
        resources.add(TicketResource.class);
        resources.add(RegistrationResource.class);

        return resources;
    }
}

@Path("/public")
public class IncidentResource { 

    @GET
    @Path("/incidents")
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidents() throws Exception {
    //...
    } 

@Path("/public")
public class IncidentDetailsResource {

    @GET
    @Path("/v1/incidents/{incidentId}/details")
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidentDetails(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }

    @GET
    @Path("/v2/incidents/{incidentId}/details")
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidentDetailsAsJson(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }

}

@Path("/public/incidents/{incidentId}/tickets") 
public class TicketResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getTickets(@PathParam("incidentId") String incidentId) throws Exception {
    //...
    }
}

@Path("/public/incidents/{incidentId}/registration")
public class RegistrationResource {

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response register(@PathParam("incidentId") String incidentId, BaseRequestMessage<IncidentRegistrationRequest> baseRequestMessage) throws Exception {
    //...
    }
}

在这种情况下,我收到此错误:

org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) with message 'null' while processing GET request sent to http://test.somewhere.com:88888/app777/public/events

试图打电话时:

  

获取/公开/事件

上述其他4个端点也可以正常工作。并且,更重要的是,如果我将IncidentResource类更改为如下所示(将方法级别的@Path注释完全移至类级别),则所有 5个端点工作:

@Path("/public/incidents")
public class IncidentResource { 

    @GET
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getIncidents() throws Exception {
    //...
    } 

我感谢所有与我同住的人!

2 个答案:

答案 0 :(得分:2)

删除@ApplicationPath(“/ context”)或者不要在请求uri中使用/ context,或者只使用@ApplicationPath(“/”)它甚至在升级时都不会中断。

以上所有不同的方法都应该有效,但对于您的版本,我会建议使用@ApplicationPath(“/”)并通过删除/上下文来更新您的请求uris,并且所有内容都应该按照您最初的预期方式工作。

Apache Wink目前尚不支持ApplicationPath。

https://issues.apache.org/jira/browse/WINK-398

答案 1 :(得分:0)

这可能对您有用:

@Path("/incidents/{incidentId}/registration")
public class RegistrationResource1 {

    @GET
    public Response getRegisteredIncidents(@PathParam("incidentId") String incidentId) {
           ...
    }
}

@Path("/incidents/registration/download")
public class RegistrationResource {

    @GET
    public Response downloadRegistrationIncidentsReport() {
           ...
    }
}

但是,我不建议像那样拆分控制器。相反,只需要在每个函数中删除尽可能多的代码来分离业务逻辑类。