1

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

学生登录后,可以浏览不同的页面,显示不同的信息,这就是通常的注册管理系统所做的。比如说在一个页面中根据注册信息显示时间表,在另一页面中显示作业。将显示的信息包括学生的属性、映射的实体(如注册课程、提交的作业等)。

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

@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);
    }
}

分配.xhtml:

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

然后,我发现将student从托管bean传递到无状态ejb,一次又一次地检索student,然后只返回一部分信息给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);
    }
}

分配.xhtml:

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

由于currentStudent具有扩展的持久性上下文,我可以直接检索信息。而且我不必为每个操作一次又一次地将 SID 传递给 EJB,也一次又一次地申请找到那个学生,因为它已经在那里被管理了。

我不确定这是否是对@Statefulbean 的滥用,因为页面是一大群对话,不像常见的“购物车”示例,用户可以选择很多订单,付款,然后在验证后提交所有数据库更改,用户确认。

请评论上述 SFSB 的使用是否是对 SFSB 的滥用以及为什么是滥用,或者上述两种设计中哪一种更好(或者如果两者都不好,因为我是第一次编写 Web 应用程序,请建议另一种从废品开始,但从 Apress 的几本书开始,那些从 Pro 开始,EJB3、JPA、JSF、Java EE 6 和 glassfish 等)。

谢谢你。

4

1 回答 1

1

如果您使用有状态会话 bean,EJB 容器会代表您的客户端管理状态,因此无需传递 ID:这样更方便。

在你的情况下,没关系。

一般来说,考虑以下项目:

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

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

于 2013-09-13T13:14:15.207 回答