Ответ 1
Как правильно использовать область сеанса
Используйте его только для данных сессий, ничего больше. Например, вошедший в систему пользователь, его настройки, выбранный язык и так далее.
Смотрите также:
И каждый раз, когда я захожу на страницу, список товаров будет создаваться из последних записей в базе данных. Как я могу справиться с этим?
Обычно вы используете запрос или просматриваете область действия для него. Загрузка списка должна происходить в методе @PostConstruct
. Если страница не содержит <h:form>
, тогда область запроса в порядке. Бин с областью представления будет вести себя как запрос, если в любом случае <h:form>
.
Все ссылки/кнопки "Просмотр продукта" и "Редактирование продукта", которые просто извлекают информацию (т.е. идемпотент), должны быть просто GET <h:link>
/<h:button>
где вы передаете идентификатор объекта в качестве параметра запроса с помощью <f:param>
.
Все ссылки/кнопки "удалить продукт" и "сохранить продукт", которые будут манипулировать информацией (т.е. не идемпотентными), должны выполнять POST с помощью <h:commandLink>
/<h:commandButton>
(вы не хотите, чтобы они были закладками /searchbot -indexable!). Это в свою очередь требует <h:form>
. Чтобы сохранить данные для проверок и запросов ajax (чтобы вам не нужно было перезагружать/предварительно инициализировать сущность при каждом запросе), боб предпочтительно должен иметь область видимости.
Обратите внимание, что у вас должны быть отдельные компоненты для каждого представления, а также обратите внимание, что эти компоненты не обязательно должны ссылаться друг на друга.
Итак, учитывая этот "продукт" сущность:
@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.save(product);
return "/products?faces-redirect=true";
}
// ...
}
И этот конвертер для <f:viewParam>
из "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.