Java 当用户返回表单时,我如何告诉Facelets页面,它应该加载什么对象?

Java 当用户返回表单时,我如何告诉Facelets页面,它应该加载什么对象?,java,jsf,facelets,java-ee-6,Java,Jsf,Facelets,Java Ee 6,我有一个问题,我解决了,但我觉得我的解决方案是一个糟糕的黑客。有更好的办法吗 我有一个页面,我在上面放置了表单,它显示了一些对象的属性,如示例所示(省略了明显的细节) Ticket.java: @Entity public class Ticket { @Id private Long id; private String title; private byte priority; // Getters, setters... } TicketContr

我有一个问题,我解决了,但我觉得我的解决方案是一个糟糕的黑客。有更好的办法吗

我有一个页面,我在上面放置了表单,它显示了一些对象的属性,如示例所示(省略了明显的细节)

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";
    }
}
xhtml(只是表单,其他都是样板)


还有TicketEJB,它负责获取这些票证、持久化等

因此,我在表单中创建了一个隐藏输入,然后(在托管bean中)使用提供的id查找票证,然后手动将托管bean的
ticket
对象中的所有字段复制到获取的票证,然后将其持久化。。。它违反了DRY原则(当我在票证中添加一个字段时,我已经发现了一个错误,但忘记在
doUpdateTicket()
中复制它)


因此,也许有更好的方法可以做到这一点?

您可以自己将票据添加为ManagedBean,但使用@SessionScoped。这样票据域对象可以在请求之间保留其id,JSF可以直接更新它。当然,您失去了使用这种方法保持数据短寿命的优势,这是您目前通过R获得的您还就绑定到域对象本身展开了一场辩论

使用JSF 2,您还可以在视图范围中存储UIViewRoot的属性,这在您的情况下可能非常理想,以避免使用隐藏字段,即在viewScope中存储具有票证的票证或控制器-因此,当用户回发到编辑页面时,票证将保留在范围内e在这里使用一个Transfer对象来将服务实体与表示层解耦,因此将a更新为,将其传递给EJB,并让EJB处理实体的更新和持久性

或者,您可以仅将长id服务器端存储在@SessionScoped或@ViewScoped中,因为将其存储为隐藏字段可能不安全,因为客户端可能会将其更改为更新另一个票证。如果确实使用另一个票证实例捕获UI输入,则可以在票证对象上提供副本构造函数,因此DoupDateicket方法本身不包括从一个票证到另一个代码的冗长复制字段


为了避免重复,我更喜欢直接绑定到JPA实体AKA域对象。我会使用@ViewScoped。

只需在视图范围bean的
预渲染视图期间从EJB获取原始票证,而不是自己创建一个新的票证。假设票证ID已作为名为
I的请求参数传递d

edit.xhtml


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

    // ...
}
唯一的区别是输入字段不会空白。但这不正是“编辑”表单背后的全部想法吗?这样一来,这个问题也会立即得到解决

哦,还有你的


真的需要成为一个



有一个问题-服务器似乎在“查看”过程中创建了四个不同的bean请求,如果我将scope设置为ViewScoped。因此它总是给出空指针异常,因为它调用
id
var,该变量被设置为另一个bean的有意义的数字。可以肯定的是,您使用的是
@ManagedBean
而不是
@Named
?哦,是的,它被命名了。我认为NetBeans知道它在做什么,并且一切都正常d今天之前很好。谢谢,现在好多了。现在有另一个问题。使用@Named,当用户提交表单时,服务器使用同一个bean来处理表单并呈现响应,因此我只是将票据留在bean中,它的字段被打印到查看页面。现在它删除该bean并创建一个新的,我不知道如何传递ti没有非常难看的破解就可以使用它(因为faces navigation似乎不允许我将值作为do()方法的返回来传递。视图范围的bean确实绑定到特定视图。一旦导航到新视图,该bean就会被破坏。基本上有两种方法可以重新显示同一票据:1)导航到有条件呈现“视图”和“编辑”状态的同一视图。2)将票据
id
作为请求参数传递给新视图,并让它通过EJB预加载。作为另一种选择,您也可以回到
@Named
,使用CDI的对话范围。然而,我无法从头脑中分辨出如何准确地配置/使用它。
@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";
    }

    // ...
}