表达式语言中的#{flash.keep.message} 中的方法链是如何工作的?
How does method chaining work in #{flash.keep.message} in Expression Language?
我有这个示例代码:
<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 行为很棒。
现在我想了解发生了什么,所以我打开 documentation。
这个class中有一个keep()
方法,但是它的return类型是void
并且需要一个String
参数。那么#{flash.keep.message}
是在调用keep()
方法时带message参数吗?我真的不这么认为,据我所知应该是#{flash.keep(message)}
,不是吗?
那么这里发生了什么?
EL 解析可以自定义 ELResolver
implementations. There are two EL resolvers involved in evaluating #{flash.keep.message}
. The first one, the JSF-builtin FlashELResolver
在 #{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
将在计算 #{flash.keep}
表达式时调用 ELFlash.setKeepFlag(facesContext)
(第 231 行)。它还将 属性 设置为已解决(第 219 行),以便 EL 上下文可以使用下一个 属性 前进,并将 base
(#{flash}
)设置为已评估结果(第 225 行),如此有效 #{flash.keep}
returns 完全相同的 #{flash}
对象。
然后,当 message
属性 要根据 #{flash.keep}
的结果进行评估时,它基本上仍然是 #{flash}
,但 "keep" 标志集,EL 内置 MapELResolver
is executed. This is because #{flash}
is essentially a Map
, see also the javadoc(强调我的)。
public abstract class Flash
extends Object
implements Map<String,Object>
这会调用 Map#get()
方法,即 customized in Flash
class 如下(行号匹配 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
所做的那样。
我有这个示例代码:
<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 行为很棒。
现在我想了解发生了什么,所以我打开 documentation。
这个class中有一个keep()
方法,但是它的return类型是void
并且需要一个String
参数。那么#{flash.keep.message}
是在调用keep()
方法时带message参数吗?我真的不这么认为,据我所知应该是#{flash.keep(message)}
,不是吗?
那么这里发生了什么?
EL 解析可以自定义 ELResolver
implementations. There are two EL resolvers involved in evaluating #{flash.keep.message}
. The first one, the JSF-builtin FlashELResolver
在 #{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
将在计算 #{flash.keep}
表达式时调用 ELFlash.setKeepFlag(facesContext)
(第 231 行)。它还将 属性 设置为已解决(第 219 行),以便 EL 上下文可以使用下一个 属性 前进,并将 base
(#{flash}
)设置为已评估结果(第 225 行),如此有效 #{flash.keep}
returns 完全相同的 #{flash}
对象。
然后,当 message
属性 要根据 #{flash.keep}
的结果进行评估时,它基本上仍然是 #{flash}
,但 "keep" 标志集,EL 内置 MapELResolver
is executed. This is because #{flash}
is essentially a Map
, see also the javadoc(强调我的)。
public abstract class Flash
extends Object
implements Map<String,Object>
这会调用 Map#get()
方法,即 customized in Flash
class 如下(行号匹配 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
所做的那样。