JSF控制器,服务和DAO

我正在尝试习惯JSF如何处理访问数据(来自spring的背景)

我正在创build一个维护用户列表的简单示例,我有类似的东西

<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? pipe理员觉得它正在做一些服务的工作。

这是做事的正确方法吗?

除了在托pipebean getter方法中执行业务逻辑效率低下以及使用过于宽泛的托pipebean范围之外,它看起来没问题。 如果将服务调用从getter方法移动到@PostConstruct方法,并使用@RequestScoped@ViewScoped而不是@SessionScoped ,则会更好。

也可以看看:

  • 为什么JSF多次调用getters
  • 如何select合适的bean范围?

我的术语是对的吗?

没关系。 只要你符合它,代码是可读的合理的方式。 只有你命名类和variables的方式有些尴尬(不合逻辑和/或重复)。 例如,我个人会使用users而不是userList ,并使用var="user"而不是var="u" ,并使用idname来代替userIduserName 。 此外,“UserListService”听起来像它只能处理用户列表,而不是一般用户。 我宁愿使用“UserService”,所以你也可以用它来创build,更新和删除用户。

也可以看看:

  • JSFpipe理的bean命名约定

“服务”更像是一个DAO?

这不完全是一个DAO。 JPA基本上是真正的DAO。 以前,当JPA不存在的时候,每个人都会自定义DAO接口,这样服务方法即使在基础实现(“普通旧式”JDBC或“老式”Hibernate等)改变时也能继续使用它们。 服务方法的真正任务是透明地pipe理事务。 这不是DAO的责任。

也可以看看:

  • 我发现JPA,或类似的,不鼓励DAO模式
  • DAO和JDBC的关系?
  • 什么时候使用Spring或者EJB3或者全部使用它们是必要的还是方便的?

pipe理员觉得它正在做一些服务的工作。

我可以想象,这是在这个相对简单的设置。 但是,控制器实际上是前端的一部分,而不是后端。 这个服务是后端的一部分,应该这样devise,使得它可以在所有不同的前端(如JSF,JAX-RS,“普通”的JSP + Servlet,甚至是Swing等)中重用。而且,前端特定的控制器也称为“支持bean”或“演示者”)允许您以成功和/或特殊结果的方式处理前端特定的方式,例如在JSF的情况下显示面部消息以防从服务抛出exception。

也可以看看:

  • JSF服务层
  • JSF MVC框架中的MVC是什么组件?

总而言之,正确的做法如下:

 <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 (eg 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(); } } 

您可以在这里find一个真正的世界启动项目,这里使用规范的Java EE / JSF / CDI / EJB / JPA实践: Java EE启动应用程序 。

也可以看看:

  • 为实体创build主 – 细节页面,如何链接它们以及select哪个bean范围
  • 将JSF2托pipe的pojo bean传递到EJB中,或将所需的东西放入传输对象中
  • filter不会初始化EntityManager
  • javax.persistence.TransactionRequiredException在小的Facelet应用程序中

这是一个道, 实际上是一个存储库,但不要太担心这种差异,因为它使用持久化上下文访问数据库。

您应该创build一个服务类,该类包装该方法,并且是调用事务的地方。

有时服务类是不必要的,但是当你有一个调用多个dao方法的服务方法时,它们的使用是更有保证的。

我通常最终只是创build服务,即使它觉得没有必要,确保模式保持不变,而且dao永远不会被直接注入。

这增加了一个额外的抽象层,使未来的重构更灵活。