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

TGM*_*TGM 25 session jsf scope master-detail

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

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

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

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

Bal*_*usC 53

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

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

也可以看看:


每次访问该页面时,都会根据数据库中的最新条目创建产品列表.我怎么处理这个?

通常,您使用请求或查看范围.列表的加载应该在@PostConstruct方法中进行.如果页面不包含任何内容<h:form>,那么请求范围就可以了.<h:form>无论如何,视图范围的bean的行为就像一个请求作用域.

检索信息(即幂等)的所有"查看产品"和"编辑产品"链接/按钮都应该是简单的GET <h:link>/ <h:button>其中您将实体标识符作为请求参数传递<f:param>.

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

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

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

@Entity
public class Product {

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

    // ...
}
Run Code Online (Sandbox Code Playgroud)

而这个"产品服务"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));
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

你可以拥有这个"查看产品" /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>
Run Code Online (Sandbox Code Playgroud)
@Named
@RequestScoped
public class ViewProducts {

    private List<Product> products; // +getter

    @EJB
    private ProductService productService;

    @PostConstruct
    public void init() {
        products = productService.list();
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

你可以在这个"编辑产品"上/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>
Run Code Online (Sandbox Code Playgroud)
@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";
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这个转换器为<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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

也可以看看: