【发布时间】:2016-04-21 16:01:32
【问题描述】:
我有一个带有多个子资源的 JAX-RS REST API,例如
users/{user_id}/posts/{post_id}/comments/{comment_id}。资源被划分为单独的类(UsersResource、UserResource、PostsResource 等)并通过子资源定位器访问。每个资源都使用关联服务(UserService、PostService、CommentService)来访问数据库。
我将如何实现这一点?我试图搜索一个示例,但只能找到非常基本的示例。
我已经实现了几种方法,但它们都“感觉”错了。
一个是在根资源中注入所有服务并传递它们。但是实例化所有服务似乎很浪费,尽管可能只需要第一个。
另一个是使所有资源@RequestScoped 并注入后续资源,以便可以在正确的位置注入正确的服务。但是我需要提前注入子资源,即使我不需要它也无法传递参数。
我目前的方法无法将服务注入我的子资源中。 (见下文)
root resource (resources/users)
@RequestScoped
@Path("users")
public class UsersResource() {
@Inject
private UserService service;
@Path("{user_id}")
public UserResource getUserResource(@Context ResourceContext context, @PathParam("user_id") Long id) {
User entity = this.service.find(id);
if (entity == null)
throw new WebApplicationException(Response.status(Status.NOT_FOUND).build());
return context.initResource(new UserResource(entity, this.service));
}
}
user sub resource (resources/users/{user_id})
public class UserResource() {
private User entity;
private UserService service;
public UserResource(User entity, UserService service) {
this.entity = entity;
this.service = service;
}
@GET
public Response doGet() {
return Response.ok(entity).build();
}
@Path("posts")
public TodosResource getPostsResource(@Context ResourceContext context) {
return context.initResource(new PostsResource(entity));
}
}
posts sub resource (resources/users/{user_id}/posts)
public class PostsResource() {
@Inject // can't inject here
private PostService service;
private User user;
public PostsResource(User user) {
this.user = user;
}
@POST
public Response doPost(@Context UriInfo info, Post post) {
post.setUser(this.user);
Post entity = this.service.persist(post);
URI uri = info.getAbsolutePathBuilder().path("/" + entity.getId()).build();
return Response.created(uri).entity(entity).build();
}
@Path("{post_id}")
public PostResource getpostResource(@Context ResourceContext context, @PathParam("post_id") Long id) {
Post entity = this.service.find(id);
if (entity == null)
throw new WebApplicationException(Response.status(Status.NOT_FOUND).build());
return context.initResource(new PostResource(entity));
}
服务示例
@Stateless
public class UserService {
@PersistenceContext
private EntityManager em;
(...)
}
【问题讨论】:
-
看看您的设置方式,我不禁觉得您的设置本身过于复杂。我会在 UsersResource 级别创建一个整体的“API”资源,并在该级别注入所有服务,然后在该级别映射子资源的内容。
-
我的原因是我不想实例化它们,如果我不需要的话。即使请求是针对根本身的,根资源也必须为每个可能的服务创建一个实例。
-
在一个资源中使用多个服务背后的想法并不是你现在就需要它们,但你肯定会在未来某个时候需要它们,所以让它们准备就绪当他们需要的时候。您的服务器将为所有用户运行您的 UsersResource 的单个实例,但目前,您建议在每次调用的基础上提供短暂的 UserResource 和 PostResource,一旦它们完成,这将超出范围,这比保留单个资源的成本要高得多。