Ich habe eine JAX-RS-REST-API mit mehreren Unterressourcen, z.Wie mit mehreren Subressourcen in JAX-RS umzugehen?
users/{user_id}/posts/{post_id}/comments/{comment_id}
. Die Ressourcen sind in einzelne Klassen (UsersResource
, UserResource
, PostsResource
usw.) unterteilt und werden über Sub-Resource-Locators angesprochen. Jede Ressource verwendet einen Korrelationsdienst (UserService
, PostService
, CommentService
), um auf die Datenbank zuzugreifen.
Wie würde ich das realisieren? Ich habe versucht, nach einem Beispiel zu suchen, konnte aber nur sehr einfache finden.
Ich habe bereits mehrere Ansätze implementiert, aber alle "fühlen" sich falsch.
Eine war, alle Dienste in die Wurzelressource zu injizieren und sie weiterzugeben. Es scheint jedoch verschwenderisch, alle Dienste zu instanziieren, obwohl nur die erste benötigt wird.
Eine andere war, alle Ressourcen @RequestScoped
zu machen und die nachfolgende Ressource zu injizieren, damit der richtige Dienst an der richtigen Stelle injiziert werden kann. Aber ich müsste die Unterressource im Voraus injizieren, selbst wenn ich sie nicht brauchte und ich wäre nicht in der Lage, Parameter weiterzugeben.
Mein aktueller Ansatz schlägt fehl, den Dienst nicht in meine Unterressource zu injizieren. (Siehe unten)
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));
}
Service Beispiel
@Stateless
public class UserService {
@PersistenceContext
private EntityManager em;
(...)
}
wird Betrachtet man, wie Sie es eingerichtet haben, kann ich nicht helfen, aber das Gefühl, dass Sie das Set-up selbst zu kompliziert haben. Ich hätte eine gesamte "API" -Ressource auf der Ebene von UsersResource erstellt und alle Dienste auf dieser Ebene injiziert und dann den Inhalt der Unterressourcen auch auf dieser Ebene zugeordnet. – Compass
Mein Grund war nur, dass ich sie nicht instanziieren wollte, wenn ich nicht müsste. Die Wurzelressource müsste eine Instanz für jeden möglichen Dienst erstellen, selbst wenn die Anforderung für den Stamm selbst gedacht ist. – aaeeiioouu
Die Idee hinter der Verwendung mehrerer Dienste in einer Ressource ist nicht, dass Sie sie alle jetzt brauchen werden, aber Sie werden sie auf jeden Fall irgendwann brauchen, damit sie bereit sind zu gehen, wenn sie gebraucht werden.Ihr Server wird eine einzelne Instanz Ihrer UsersResource für alle Benutzer ausführen, aber im Moment schlagen Sie vor, UserResource und PostResource von kurzer Dauer auf Abruf bereitzustellen, was nach dem Abschluss nicht mehr möglich ist , die erheblich teurer ist als eine einzelne Ressource. – Compass