Как обновить страницу ViewScoped (Omnifaces) при изменении данных? - PullRequest
0 голосов
/ 26 июня 2018

У меня есть некоторая модель категории, которая организована в виде списка смежности. Поэтому, когда я добавляю новый, я форматирую текущий список, чтобы он имел видимую иерархию. Для этого я использую Omnifaces ViewScoped bean. После загрузки данных я форматирую их и отображаю в selectOneMenu. Когда я добавляю новую категорию, у которой есть родитель, я перенаправляю в список категорий. Если я снова открою страницу формы, она не отображает новую иерархию, но ставит новую категорию в конец, как будто у нее нет родителя. Например, если я перезагружаю сервер и снова загружаю страницу, она отображается так, как должна.

Так что мой вопрос в том, как мне обновить его должным образом, поскольку, очевидно, я делаю это неправильно.

form.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:p="http://primefaces.org/ui"
                template="#{adminConfig.templatePath}"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:f="http://xmlns.jcp.org/jsf/core"> 

    <ui:define name="title">#{categoryFormMB.title}</ui:define>

    <ui:define name="description"></ui:define>

    <ui:define name="body">
        <f:metadata>
            <f:viewParam name="id" value="#{categoryFormMB.id}" converter="javax.faces.Long"/>

            <f:event type="preRenderView" listener="#{categoryFormMB.initForm()}"/>
        </f:metadata>

        <div class="row">
            <div class="col-md-6">
                <p:panel styleClass="box box-primary">
                    <h:form styleClass="form-horizontal">
                        <div class="form-group ui-flat">
                            <p:outputLabel 
                                for="name" 
                                value="#{label.categoryName}" 
                                styleClass="control-label col-md-4"/>

                            <div class="col-md-8">
                                <p:inputText 
                                    id="name" 
                                    value="#{categoryFormMB.category.name}" 
                                    styleClass="form-control" 
                                    required="true" />
                            </div>
                        </div>

                        <div class="form-group ui-flat">
                            <p:outputLabel 
                                for="slug" 
                                value="#{label.categorySlug}" 
                                styleClass="control-label col-md-4"/>

                            <div class="col-md-8">
                                <p:inputText 
                                    id="slug" 
                                    value="#{categoryFormMB.category.slug}" 
                                    styleClass="form-control" 
                                    required="true" />
                            </div>
                        </div>

                        <div class="form-group ui-flat">
                            <p:outputLabel 
                                for="parent"
                                value="#{label.parentCategory}"
                                styleClass="control-label col-md-4"/>

                            <div class="col-md-8">
                                <p:selectOneMenu 
                                    value="#{categoryFormMB.category.parent}" 
                                    id="parent" 
                                    converter="categoryConv">
                                    <f:selectItem 
                                        itemLabel="#{label.noParent}" 
                                        itemValue=""/>

                                    <f:selectItems 
                                        value="#{categoryFormMB.formattedList}" 
                                        var="category" 
                                        itemValue="#{category}" 
                                        itemLabel="#{category.name}"/>
                                </p:selectOneMenu>
                            </div>
                        </div>

                        <div class="form-group ui-flat">
                            <p:outputLabel 
                                for="description" 
                                value="#{label.categoryDescription}" 
                                styleClass="control-label col-md-4"/>

                            <div class="col-md-8">
                                <p:inputTextarea 
                                    id="description"
                                    value="#{categoryFormMB.category.description}" 
                                    styleClass="form-control"/>
                            </div>
                        </div>

                        <div class="form-group ui-flat">
                            <p:outputLabel 
                                for="title-tag" 
                                value="#{label.titleTag}" 
                                styleClass="control-label col-md-4"/>

                            <div class="col-md-8">
                                <p:inputText
                                    id="title-tag"
                                    value="#{categoryFormMB.category.titleTag}" 
                                    styleClass="form-control"/>
                            </div>
                        </div>

                        <div class="form-group ui-flat">
                            <p:outputLabel 
                                for="description-tag" 
                                value="#{label.descriptionTag}" 
                                styleClass="control-label col-md-4"/>

                            <div class="col-md-8">
                                <p:inputTextarea 
                                    id="description-tag"
                                    value="#{categoryFormMB.category.descriptionTag}" 
                                    styleClass="form-control"/>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-4"></div>

                            <div class="col-md-8">
                                <div class="pull-right">
                                    <p:commandButton 
                                        value="#{label.saveCategory}" 
                                        ajax="false"
                                        rendered="#{ ! categoryFormMB.editing}"
                                        action="#{categoryFormMB.save()}" 
                                        styleClass="btn btn-success btn-flat" 
                                        icon="fa fa-floppy-o"/>

                                    <p:commandButton 
                                        value="#{label.updateCategory}" 
                                        ajax="false"
                                        rendered="#{categoryFormMB.editing}"
                                        action="#{categoryFormMB.update()}" 
                                        styleClass="btn btn-success btn-flat" 
                                        icon="fa fa-floppy-o"/>

                                    <p:commandButton 
                                        value="#{label.cancel}" 
                                        action="#{categoryFormMB.close()}" 
                                        styleClass="btn btn-danger btn-flat" 
                                        ajax="false"
                                        icon="fa fa-times"
                                        immediate="true"/>
                                </div>
                            </div>
                        </div>
                    </h:form>

                    <p:messages 
                        globalOnly="false" 
                        showDetail="true" 
                        showSummary="false" 
                        showIcon="true" />
                </p:panel>
            </div>
        </div>
    </ui:define>
