includeViewParams=true 将空模型值转换为查询字符串中的空字符串
Posted
技术标签:
【中文标题】includeViewParams=true 将空模型值转换为查询字符串中的空字符串【英文标题】:includeViewParams=true converts null model value to empty string in query string 【发布时间】:2014-07-06 16:45:16 【问题描述】:给定一个<p:selectOneMenu>
,如下所示。
<f:metadata>
<f:viewParam name="id" value="#testManagedBean.id" converter="javax.faces.Long"/>
</f:metadata>
<p:selectOneMenu value="#localeBean.language" onchange="changeLanguage();">
<f:selectItem itemValue="en" itemLabel="English" />
<f:selectItem itemValue="hi" itemLabel="Hindi" />
</p:selectOneMenu>
<p:remoteCommand action="#testManagedBean.submitAction"
name="changeLanguage"
process="@this"
update="@none"/>
对应的托管bean:
@ManagedBean
@RequestScoped
public final class TestManagedBean
private Long id; //Getter and setter.
public TestManagedBean()
public String submitAction()
return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true&includeViewParams=true";
<f:viewParam>
表示的参数是可选的。例如,使用如下 URL 访问页面。
https://localhost:8181/Project-war/private_resources/Test.jsf
由于id
是一个可选参数,一个空参数附加到URL(当从<p:selectOneMenu>
更改语言时),以防它如下提供。
https://localhost:8181/Project-war/private_resources/Test.jsf?id=
这不应该发生。如果未提供空参数且 URL 应与第一个类似,则不应附加空参数。
有没有办法防止空参数在未传递的情况下附加到 URL 中?
这仅与<f:viewParam>
- javax.faces.Long
指定的转换器相关联。
如果移除此转换器,则不会将参数附加到 URL,以防不提供任何参数。
虽然完全没有必要指定此处演示的转换器,但我有如下所示的转换器将通过 URL 作为查询字符串参数传递的 id
转换为 JPA 实体。
@ManagedBean
@RequestScoped
public final class ZoneConverter implements Converter
@EJB
private final SharableBeanLocal sharableService = null;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
try
long parsedValue = Long.parseLong(value);
if (parsedValue <= 0)
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Message Summary", "Message"));
ZoneTable entity = sharableService.findZoneById(parsedValue);
if (entity == null)
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_WARN, "Message Summary", "Message"));
return entity;
catch (NumberFormatException e)
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Message Summary", "Message"), e);
@Override
public String getAsString(FacesContext context, UIComponent component, Object value)
return value instanceof ZoneTable ? ((ZoneTable) value).getZoneId().toString() : "";
现在需要使用<f:viewParam>
明确指定此转换器,如下所示。
<f:viewParam name="id"
value="#testManagedBean.id"
converter="#zoneConverter"
rendered="#not empty param.id"/>
并且关联的托管bean需要进行如下更改。
@ManagedBean
@RequestScoped
public final class TestManagedBean
private ZoneTable id; //Getter and setter.
public TestManagedBean()
public String submitAction()
return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true&includeViewParams=true";
【问题讨论】:
您是否尝试过将required="false"
用于您的<f:viewParam>
?
尝试将required
的<f:viewParam>
设置为false
,但这也没有什么不同。
您在帖子中遇到的一些错误/不是最佳实践:1. 从 JSF 2 开始,*.xhtml
被用作映射模式,而不是 *.jsf
。 X。 2. 你忘了告诉#bean
的实现。 3. 您为您的问题包装了很多不相关的代码:托管属性与您的案例无关,p:remoteCommand
也不相关。删除它们并最小化您的测试用例,直到您可以用最少的代码重现问题。如果您继续拥有它,请按原样发布。见SSCCEquestionformatting.PD:我对你的问题做了一个测试用例,没有问题。
【参考方案1】:
这可能是UIViewParameter#getStringValueFromModel()
的Mojarra's default implementation 的疏忽,其来源供参考,复制粘贴如下:
384 public String getStringValueFromModel(FacesContext context)
385 throws ConverterException
386 ValueExpression ve = getValueExpression("value");
387 if (ve == null)
388 return null;
389
390
391 Object currentValue = ve.getValue(context.getELContext());
392
393 // If there is a converter attribute, use it to to ask application
394 // instance for a converter with this identifer.
395 Converter c = getConverter();
396
397 if (c == null)
398 // if value is null and no converter attribute is specified, then
399 // return null (null has meaning for a view parameters; it means remove it).
400 if (currentValue == null)
401 return null;
402
403 // Do not look for "by-type" converters for Strings
404 if (currentValue instanceof String)
405 return (String) currentValue;
406
407
408 // if converter attribute set, try to acquire a converter
409 // using its class type.
410
411 Class converterType = currentValue.getClass();
412 c = context.getApplication().createConverter(converterType);
413
414 // if there is no default converter available for this identifier,
415 // assume the model type to be String.
416 if (c == null)
417 return currentValue.toString();
418
419
420
421 return c.getAsString(context, this, currentValue);
422
在为includeViewParams=true
构建查询字符串期间,每个UIViewParameter
(<f:viewParam>
后面的 UI 组件)都会调用此方法。我们在源代码中看到,无论currentValue
是否为null
,它都会调用转换器。也就是说,即使模型值为null
,它仍然会用它调用转换器。
根据javadoc of Converter#getAsString()
,如果值为null
,则转换器按规范要求返回零长度字符串:
getAsString
...
返回:如果值为
null
,则返回零长度字符串,否则为转换结果
因此,转换器实际上应该永远不会在 getAsString()
上返回 null
。然后他们返回一个空字符串。对于查询字符串中的视图参数,这是非常不可取的。空字符串值和查询字符串中完全不存在之间的区别非常显着。
我已经以issue 3288 向 Mojarra 家伙报告了它。然后他们应该按如下方式解决这个问题:
391 Object currentValue = ve.getValue(context.getELContext());
392
393 if (currentValue == null)
394 return null;
395
与此同时,我有committed OmniFaces 的解决方案。 <o:viewParam>
已通过此修复扩展。可通过今天的1.8 snapshot 获取。
<f:metadata>
<o:viewParam name="id" value="#testManagedBean.id" converter="javax.faces.Long"/>
</f:metadata>
更新:他们决定不修复它。无论如何,都有 OmniFaces。
【讨论】:
看起来他们现在可能正在重新考虑规范级别:java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1180以上是关于includeViewParams=true 将空模型值转换为查询字符串中的空字符串的主要内容,如果未能解决你的问题,请参考以下文章
带有 includeViewParams 的 JSF2 重定向允许用户输入解析为文本字段的 EL 表达式