在EJB中正确使用有状态会话Bean

时间:2013-09-10 14:11:52

标签: jsf java-ee web-applications jpa ejb

我正在尝试构建一个测试网站,该网站使用JSF 2.0,EJB 3.1和JPA 2.0显示有关学生的各种信息。

学生登录后,学生可以浏览不同的页面以显示不同类型的信息,这是通常的注册管理系统所做的事情。假设根据一个页面中的登记信息显示时间表,并在另一个页面中显示分配。将显示的信息包括学生的属性,映射的实体,如注册课程,提交的作业等。

首先,我尝试创建一个无状态bean并获取每个页面所需的信息,并更改学生的一些属性

@Entity
public class Student{
    @Id
    private String sid;
    private String address;
    @ManyToMany
    private List<Assignment> submittedAssignments;
    @ManyToMany
    private List<Course> courses;
}
@Stateless
@LocalBean
public class studentDao {
    @PersistenceContext(unitName="PU")
    private EntityManager em;

    public Student getStudent(String sid){
        return em.find(Student.class, sid);
    }
    public List<Course> getCoursesByStudent(String sid){
    return em.find(Student.class, sid).getCourses();
    }
    public List<Assignment> getAssignmentsByStudent(String sid){
        return em.find(Student.class, sid).getSubmittedAssignments();
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void ChangeAddress(String sid, String newAddress){
        em.find(Student.class, sid).setAddress(newAddress);
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void SubmitAssignment(String sid, Assignment submittedAssignment){
    }
    //Some more methods, just list a few for illustration.
}

@ManagedBean
@SessionScoped
public class LoginSession{
    private String sid;
    //getter
    public login(String sid){
        //probably will need password validation later, so I have to connect to db and check the password.
        this.sid=sid;
    }
}

@ManagedBean
@RequestScoped
public class AssignmentBean{
    @EJB
    private StudentDao studentDao;
    @ManagedProperty(value="#{loginSession}")
    private LoginSession session;

    public List<Assignment> getAssignments(){
        return studentDao.getAssignmentsByStudent(session.sid);
    }
}

assignment.xhtml:

<h:datatable value="#{assignmentBean.assignments}"></h:datatable>

然后,我发现将学生从托管bean传递给无状态ejb,一次又一次地检索学生,然后只将一部分信息返回给ManagedBean进行显示是相当繁琐的,因此我想我可以这样做。

@Stateful
@LocalBean
public class studentDao {
    @PersistenceContext(unitName="PU", type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    private Student currentStudent;

    public void login(String sid){
        //didn't make a password, just type sid and done.
        currentStudent = em.find(Student.class, sid);
    }
    public Boolean getLoggedIn(){
        return currentStudent != null;
    }
    public Student getCurrentStudent(){
        return currentStudent;
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void ChangeAddress(String newAddress){
        currentStudent.setAddress(newAddress);
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void SubmitAssignment(Assignment submittedAssignment){
    }
}

@ManagedBean
@SessionScoped
public class LoginSession{
    @EJB
    private StudentDao studentDao;

    public login(String sid){
        studentDao.login(sid);
    }
}

assignment.xhtml:

<h:datatable value="#{loginSession.studentDao.currentStudent.submittedAssignments}"></h:datatable>

由于currentStudent与扩展持久化上下文一起存在,我可以直接检索信息。并且我不必为每个操作一次又一次地将SID传递给EJB,也适用于一次又一次地找到该学生,因为它已经在那里管理。

我不确定是否滥用@Stateful bean,因为网页是一大堆对话,不像普通的购物车&#34;例如,用户可以选择大量订单,进行付款,然后在验证和用户确认后提交所有数据库更改。

请评论上述SFSB用法是否滥用SFSB以及为什么如果是滥用,或者上述两种设计中的哪一种更好(或者如果两者都不好则建议另一种,因为我是第一次写作一个Web应用程序,从废料开始,但是来自Apress的一些书籍,那些以Pro,EJB3,JPA,JSF,带有glassfish等的Java EE 6开头的那些书。)

谢谢。

1 个答案:

答案 0 :(得分:1)

如果您使用有状态会话bean,EJB容器代表您的客户端管理状态,因此不需要传递ID:它更舒服。

在你的情况下,没关系。

一般来说,请考虑以下事项:

  • 无状态服务有时候更容易测试:如果你编写测试用例,则不必考虑对状态的副作用。
  • 如果有状态会话bean包含缓存数据,则必须处理缓存失效。
  • 如果您的会话bean是@Remote:如果客户端和服务器不在同一个JVM上,则每个方法调用都需要编组,然后通过网络。
  • 如果您有许多有状态会话消耗服务器端的资源:您已经有两个List,其数量和内容很可能随着时间的推移而增长。使用无状态设置,您可以设计一个仅在浏览器中管理状态的应用程序,例如。
  • 如果其他人正在使用您的舒适状态API,并且您必须在以后进行更改,那么您将进行无休止的讨论。

由于这些原因,我总是更喜欢使用数据传输对象的无状态设置。但同样,在你的情况下,没关系。