</ui:composition>

CategoryFormMB

package com.github.cvetan.bookstore.mb.category;

import static com.github.adminfaces.template.util.Assert.has;
import com.github.cvetan.bookstore.model.Category;
import com.github.cvetan.bookstore.sb.category.CategorySBLocal;
import com.github.cvetan.bookstore.util.Redirector;
import com.github.cvetan.bookstore.util.StringRepeater;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

/**
 *
 * @author cvetan
 */
@Named(value = "categoryFormMB")
@RequestScoped
public class CategoryFormMB {

    @EJB
    private CategorySBLocal categorySB;

    private List<Category> list;

    private List<Category> formattedList;

    private String title;

    private Integer id;

    private boolean editing;

    private Category category;

    private String message;

    /**
     * Creates a new instance of CategoryFormMB
     */
    public CategoryFormMB() {
    }

    public CategorySBLocal getCategorySB() {
        return categorySB;
    }

    public void setCategorySB(CategorySBLocal categorySB) {
        this.categorySB = categorySB;
    }

    public List<Category> getList() {
        return list;
    }

    public void setList(List<Category> list) {
        this.list = list;
    }

    public List<Category> getFormattedList() {
        return formattedList;
    }

    public void setFormattedList(List<Category> formattedList) {
        this.formattedList = formattedList;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public boolean isEditing() {
        return editing;
    }

    public void setEditing(boolean editing) {
        this.editing = editing;
    }

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void initForm() {
        formattedList = new ArrayList<>();

        getListFromDB();
        formatList(list, 0);

        if (has(id)) {
            // TODO
        } else {
            title = "New category";
            editing = false;
            category = new Category();
            message = "Category has been saved.";
        }
    }

    private void getListFromDB() {
        list = categorySB.getAll();
    }

    private void formatList(List<Category> list, int level) {
        for (Category c: list) {
            if (formattedList.contains(c)) {
                continue;
            }

            c.setName(StringRepeater.repeat(" - ", level) + c.getName());

            formattedList.add(c);

            if ( ! c.getChildCategories().isEmpty()) {
                formatList(c.getChildCategories(), level + 1);
            }
        }
    }

    public String save() {
        try {
            categorySB.save(category);

            return Redirector.redirectWithInfo("Category has been saved.", "/admin/category-list.xhmtl?faces-redirect=true");
        } catch (Exception ex) {
            return Redirector.redirectWithError(ex.getMessage(), "/admin/category-form.xhtml?faces-redirect=true");
        }
    }

}

CategorySB (EJB)

package com.github.cvetan.bookstore.sb.category;

import com.github.cvetan.bookstore.model.Category;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author cvetan
 */
@Stateless
public class CategorySB implements CategorySBLocal {

    @PersistenceContext (unitName = "BookstorePU")
    private EntityManager entityManager;

