Как я могу сообщить странице Facelets, какой объект она будет загружать, когда пользователь возвращает форму? - PullRequest
0 голосов
/ 15 июня 2011

У меня была проблема, которую я решил, но я чувствую, что мое решение - плохой взлом.Есть ли лучший способ?

У меня есть страница, на которой я разместил форму, которая показывает свойства какого-то объекта, как в примере (очевидные детали опущены).

Ticket.java:

@Entity
public class Ticket {
    @Id
    private Long id;
    private String title;
    private byte priority;
    // Getters, setters...
}

TicketController.java

@RequestScoped
public class TicketController {
    private Ticket ticket = new Ticket();
    // Getters, setters...

    public String doUpdateTicket() {
        Ticket t = ticketEJB.getTicketById(ticket.getId());
        t.setTitle(ticket.getTitle());
        t.setPriority(ticket.getPriority());
        ticketEJB.updateTicket(t);
        ticket = t;
        return "view.faces";
    }
}

edit.xhtml (только форма, все остальное - шаблон)

<h:form>
    <h:inputHidden value="#{ticketController.ticket.id}" />
    <h:panelGrid columns="2">
        <h:outputLabel value="ID"/>
        <h:outputLabel value="#{ticketController.ticket.id}"/>
        <h:outputLabel value="Title: "/>
        <h:inputText value="#{ticketController.ticket.title}"/>
        <h:outputLabel value="Priority: "/>
        <h:inputText value="#{ticketController.ticket.priority}" />
        <h:commandButton value="Submit" 
             action="#{ticketController.doUpdateTicket}" />
    </h:panelGrid>
</h:form>

Также есть TicketEJB, которыйотвечает за выборку этих заявок, сохранение и т. д.

Поэтому я создаю скрытый ввод в форме, затем (в управляемом компоненте) нахожу заявку, используя предоставленный идентификатор, затем вручную копирую все поля из ticketобъект управляемого бина в извлеченный тикет, затем сохранить его ... Это связано с нарушением принципа СУХОЙ (я уже наткнулся на ошибку, когда добавил поле в тикет, но забыл скопировать его в doUpdateTicket().

Так, может быть, есть лучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 15 июня 2011

Просто получите оригинальный билет от EJB во время preRenderView боба с областью видимости вместо того, чтобы создавать новый самостоятельно.Предполагая, что идентификатор билета был передан в качестве параметра запроса с именем id:

edit.xhtml

<f:metadata>
    <f:viewParam name="id" value="#{ticketController.id}" />
    <f:event type="preRenderView" listener="#{ticketController.preLoad}" />
</f:metadata>
...

TicketController

@ManagedBean
@ViewScoped
public class TicketController {
    private Long id;
    private Ticket ticket;

    @EJB
    private TicketEJB ticketEJB;

    public void preLoad() {
        ticket = ticketEJB.getTicketById(id);
    }

    public String doUpdateTicket() {
        ticketEJB.updateTicket(ticket);
        return "view.faces";
    }

    // ...
}

ЕдинственныйРазница в том, что поля ввода не исчезают.Но не в этом ли вся идея формы «редактирования»?Эта проблема также сразу же исправляется таким образом.

О, и ваш

<h:outputLabel value="#{ticketController.ticket.id}"/>

действительно должен быть

<h:outputText value="#{ticketController.ticket.id}"/>
1 голос
/ 15 июня 2011

Вы можете добавить Билет как ManagedBean самостоятельно, но использовать @SessionScoped. Таким образом, объект Ticket Domain сохраняет свой идентификатор между запросами, и JSF может обновлять его напрямую. Конечно, при таком подходе вы теряете преимущество сохранения данных на короткое время, которое вы в настоящее время получаете через область запросов. И вы начинаете дискуссию о привязке к самому объекту домена.

С JSF 2 у вас также есть View Scope, где вы можете хранить атрибуты для UIViewRoot, что может быть очень желательно в вашем случае, чтобы избежать использования скрытых полей, т.е. хранить Ticket или Controller, который имеет HAS-A Ticket в viewScope - так пока пользователь выполняет обратную передачу на страницу редактирования, заявка остается в области действия. Некоторые люди могут сказать, что вы должны использовать здесь Transfer Object для отделения сущностей Service от уровня представления - поэтому обновите TO, передайте его в EJB и позвольте EJB обрабатывать обновление и сохранение сущности.

В качестве альтернативы вы можете хранить только сторону сервера Long id в @SessionScoped или @ViewScoped, поскольку может быть небезопасно хранить это как скрытое поле, так как клиент может изменить его, чтобы обновить другой тикет. Если вы используете другой экземпляр Ticket для захвата входных данных пользовательского интерфейса, вы можете предоставить конструктор копирования для объекта Ticket, поэтому сам метод doUpdateTicket не включает в себя утомительные поля копирования из одного Ticket в другой код.

Чтобы избежать повторения, я бы предпочел привязку непосредственно к объекту домена АКА объекта JPA. И я бы использовал @ ViewScoped.

...