会话范围的正确用法是什么
仅将其用于会话范围的数据,仅此而已。例如,登录用户、其设置、选择的语言等等。
另见:
而且每次我访问该页面时,都会根据数据库中的最新条目创建产品列表。我该如何处理?
通常您使用请求或视图范围。列表的加载应该在 @PostConstruct 方法中进行。如果页面不包含任何<h:form>,那么请求范围就可以了。当没有 <h:form> 时,视图范围的 bean 的行为类似于请求范围。
检索信息(即幂等)的所有“查看产品”和“编辑产品”链接/按钮都应该是普通的 GET <h:link> / <h:button> 其中您将实体标识符传递为<f:param>的请求参数。
所有将操作信息(即非幂等)的“删除产品”和“保存产品”链接/按钮应由<h:commandLink>/<h:commandButton> 执行 POST(您不希望它们是可收藏的/可搜索机器人索引的!)。这又需要<h:form>。为了保留验证和 ajax 请求的数据(这样您就不需要在每个请求上重新加载/预初始化实体),bean 最好是视图范围。
请注意,基本上每个视图都应该有一个单独的 bean,并且还请注意,这些 bean 不一定需要相互引用。
所以,给定这个“产品”实体:
@Entity
public class Product {
@Id
private Long id;
private String name;
private String description;
// ...
}
还有这个“产品服务”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 上“查看产品”:
<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.update(product);
return "/products?faces-redirect=true";
}
// ...
}
这个转换器用于“编辑产品”的<f:viewParam>:
@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);
}
}
}
您甚至可以使用通用转换器,Implement converters for entities with Java Generics 对此进行了说明。
另见: