J'essaie de m'habituer au fonctionnement de JSF en ce qui concerne l'accès aux données (provenant d'un fond de printemps)
Je crée un exemple simple qui maintient une liste d'utilisateurs, j'ai quelque chose comme
<h:dataTable value="#{userListController.userList}" var="u">
<h:column>#{u.userId}</h:column>
<h:column>#{u.userName}</h:column>
</h:dataTable>
Ensuite, le "contrôleur" a quelque chose comme
@Named(value = "userListController")
@SessionScoped
public class UserListController {
@EJB
private UserListService userListService;
private List<User> userList;
public List<User> getUserList() {
userList = userListService.getUsers();
return userList;
}
}
Et le "service" (bien qu'il ressemble plus à un DAO) a
public class UserListService {
@PersistenceContext
private EntityManager em;
public List<User> getUsers() {
Query query = em.createQuery("SELECT u from User as u");
return query.getResultList();
}
}
Est-ce la bonne façon de faire les choses? Ma terminologie est-elle correcte? Le "service" ressemble plus à un DAO? Et le contrôleur a l'impression de faire une partie du travail du service.
Est-ce la bonne façon de faire les choses?
Hormis la mise en œuvre de la logique métier de manière inefficace dans une méthode getter de bean managé et l'utilisation d'une portée de bean managé trop large, cela semble correct. Si vous déplacez l'appel de service de la méthode getter vers un @PostConstruct
méthode et utilisez soit @RequestScoped
ou @ViewScoped
au lieu de @SessionScoped
, ça va mieux.
Ma terminologie est-elle correcte?
Ça va. Tant que vous y êtes cohérent et que le code est lisible de manière sensée. Seule votre façon de nommer les classes et les variables est quelque peu maladroite (illogique et/ou duplication). Par exemple, personnellement, j'utiliserais users
au lieu de userList
, et j'utiliserais var="user"
au lieu de var="u"
, et utilisez id
et name
au lieu de userId
et userName
. En outre, un "UserListService" sonne comme s'il ne pouvait traiter que des listes d'utilisateurs au lieu des utilisateurs en général. Je préfère utiliser "UserService" afin que vous puissiez également l'utiliser pour créer, mettre à jour et supprimer des utilisateurs.
Le "service" ressemble plus à un DAO?
Ce n'est pas exactement un DAO. Fondamentalement, JPA est le véritable DAO ici. Auparavant, lorsque JPA n'existait pas, tout le monde a créé des interfaces DAO afin que les méthodes de service puissent continuer à les utiliser même lorsque l'implémentation sous-jacente ("plain old" JDBC, ou "good old" Hibernate, etc.) change. La vraie tâche d'une méthode de service est de gérer de manière transparente les transactions. Ce n'est pas la responsabilité du DAO.
Et le contrôleur a l'impression de faire une partie du travail du service.
Je peux imaginer qu'il fait cela dans cette configuration relativement simple. Cependant, le contrôleur fait en fait partie du frontend et non du backend. Le service fait partie du backend qui doit être conçu de manière à être réutilisable sur tous les frontends différents, tels que JSF, JAX-RS, Jlet + Servlet "plain", même Swing, etc. En outre, le contrôleur spécifique au frontend ( également appelé "backing bean" ou "présentateur") vous permet de traiter de manière spécifique au frontend des succès et/ou des résultats exceptionnels, comme dans le cas de JSF affichant un message de visages en cas d'exception levée par un service.
Dans l'ensemble, l'approche correcte serait comme ci-dessous:
<h:dataTable value="#{userBacking.users}" var="user">
<h:column>#{user.id}</h:column>
<h:column>#{user.name}</h:column>
</h:dataTable>
@Named
@RequestScoped // Use @ViewScoped once you bring in ajax (e.g. CRUD)
public class UserBacking {
private List<User> users;
@EJB
private UserService userService;
@PostConstruct
public void init() {
users = userService.listAll();
}
public List<User> getUsers() {
return users;
}
}
@Stateless
public class UserService {
@PersistenceContext
private EntityManager em;
public List<User> listAll() {
return em.createQuery("SELECT u FROM User u", User.class).getResultList();
}
}
Vous pouvez trouver ici un projet de lancement réel en utilisant ici les pratiques canoniques Java EE/JSF/CDI/EJB/JPA: application de lancement Java EE .
C'est un dao, enfin un dépôt mais ne vous inquiétez pas trop de cette différence, car il accède à la base de données en utilisant le contexte de persistance.
Vous devez créer une classe de service, qui encapsule cette méthode et où les transactions sont appelées.
Parfois, les classes de service ne semblent pas nécessaires, mais lorsque vous avez une méthode de service qui appelle de nombreuses méthodes dao, leur utilisation est plus garantie.
Normalement, je finis par créer le service, même si cela ne semble pas nécessaire, pour garantir que les modèles restent les mêmes et que le dao n'est jamais injecté directement.
Cela ajoute une couche supplémentaire d'abstraction rendant la refactorisation future plus flexible.