Контроллер JSF, Сервис и DAO
Я пытаюсь привыкнуть к тому, как JSF работает в отношении доступа к данным (из весеннего фона)
Я создаю простой пример, который ведет список пользователей, у меня есть что-то вроде
<h:dataTable value="#{userListController.userList}" var="u">
<h:column>#{u.userId}</h:column>
<h:column>#{u.userName}</h:column>
</h:dataTable>
Тогда у "контроллера" есть что-то вроде
@Named(value = "userListController")
@SessionScoped
public class UserListController {
@EJB
private UserListService userListService;
private List<User> userList;
public List<User> getUserList() {
userList = userListService.getUsers();
return userList;
}
}
И "сервис" (хотя это больше похоже на DAO) имеет
public class UserListService {
@PersistenceContext
private EntityManager em;
public List<User> getUsers() {
Query query = em.createQuery("SELECT u from User as u");
return query.getResultList();
}
}
Это правильный способ делать вещи? Правильна ли моя терминология? "Сервис" больше напоминает DAO? И контроллер чувствует, что он выполняет часть работы сервиса.
2 ответа
Это правильный способ делать вещи?
Помимо выполнения бизнес-логики неэффективным способом в методе получения управляемого компонента и использованием слишком широкой области действия управляемого компонента, все выглядит хорошо. Если вы переместите сервисный вызов из метода получения в @PostConstruct
метод и использовать либо @RequestScoped
или же @ViewScoped
вместо @SessionScoped
, это будет выглядеть лучше.
Смотрите также:
Правильна ли моя терминология?
Это нормально. Пока вы согласны с этим и код читается разумным способом. Только ваш способ именования классов и переменных несколько неудобен (нелогично и / или дублирование). Например, я бы лично использовал users
вместо userList
и использовать var="user"
вместо var="u"
и использовать id
а также name
вместо userId
а также userName
, Кроме того, "UserListService" звучит так, как будто он может работать только со списками пользователей, а не с пользователями в целом. Я бы предпочел использовать "UserService", чтобы вы также могли использовать его для создания, обновления и удаления пользователей.
Смотрите также:
"Сервис" больше напоминает DAO?
Это не совсем DAO. По сути, JPA является настоящим DAO здесь. Раньше, когда JPA не существовало, все создавали интерфейсы DAO, чтобы сервисные методы могли продолжать использовать их, даже когда изменяется базовая реализация ("старый добрый" JDBC или "старый добрый" Hibernate и т. Д.). Настоящая задача сервисного метода - прозрачное управление транзакциями. Это не ответственность DAO.
Смотрите также:
- Я обнаружил, что JPA, или что-то подобное, не поддерживает модель DAO
- DAO и JDBC отношения?
- Когда необходимо или удобно использовать Spring или EJB3 или все вместе?
И контроллер чувствует, что он выполняет часть работы сервиса.
Я могу представить, что это происходит в этой относительно простой установке. Однако контроллер на самом деле является частью внешнего интерфейса, а не внутреннего интерфейса. Сервис является частью бэкэнда, который должен быть спроектирован таким образом, чтобы его можно было многократно использовать во всех различных интерфейсах, таких как JSF, JAX-RS, "простой" JSP+ сервлет, даже Swing и т. Д. Кроме того, контроллер, специфичный для внешнего интерфейса (также называемый "поддерживающим компонентом" или "презентатором"), позволяет вам иметь дело с конкретным внешним интерфейсом с успехом и / или исключительными результатами, например, в случае JSF, отображающим сообщение лиц в случае исключения, выданного службой.
Смотрите также:
В общем, правильный подход будет выглядеть так:
<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();
}
}
Здесь вы можете найти настоящий стартовый проект с использованием канонических практик Java EE / JSF / CDI / EJB / JPA: Java EE kickoff app.
Смотрите также:
- Создание основных страниц для сущностей, как их связать и какую область действия bean выбрать.
- Передача управляемого EJB-компонента JSF2 в EJB или помещение того, что требуется, в объект передачи
- Фильтр не инициализирует EntityManager
- javax.persistence.TransactionRequiredException в небольшом приложении Facelet
Это дао, на самом деле это репозиторий, но не стоит слишком беспокоиться об этой разнице, так как он обращается к базе данных, используя контекст постоянства.
Вы должны создать класс обслуживания, который обернет этот метод и будет вызывать транзакции.
Иногда классы обслуживания чувствуют себя ненужными, но когда у вас есть метод обслуживания, который вызывает много методов dao, их использование более оправдано.
Я обычно заканчиваю тем, что просто создавал сервис, даже если он чувствовал себя ненужным, чтобы гарантировать, что шаблоны остаются прежними, и дао никогда не вводится напрямую.
Это добавляет дополнительный уровень абстракции, делая будущий рефакторинг более гибким.