1

我有这个示例代码:

<h:form>
    <h:commandButton action="#{fooBar.foo()}" value="Submit"/>
</h:form>

在 bean 中:

@ManagedBean
@ApplicationScoped
public class FooBar {
    public String foo() {
        final Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
        flash.put("message", "Hello World");
        return "hello?faces-redirect=true";
    }
}

最后在hello.xhtml

<h:body>
    #{flash.keep.message}
</h:body>

所以我去index.xhtml,点击提交,我hello.xhtml按预期被重定向到。当我刷新页面时,我仍然会看到消息,因为 flash.keep 行为很棒。

现在我试图了解发生了什么,所以我打开了文档

这个类中有一个keep()方法,但它的返回类型是void并且它需要一个String参数。那么是用 message 参数#{flash.keep.message}调用方法吗?keep()我真的不这么认为,据我所知,它应该是#{flash.keep(message)},不是吗?

那么这里发生了什么?

4

1 回答 1

1

EL 解析可以通过ELResolver实现进行定制。有两个 EL 解析器参与评估#{flash.keep.message}。第一个,JSF-builtinFlashELResolver#{flash}. 正如您在其源代码中看到的(行号与 Mojarra 2.2.12 匹配),

216        // and the property argument is "keep"...
217        if (property.toString().equals(FLASH_KEEP_VARIABLE_NAME))
218        {
219            elContext.setPropertyResolved(true);
220          
221            // then this is a request to promote the value
222            // "property", which is assumed to have been previously
223            // stored in request scope via the "flash.now"
224            // expression, to flash scope.
225            result = base;
226            // Set a flag so the flash itself can look in the request
227            // and promote the value to the next request
228            FlashFactory ff = (FlashFactory) 
229                    FactoryFinder.getFactory(FactoryFinder.FLASH_FACTORY);
230            ff.getFlash(true);
231            ELFlash.setKeepFlag(facesContext);
232        }

计算表达式时FlashELResolver将调用ELFlash.setKeepFlag(facesContext)(第 231 行) 。#{flash.keep}它还将属性设置为已解析(第 219 行),以便 EL 上下文可以使用下一个属性前进,并将base(the #{flash}) 设置为评估结果(第 225 行),因此有效地#{flash.keep}返回了相同的#{flash}对象。

然后,当message要根据 的结果评估属性时#{flash.keep},本质上仍然是#{flash},但设置了“keep”标志,MapELResolver则执行 EL-builtin。这是因为#{flash}本质上是 a Map,另请参见javadoc(强调我的)。

公共抽象类 Flash
扩展 Object
实现 Map<String,Object>

这将调用该Map#get()方法,该方法在类中自定义Flash如下(行号与 Mojarra 2.2.12 匹配):

384     public Object get(Object key) {
385         Object result = null;
386 
387         FacesContext context = FacesContext.getCurrentInstance();
388         if (null != key) {
389             if (key.equals("keepMessages")) {
390                 result = this.isKeepMessages();
391             } else if (key.equals("redirect")) {
392                 result = this.isRedirect();
393             } else {
394                 if (isKeepFlagSet(context)) {
395                     result = getPhaseMapForReading().get(key);
396                     keep(key.toString());
397                     clearKeepFlag(context);
398                     return result;
399                 }
400 
401             }
402 
403         }

正如您在第 396 行看到的那样,它会keep(key)在设置标志时调用,如FlashELResolver.

于 2016-06-25T14:45:27.923 回答