    @Override
    public List<Category> getAll() {
        return entityManager.createNamedQuery("Category.findAll").getResultList();
    }

    @Override
    public void save(Category category) {
        entityManager.persist(category);
    }

    @Override
    public Category getById(int id) {
        Query query = entityManager.createNamedQuery("Category.findById");
        query.setParameter("id", id);

        Category category = (Category) query.getSingleResult();

        return category;
    }

    @Override
    public void update(Category category) {

    }

    @Override
    public void delete(int id) {
        Category category = entityManager.find(Category.class, id);

        entityManager.remove(category);
    }
}

Категория сущности

package com.github.cvetan.bookstore.model;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 *
 * @author cvetan
 */
@Entity
@Table(name = "categories")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Category.findAll", query = "SELECT c FROM Category c")
    , @NamedQuery(name = "Category.findById", query = "SELECT c FROM Category c WHERE c.id = :id")
    , @NamedQuery(name = "Category.findByName", query = "SELECT c FROM Category c WHERE c.name = :name")
    , @NamedQuery(name = "Category.findBySlug", query = "SELECT c FROM Category c WHERE c.slug = :slug")
    , @NamedQuery(name = "Category.findByDescription", query = "SELECT c FROM Category c WHERE c.description = :description")
    , @NamedQuery(name = "Category.findByTitleTag", query = "SELECT c FROM Category c WHERE c.titleTag = :titleTag")
    , @NamedQuery(name = "Category.findByDescriptionTag", query = "SELECT c FROM Category c WHERE c.descriptionTag = :descriptionTag")
    , @NamedQuery(name = "Category.findByCreatedAt", query = "SELECT c FROM Category c WHERE c.createdAt = :createdAt")
    , @NamedQuery(name = "Category.findByUpdatedAt", query = "SELECT c FROM Category c WHERE c.updatedAt = :updatedAt")})
public class Category implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 255)
    @Column(name = "name")
    private String name;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 255)
    @Column(name = "slug")
    private String slug;

    @Size(max = 255)
    @Column(name = "description")
    private String description;

    @Size(max = 255)
    @Column(name = "title_tag")
    private String titleTag;

    @Size(max = 255)
    @Column(name = "description_tag")
    private String descriptionTag;

    @Basic(optional = false)
    @NotNull
    @Column(name = "created_at")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt;

    @Column(name = "updated_at")
    @Temporal(TemporalType.TIMESTAMP)
    private Date updatedAt;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    private List<Category> childCategories;


    @JoinColumn(name = "parent", referencedColumnName = "id")
    @ManyToOne
    private Category parent;

    public Category() {
    }

    public Category(Integer id) {
        this.id = id;
    }

    public Category(Integer id, String name, String slug, Date createdAt) {
        this.id = id;
        this.name = name;
        this.slug = slug;
        this.createdAt = createdAt;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSlug() {
        return slug;
    }

    public void setSlug(String slug) {
        this.slug = slug;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getTitleTag() {
        return titleTag;
    }

    public void setTitleTag(String titleTag) {
        this.titleTag = titleTag;
    }

    public String getDescriptionTag() {
        return descriptionTag;
    }

    public void setDescriptionTag(String descriptionTag) {
        this.descriptionTag = descriptionTag;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public Date getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(Date updatedAt) {
        this.updatedAt = updatedAt;
    }

    @XmlTransient
    public List<Category> getChildCategories() {
        return childCategories;
    }

    public void setChildCategories(List<Category> childCategories) {
        this.childCategories = childCategories;
    }

    public Category getParent() {
        return parent;
    }

    public void setParent(Category parent) {
        this.parent = parent;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Category)) {
            return false;
        }

        Category other = (Category) object;

        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return name;
    }

    @PrePersist
    public void setCreatedAt() {
        createdAt = new Date();
    }

    @PreUpdate
    public void setUpdatedAt() {
        updatedAt = new Date();
    }

}

1 Ответ

0 голосов
/ 01 июля 2018

На стороне JPA / EclipseLink есть кеширование, которого я не знал. Когда я очищаю кеш с помощью entityManager.getEntityManagerFactory().getCache().evictAll();, он обновляет данные. Так что проблема была не в компоненте или его сфере действия.

...