我有几个页面需要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上调用正确的值。
我是否完全错误地了解了视图参数的工作原理,或者是否存在某种错误?我认为我的用例应该极端通用,并且在框架中有基本的支持。
答案 0 :(得分:25)
当我四处搜索时,我得到的结论是视频参数应保留在帖子之后,因此读取userpage.jsf?userId = 123,但事实并非如此。什么是真正的预期行为?
这种行为是正确的。 <h:form>
生成一个HTML <form>
元素,其中包含操作网址,不含任何视图参数。 POST请求只是提交到该URL。如果您打算在URL中保留视图参数,那么基本上有3种方法:
带来一些ajax魔法。
<h:commandButton action="#{userPageController.doAction}" value="post">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
这样,最初请求的页面以及浏览器地址栏中的请求URL始终保持不变。
如果适用(例如,对于页面到页面的导航),请将其设为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。
自行控制<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">
更新:以编程方式获取当前视图的视图参数(基本上是您的第二个问题)应按如下方式完成:
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>
内?