JSF设计和@Stateless @EJB @PersistenceContext解释/用法

时间:2015-09-09 14:43:54

标签: jsf java-ee jpa ejb

我正在使用JSF(2.2)和EclipseLink(JPA 2.1)使用NetBeans 8.0.2构建Web应用程序。

让我们假设当前功能是安静的基本包含:登录,注销,注册,用户角色,仅供管理员使用的页面(通过使用过滤器)等。

我已经阅读过maaany SO Q& A(主要来自@BalusC,谢谢!)并且想验证我的设计是否正确/遵循最佳做法。

目前我有:

用户实体(UserEntity.java)

也许这个名字是多余的,但我想要一个明显的名称开头),对应于数据库中的用户:

@Entity
@Table(name = "Users")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "UserEntity.findAll", query = "SELECT u FROM UserEntity u")...})

public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "userID")
    private Integer userID;
    ...
}

用户bean(User.java)

它使用UserService并保留相关的UserEntity。它的方法用于.xhtml文件的EL

@ManagedBean(name = "user")  // name not needed here, but I kind of like it
@SessionScoped
public class User implements Serializable {
    private UserEntity userEntity;      // with getter or make this public to be accessed directly from EL?

    public String login() {
        userEntity = UserService.find(username);
        ...
    }
    ...
}

和UserService.java

基本上有数据库访问方法:

public class UserService {
    public static String insertUser(UserEntity user) {
            String retMessage;
            EntityManager em = JPAResource.factory.createEntityManager();
            EntityTransaction tx = em.getTransaction();

            tx.begin();
            try {
                em.persist(user);
                tx.commit();
                retMessage = "ok";
                return retMessage;
            }
            catch (PersistenceException e) {
                if (tx.isActive()) tx.rollback();
                retMessage = e.getMessage();
                return retMessage;
            }
            finally {
                em.close();
            }
    }
    ...
}

在某些时候,我注意到UserService只能有静态方法,因此我可以在不创建实例的情况下访问它们。

这很糟糕,为什么?

我想正确的方法是将UserService作为:     import javax.ejb.TransactionAttribute;     import javax.ejb.TransactionAttributeType;     ...

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public static String insertUser(UserEntity user)
    {
        em.persist(user);
    }
    ...
}

用户bean为:

@ManagedBean(name = "user")
@SessionScoped
public class User implements Serializable {
    @EJB
    private UserEntity userEntity;

    public String login() {
        userEntity = UserService.find(username);
        ...
    }
    ...
}

这是对的吗?

我不确定@Stateless@EJBPersistenceContext到底是什么意思。 (它们分别来自javax.ejb.Statelessjavax.ejb.EJBjavax.persistence.PersistenceContext吗?)

使用@Stateless@EJB是否允许我使用UserService而不创建实例并且没有静态方法?

检查交易怎么样? @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)是否涵盖了我?即无需进一步检查?如果抛出异常,方法return会带有相关消息吗?

使用@PersistenceContext,创建EntityManager实例的人/谁?

这种设计是否是良好的做法,尊重关注点的分离等?

谢谢!

另见:

1 个答案:

答案 0 :(得分:1)

@Stateless是替代静态方法的方法。如果您使用NetBeans,您可以自动生成这些@Stateless类,它们在那里称为外观(在NetBeans中 - >右键单击pacakge - > new - >实体类的会话bean并选择实体)。

您不能自己创建EJB个实例,只需使用@EJB注释,容器就会为您提供实例"。

对于您有单独注释的交易,您可以阅读javax.ejb.TransactionAttribute。您只需使用EJB注释javax.ejb.TransactionAttributeType类/方法并给予@SessionScoped以及所有内容,容器将为您开始/结束/嵌套(阻止)事务。

对于关于@RequestScoped的部分,它可以是您的控制器。我们假设您有5个xhtml页面。然后创建5个支持bean(@ViewScoped / @Inject等),并在每个控制器类中使用EJB。因此,您的支持bean将其逻辑范围缩小到仅1页,然后将进一步的操作转发给控制器类。 Controller类可以有只有1行的方法(API),它将操作转发到@Stateful。在EJB中,您可以使用与此控制器通信的服务(@Stateless),此服务与其他类进行通信(如先前支持bean,但现在只需将其称为管理器),并且管理器具有业务逻辑。此逻辑可以通过先前生成的外观(EJB)将数据持久保存到数据库中。

您不需要使用javax.annotation.security.RolesAllowed过滤器来控制角色,您可以使用注释@ManagedBean并指定哪个角色可以调用哪个方法。

这是我的观点,它可能不是很复杂的解释,但有很多工作人员可以使用关键字进行谷歌搜索。

编辑:

不要使用@ManagedProperty@Named等JSF注释。更好地使用CDI @Inject和{{1}}等新技术。