在两个ViewScoped ManagedBeans之间传递对象的最佳解决方案

4
我想知道在两个ViewScoped beans之间传递数据(对象)的最佳实践是什么。
它们需要是视图作用域,因为这里有一个问题被精彩地解释了here (简而言之:在两个视图中,我都使用了h:dataTable内的h:commandLink,提交时需要数据模型仍然存在)。
现在我的问题是,点击链接也会导航到新视图,所以使用以下代码,我的对象被传递,但当视图更改时,DetailViewController实例就被销毁并创建一个新实例。
<h:dataTable value="#{searchController.dataModel}" var="item">
    ...
    <h:column>
        <f:facet name="header">Action</f:facet>
        <h:commandLink id="open" value="open" action="#{searchController.showDetail(item)}" />
    </h:column>
</h:dataTable>

Bean:

@ManagedBean
@ViewScoped
public class SearchController {

    @ManagedProperty(value="#{detailViewController}")
    private DetailViewController detailViewController;

    // getters, setters, etc. ...

    public String showDetail(Item i) {
        detailViewController.setItem(i);
        return "view_detail.xhtml";
    }

}

你怎么解决这个问题?我考虑把对象放在Flash里:FacesContext.getExternalContext.getFlash()... 是否有更简单或更优雅的解决方案?


我忘了提到我正在使用Servlet 3.0/JSF 2.2(Mojarra),如果这是相关的话。 - syntaxerror
不要将detailViewController设置为托管属性,那是完全错误的。返回其视图ID(在您的情况下可以是view_detail,请注意我正在修剪.xhtml)。稍后,在view_detail.xhtml中引用detailViewController,并且您将通过框架实例化它。对于传递参数,您有多种选择,例如使用视图参数、使用Flash范围、使用Flow范围等等...只需搜索一下,您就会在SO上找到有趣的参考资料,这里是我的参考链接:flashview - Aritz
你实际上可以在JSF 2中返回文件名称而不是ViewID。至于“ManagedProperty”,它是与RequestScoped bean完美配合的解决方案:目的只是获取对下一个视图bean的引用,以便您可以预先初始化它。但是对于ViewScoped bean,显然没有意义。所以我想,在这里使用flash范围并不是最糟糕的想法。谢谢你的回答,我一直在想我可能忽略了什么,甚至可以更容易地实现它;-)) - syntaxerror
在工作之前初始化 bean 可以运行,但不是 JSF 的方式,据我所知从来没有过。实际上,您正在推广一种不必要的代码耦合,视图范围或会话范围的 bean 不应该知道与其相同或更窄的范围内的其他 bean。您只需要确保向目标视图传递正确的参数,框架将负责初始化它。 - Aritz
1个回答

1

您可以使用视图参数。(请参阅JSF2中从操作导航时如何传递视图参数?

通常,您的方法返回带有查询参数的URL:

 public String showDetail(Item i) {
    return "view_detail.xhtml?id="+i.getId();
 }

在你的 view_detail.xhtml 文件中,你需要添加一个 f:viewParam 标签,并将其设定为你的 bean 字段之一:
<f:metadata>
    <f:viewParam name="id" value="#{myBean.id}" />
</f:metadata>

然后从您的后备bean中,您可以使用该字段在@postConstruct方法中获取您的Item实例。 如果您不使用f:viewparam标记,您也可以获取请求参数以获取id。

private String id;
private Item item;

@PostConstruct
public void init() {
  if (id != null) {
    item = fetchItem(id);
  } else {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();
    if (requestParameters.containsKey("id")) {
       id = requestParameters.get("id");
       item = fetchItem(id);
    } else {
       throw new WebServiceException("No item id in request parameters");
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接