为实体创建主 - 详细信息页面,如何链接它们以及选择哪个bean范围

时间:2011-12-10 21:10:35

标签: jsf session scope master-detail

我已经开始学习JSF,但遗憾的是大多数教程只提供登录或注册部分。

你能指点我一些更深入的例子吗?我感兴趣的一件事是一个显示产品列表的页面。我在页面主页,然后按产品页面,以便我可以看到添加的最新产品。每次访问该页面时,都会根据数据库中的最新条目创建产品列表。我怎么处理这个?

解决此问题的一种方法是创建一个会话范围的托管bean,在其中我将通过其他托管bean更新不同的实体。我在一些教程中发现了这种方法,但看起来很困难而且很笨拙。

哪种方法可以解决这样的问题?在两页主从细节用户界面中,会话范围的正确用法是什么?

2 个答案:

答案 0 :(得分:52)

  

会话范围的正确用法是什么

仅用于会话作用域数据,没有别的。例如,登录用户,其设置,所选语言等。

另见:


  

每次访问该页面时,都会根据数据库中的最新条目创建产品列表。我该如何处理?

通常,您可以使用请求或查看范围。加载列表应该以{{1​​}}方法进行。如果页面不包含任何@PostConstruct,则请求范围正常。无论如何,当没有<h:form>时,视图范围的bean将表现为请求范围。

所有“查看产品”和“编辑产品”链接/按钮只是检索信息(即幂等)只是简单的GET <h:form> / <h:link>你通过实体标识符为<h:button>的请求参数。

所有“删除产品”和“保存产品”链接/按钮操纵信息(即非幂等)应该<f:param> / <h:commandLink>执行POST(您不希望它们是可收藏的/ searchbot-indexable!)。这又需要<h:commandButton>。为了保留验证和ajax请求的数据(这样你不需要在每个请求上重新加载/预初始化实体),bean应该最好是视图范围。

请注意,每个视图基本上应该有一个单独的bean,并且还要注意那些bean不一定需要相互引用。

所以,鉴于这个“产品”实体:

<h:form>

这个“产品服务”EJB:

@Entity
public class Product {

    @Id
    private Long id;
    private String name;
    private String description;

    // ...
}

您可以在@Stateless public class ProductService { @PersistenceContext private EntityManager em; public Product find(Long id) { return em.find(Product.class, id); } public List<Product> list() { return em.createQuery("SELECT p FROM Product p", Product.class).getResultList(); } public void create(Product product) { em.persist(product); } public void update(Product product) { em.merge(product); } public void delete(Product product) { em.remove(em.contains(product) ? product : em.merge(product)); } // ... } 上使用此“查看产品”:

/products.xhtml
<h:dataTable value="#{viewProducts.products}" var="product">
    <h:column>#{product.id}</h:column>
    <h:column>#{product.name}</h:column>
    <h:column>#{product.description}</h:column>
    <h:column>
        <h:link value="Edit" outcome="/products/edit">
            <f:param name="id" value="#{product.id}" />
        </h:link>
    </h:column>
</h:dataTable>

您可以在@Named @RequestScoped public class ViewProducts { private List<Product> products; // +getter @EJB private ProductService productService; @PostConstruct public void init() { products = productService.list(); } // ... } 上使用此“编辑产品”:

/products/edit.xhtml
<f:metadata>
    <f:viewParam name="id" value="#{editProduct.product}" 
        converter="#{productConverter}" converterMessage="Unknown product, please use a link from within the system."
        required="true" requiredMessage="Bad request, please use a link from within the system."
    />
</f:metadata>

<h:messages />

<h:form rendered="#{not empty editProduct.product}>
    <h:inputText value="#{editProduct.product.name}" />
    <h:inputTextarea value="#{editProduct.product.description}" />
    ...
    <h:commandButton value="save" action="#{editProduct.save}" />
</h:form>

此编辑产品@Named @ViewScoped public class EditProduct { private Product product; // +getter +setter @EJB private ProductService productService; public String save() { productService.save(product); return "/products?faces-redirect=true"; } // ... } 的转换器:

<f:viewParam>

您甚至可以使用通用转换器,这在Implement converters for entities with Java Generics中进行了解释。

另见:

答案 1 :(得分:0)

作为对BalusC推荐的一项小改进,有时您可以从{&n; 34;详细信息&#34;的<Assembly: Obfuscation(Feature:="encrypt symbol names with password XXXX", Exclude:=False)> 中移除required / requiredMessage部分。屏幕,而是使用编辑表单的条件呈现(如BalusC所做的),具有反向条件,用于推荐&#34; list / master&#34;屏幕或甚至使用一个viewAction来测试param并强制重定向到该列表。