Перенос функциональности управляемого bean-компонента при переходе с Core JSF на Seam

Я использовал для инициализации определенных свойств объекта сущности предопределенными значениями еще на этапе его создания в методе @PostConstruct управляемого bean-компонента jsf (или даже конструктора управляемого bean-компонента). Я больше не могу сохранять эту функциональность при переносе проекта в Seam с удаленным управляемым bean-компонентом (интересно также, как это было бы в JSF 2.2 без управляемых bean-компонентов).

Класс объекта:

@Entity
@Name("task") // this line in Seam version
public class Task implements Serializable {

    private Integer id;
    private String subject;
    private Date creationDate;
    private Date completionDate;
    private Category category;
    private User user;

    public Task() {
    }

    public Task(Date creationDate) {
        this.creationDate = creationDate;
        this.user = user;
    }

    // getters & setters, etc.
}

Управляемый компонент JSF

public class TaskBean extends BaseBean {

    // Super class provides the logged in user object and a default category object

    private Task task = new Task(java.util.Calendar.getInstance().getTime(), this.user);

    @PostConstruct
    public void initTaskBean() {
        if (certainConditionMet) 
            task.setCategory(defaultCategory);
    }

    // Other managed bean business...
}

Страница JSF

<h:form>
<h:panelGrid columns="2">
    Date: <h:outputText value="#{taskBean.task.creationDate}">
            <f:convertDateTime pattern="dd/MM/yyyy" />
           </h:outputText>
    User:  <h:outputText value="#{taskBean.task.user.name}" />
    Subject: <h:inputText value="#{taskBean.task.subject}" id="subjectField" />
    Category: <h:selectOneMenu value="#{taskBean.task.category}" id="catMenu">
                <f:selectItems value="#{taskBean.categories}" />
              </h:selectOneMenu>
    // remaining stuff
</h:panelGrid>
</h:form>

Сессионный компонент без сохранения состояния в версии Seam также принимает на себя ответственность управляемого bean-компонента jsf

@Name("taskAction")
@Stateless
public class TaskAction implements TaskActionLocal {

    @PersistenceContext
    private EntityManager em;

    @In private FacesMessages facesMessages;
    @In User user;
    @In Category defaultCategory
    @Logger private Log log;

    @In
    // private Task task = new Task(java.util.Calendar.getInstance().getTime(), user)
    // the above didn't work so 
    private Task task; 

    @PostConstruct
    public void baslarken() {
        System.out.println("TaskAction PostConstructed");
        task = new task(java.util.Calendar.getInstance().getTime(), user);
        if (certainConditionMet) 
                task.setCategory(defaultCategory);

        // the above won't work either. Date and User always blank on the ui form
    }

    // other business methods, etc
}

Вариант формы со швом:

<h:form id="todo" styleClass="edit">
    <rich:panel>
        <f:facet name="header">Task To Do</f:facet>

        <s:decorate id="dateField" template="layout/edit.xhtml">
            <ui:define name="label">Date:</ui:define>
            <h:outputText value="#{task.creationDate}"/>
        </s:decorate>

        <s:decorate id="userField" template="layout/edit.xhtml">
            <ui:define name="label">User:</ui:define>
            <h:outputText value="#{task.user.name}"/>
        </s:decorate>

        <s:decorate id="subjectField" template="layout/edit.xhtml">
            <ui:define name="label">Başlık</ui:define>
            <h:inputText id="subject" required="true" value="#{task.subject}" >
            <a4j:support event="onblur" reRender="subjectField" bypassupdates="true" ajaxSingle="true" />
            </h:inputText>
        </s:decorate>

        <!-- other components, etc -->
    </rich:panel>
</h:form>

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


person Skyhan    schedule 19.10.2011    source источник


Ответы (2)


Сначала извините, но я не могу найти ссылку для комментария к этому ответу ?? (так что модераторы могут смело перемещать этот пост;))

Возможно расширение класса entityhome как сессионного компонента. Да. Но я не уверен, правильно ли это. Я бы с большей вероятностью создал новый сеансовый компонент, который более точно служит моей цели.

Для вызова фабрики. Вы назовете это так же со страницы jsf, как и любое другое имя. Т.е. значение = "# {createNewTask.id}". Или вы можете ввести его в другой класс. Взгляните на документ по шву. Это действительно хорошо написано.

person Martin Frey    schedule 25.10.2011
comment
Спасибо, Мартин. Я применил своего рода шаблон фасада службы к проекту, где каждое взаимодействие напрямую с базой данных осуществляется с использованием сеансовых компонентов в качестве фасадов служб, и они вызываются компонентами Seam (управляемый компонент) - хотя по швам этот шаблон может быть неприменим. очень подходит, так как устраняет необходимость в управляемых компонентах JSF. Поэтому я буду искать более подходящие шаблоны проектирования, специально подходящие для Seam, и такие, которые позволят мне поддерживать чистоту кода для больших проектов. - person Skyhan; 25.10.2011

У вас есть несколько возможностей инициализировать объект. Существует класс EntityHome, который вы можете расширить для сущности. Это стандартная реализация обработки сущностей для редактора. Он также используется, если вы используете seam-gen для создания своего приложения.

Это выглядело бы примерно так:

@Name("queryHome")
@Scope(ScopeType.CONVERSATION)
public class QueryHome extends EntityHome<Query> {
    /*
     * (non-Javadoc)
     * @see org.jboss.seam.framework.Home#createInstance()
     */
    @Override
    public Query createInstance() {
        Query query = super.createInstance();
        query.setUser(loggedUser);
        query.setCreationDate(new Date());
        query.setLastExecutionDate(new Date());
        return query;
    }
}

И вы будете вызывать queryHome.getInstance (). Если свойство id в entityHome установлено, он попытается загрузить объект с этим идентификатором из базы данных, а если идентификатора нет, он вызовет createInstance (). Вот как я его обычно использую.

Вы также можете создать фабричный аннотированный метод в bean-компоненте, управляемом швом. Там ты можешь делать все, что хочешь.

@Name("CreationFactory")
@Scope(ScopeType.STATELESS)
pulic class CreationFactory {

    @Factory("createNewTask")
    public Task createTask() {
        Task task = new Task();
        task.sometext = "sometext";
        return task;
    }
}

Обычно я не получаю доступ к bean-компоненту и не создаю его напрямую, но для этого я использую компонент-менеджер, например entityhome. Вы можете упростить доступ с помощью фабрики, но это объясняется в документации Seam.

Мартин

person Martin Frey    schedule 21.10.2011
comment
Мартин, спасибо за совет, первый способ работает нормально - хотя я не уверен в сценарии EJB, расширение EntityHome как сессионного компонента будет работать (так ли?) Второй способ, можете ли вы дать мне представление о том, как будет вызван метод createTask? - person Skyhan; 23.10.2011