问题描述
我已经开始学习JSF,但不幸的是,那里的大多数教程都只提供了登录或注册部分.
I have started learning JSF, but sadly most tutorials out there present only a log in or a register section.
您能指出我更多的例子吗?我感兴趣的一件事是显示产品列表的页面.我在第 home 页上,然后按第 products 页,以便可以看到最新添加的 products .每次我访问该页面时,都会从数据库中的最新条目创建产品列表.我该如何处理?
Can you point me to some more in depth examples? One thing I'm interested in is a page presenting a list of products. I'm on page home and I press on page products so that I can see the latest products added. And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
解决此问题的一种方法是创建一个会话范围的托管bean,在其中放置通过其他托管bean更新的不同实体.我在一些教程中发现了这种方法,但似乎很困难而且笨拙.
One way to solve this would be to create a session scoped managed bean in which I would place different entities updated through other managed beans. I found this kind of approach in some tutorials, but it seems quite difficult and clumsy.
哪种方法是解决此类问题的最佳方法?两页主从用户界面中会话作用域的正确用法是什么?
Which would be the best approach to solve a thing like this? What is the correct usage of session scope in two-page master-detail user interface?
推荐答案
仅将其用于会话范围的数据,仅此而已.例如,登录用户,其设置,选择的语言等.
Use it for session scoped data only, nothing else. For example, the logged-in user, its settings, the chosen language, etcetera.
通常,您使用请求或视图范围.列表的加载应以@PostConstruct
方法进行.如果页面不包含任何<h:form>
,则请求范围很好.无论如何,在没有<h:form>
的情况下,视图作用域的bean的行为就像请求作用域的行为.
Typically you use the request or view scope for it. Loading of the list should happen in a @PostConstruct
method. If the page doesn't contain any <h:form>
, then the request scope is fine. A view scoped bean would behave like a request scoped when there's no <h:form>
anyway.
所有查看产品"和编辑产品"的链接/按钮只是获取信息(即幂等),它们应该只是普通的GET <h:link>
/<h:button>
,其中您将实体标识符作为<f:param>
的请求参数.
All "view product" and "edit product" links/buttons which just retrieve information (i.e. idempotent) whould be just plain GET <h:link>
/ <h:button>
wherein you pass the entity identifier as a request parameter by <f:param>
.
所有将操纵信息(即非幂等)的删除产品"和保存产品"链接/按钮都应通过<h:commandLink>
/<h:commandButton>
执行POST(您不希望这样做)它们可以添加为书签/searchbot-indexable!).这又需要<h:form>
.为了保留用于验证和ajax请求的数据(这样您就不必在每个请求上都重新加载/预初始化实体),最好应将bean视为作用域.
All "delete product" and "save product" links/buttons which will manipulate information (i.e. non-idempotent) should perform POST by <h:commandLink>
/<h:commandButton>
(you don't want them to be bookmarkable/searchbot-indexable!). This in turn requires a <h:form>
. In order to preserve the data for validations and ajax requests (so that you don't need to reload/preinitialize the entity on every request), the bean should preferably be view scoped.
请注意,基本上每个视图都应该有一个单独的bean,并且还要注意,这些bean不一定需要互相引用.
Note that you should basically have a separate bean for each view and also note that those beans doesn't necessarily need to reference each other.
因此,鉴于此产品"实体:
So, given this "product" entity:
@Entity
public class Product {
@Id
private Long id;
private String name;
private String description;
// ...
}
这个产品服务" EJB:
And this "product service" EJB:
@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
上使用此查看产品":
You can have this "view products" on /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
上使用此编辑产品":
And you can have this "edit product" on /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>
:
And this converter for <f:viewParam>
of "edit product":
@Named
@RequestScoped
public class ProductConverter implements Converter {
@EJB
private ProductService productService;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
Long id = Long.valueOf(value);
return productService.find(id);
} catch (NumberFormatException e) {
throw new ConverterException("The value is not a valid Product ID: " + value, e);
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
if (value instanceof Product) {
Long id = ((Product) value).getId();
return (id != null) ? String.valueOf(id) : null;
} else {
throw new ConverterException("The value is not a valid Product instance: " + value);
}
}
}
您甚至可以使用通用转换器,这在中实现Java Generics的实体.
You can even use a generic converter, this is explained in Implement converters for entities with Java Generics.
- JSF控制器,服务和DAO
- JSF服务层
- 如何注入@ EJB,@ PersistenceContext, @FacesConverter中的@ Inject,@ Autowired等?
- JSF 2.0中的通信-包含多个示例/提示
- How to navigate in JSF? How to make URL reflect current page (and not previous one)
- JSF Controller, Service and DAO
- JSF Service Layer
- How to inject @EJB, @PersistenceContext, @Inject, @Autowired, etc in @FacesConverter?
- Communication in JSF 2.0 - Contains several examples/hints
这篇关于为实体创建主从页面,如何链接它们以及选择哪个bean作用域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!