我已经开始学习JSF,但遗憾的是大多数教程只提供登录或注册部分。
你能指点我一些更深入的例子吗?我感兴趣的一件事是一个显示产品列表的页面。我在页面主页,然后按产品页面,以便我可以看到添加的最新产品。每次访问该页面时,都会根据数据库中的最新条目创建产品列表。我怎么处理这个?
解决此问题的一种方法是创建一个会话范围的托管bean,在其中我将通过其他托管bean更新不同的实体。我在一些教程中发现了这种方法,但看起来很困难而且很笨拙。
哪种方法可以解决这样的问题?在两页主从细节用户界面中,会话范围的正确用法是什么?
答案 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并强制重定向到该列表。