在post之后处理JSF中的视图参数

时间:2012-04-27 14:35:21

标签: jsf-2 viewparams

我有几个页面需要userId才能工作,因此代码如下:

userpage.xhtml

<!-- xmlns etc. omitted -->
<html>
<f:metadata>
    <f:viewParam name="userId" value="#{userPageController.userId}"/>
</f:metadata>
<f:view contentType="text/html">
<h:head>
</h:head>
<h:body>
    <h:form>
        <h:commandButton action="#{userPageController.doAction}" value="post"/>
    </h:form>
</h:body>
</f:view>

userPageController.java

@Named
@ViewScoped
public class userPageControllerimplements Serializable {
    private static final long serialVersionUID = 1L;

    @Inject protected SessionController sessionController;
    @Inject private SecurityContext securityContext;
    @Inject protected UserDAO userDAO;

    protected User user;
    protected Long userId;

    public UserPage() {
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        if(!FacesContext.getCurrentInstance().isPostback()){
            User u = userDAO.find(userId);
            this.userId = userId;
            this.user = u;
        }
    }

    public void doAction(){

    }

}

然而,在调用doAction之后,url中的view参数消失。豆子仍然可以运作,因为它的景观自然,但它破坏了我未来导航的尝试。当我四处搜索时,我得到的结论是视频参数应保留在帖子之后,因此读取userpage.jsf?userId = 123,但事实并非如此。什么是真正的预期行为?

与此相关,我试图在导航到我想要保留userId的另一个页面时实现自动添加视图参数。它似乎适用于其他人,但对我来说,ViewRoot中的userId始终为null。下面的代码用于检索视图参数(我知道我可以在bean中使用我临时存储的userId进行导航,但这个解决方案会更加漂亮):

    String name = "userId";
    FacesContext ctx = FacesContext.getCurrentInstance();
    ViewDeclarationLanguage vdl = ctx.getApplication().getViewHandler().getViewDeclarationLanguage(ctx, viewId);
    ViewMetadata viewMetadata = vdl.getViewMetadata(ctx, viewId);
    UIViewRoot viewRoot = viewMetadata.createMetadataView(ctx);
    UIComponent metadataFacet = viewRoot.getFacet(UIViewRoot.METADATA_FACET_NAME);

    // Looking for a view parameter with the specified name
    UIViewParameter viewParam = null;
    for (UIComponent child : metadataFacet.getChildren()) {
        if (child instanceof UIViewParameter) {
            UIViewParameter tempViewParam = (UIViewParameter) child;
            if (name.equals(tempViewParam.getName())) {
                viewParam = tempViewParam;
                break;
            }
        }
    }

    if (viewParam == null) {
        throw new FacesException("Unknown parameter: '" + name + "' for view: " + viewId);
    }

    // Getting the value
    String value = viewParam.getStringValue(ctx);  // This seems to ALWAYS be null.

最后一个想法是setter方法似乎仍然有用,setUserId在post上调用正确的值。

我是否完全错误地了解了视图参数的工作原理,或者是否存在某种错误?我认为我的用例应该极端通用,并且在框架中有基本的支持。

2 个答案:

答案 0 :(得分:25)

  

当我四处搜索时,我得到的结论是视频参数应保留在帖子之后,因此读取userpage.jsf?userId = 123,但事实并非如此。什么是真正的预期行为?

这种行为是正确的。 <h:form>生成一个HTML <form>元素,其中包含操作网址,不含任何视图参数。 POST请求只是提交到该URL。如果您打算在URL中保留视图参数,那么基本上有3种方法:

  1. 带来一些ajax魔法。

    <h:commandButton action="#{userPageController.doAction}" value="post">
        <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    

    这样,最初请求的页面以及浏览器地址栏中的请求URL始终保持不变。

  2. 如果适用(例如,对于页面到页面的导航),请将其设为GET请求并使用includeViewParams=true。您可以使用<h:link><h:button>

    <h:button outcome="nextview?includeViewParams=true" value="post" />
    

    但是,这在早于2.1.6的Mojarra版本中具有EL安全漏洞。确保您使用的是Mojarra 2.1.6或更高版本。另请参阅issue 2247

  3. 自行控制<h:form>的动作网址生成。提供自定义ViewHandler(仅展开ViewHandlerWrapper),您可以在getActionURL()中完成工作。

    public String getActionURL(FacesContext context, String viewId) {
        String originalActionURL = super.getActionURL(context, viewId);
        String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
        return newActionURL;
    }
    

    要使其运行,请在faces-config.xml中注册,如下所示:

    <application>
        <view-handler>com.example.YourCustomViewHandler</view-handler>
    </application>
    

    这也是OmniFaces <o:form>正在做的事情。它支持额外的includeViewParams属性,该属性包含表单操作URL中的所有视图参数:

    <o:form includeViewParams="true">
    

  4. 更新:以编程方式获取当前视图的视图参数(基本上是您的第二个问题)应按如下方式完成:

    Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(FacesContext.getCurrentInstance().getViewRoot());
    
    for (UIViewParameter viewParam : viewParams) {
        String name = viewParam.getName();
        Object value = viewParam.getValue();
        // ...
    }
    

答案 1 :(得分:0)

我是正确的,对于解决方案1 ​​<f:ajax execute="@form" render="@form" />工作,我还必须包含类似

的内容
<f:param name="userId" value="#{userPageController.userId}"/>

<h:commandButton>内?

https://stackoverflow.com/a/14026995/811046

中描述的相同