Creating master-detail pages for entities, how to link them and which bean scope to choose

后端 未结 2 1364
礼貌的吻别
礼貌的吻别 2020-11-21 06:26

I have started learning JSF, but sadly most tutorials out there present only a log in or a register section.

Can you point me to some more in depth examples? One thi

2条回答
  •  难免孤独
    2020-11-21 06:46

    What is the correct usage of session scope

    Use it for session scoped data only, nothing else. For example, the logged-in user, its settings, the chosen language, etcetera.

    See also:

    • How to choose the right bean scope?

    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?

    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 , then the request scope is fine. A view scoped bean would behave like a request scoped when there's no anyway.

    All "view product" and "edit product" links/buttons which just retrieve information (i.e. idempotent) whould be just plain GET / wherein you pass the entity identifier as a request parameter by .

    All "delete product" and "save product" links/buttons which will manipulate information (i.e. non-idempotent) should perform POST by / (you don't want them to be bookmarkable/searchbot-indexable!). This in turn requires a . 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.

    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;
    
        // ...
    }
    

    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 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));
        }
    
        // ...
    }
    

    You can have this "view products" on /products.xhtml:

    
        #{product.id}
        #{product.name}
        #{product.description}
        
            
                
            
        
    
    
    @Named
    @RequestScoped
    public class ViewProducts {
    
        private List products; // +getter
    
        @EJB
        private ProductService productService;
    
        @PostConstruct
        public void init() {
            products = productService.list();
        }
    
        // ...
    }
    

    And you can have this "edit product" on /products/edit.xhtml:

    
        
    
    
    
    
    
        
        ...
        
    
    
    @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";
        }
    
        // ...
    }
    

    And this converter for 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);
            }
        }
    
    }
    

    You can even use a generic converter, this is explained in Implement converters for entities with Java Generics.

    See also:

    • 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

提交回复
热议问题