【问题标题】:EL expression in c:set gets called multiple times instead of its return value being usedc:set 中的 EL 表达式被多次调用,而不是使用它的返回值
【发布时间】:2026-02-12 06:05:01
【问题描述】:

我在请求范围内有一个操作。其方法之一的返回值被传递给自定义 facelet 标记。这个标签然后提取返回对象的几个属性并显示它们。问题是对于返回对象的属性的每次评估都会调用对 Action 进行方法调用的 EL 表达式。我会把相关的代码放在这里。

一些.xhtml

<ui:include src="someOther.xhtml">
    <ui:param name="profileUri" value="#{param['relateToProfile']}"/>
    <ui:param name="qualifier" value="#{param['qualifier']}"/>
    <ui:param name="cellStyleClass" value="#{param['cellStyle']}"/>
</ui:include>

someOther.xhtml(方法一)注意 ProfileAction 在 @RequestScoped 中

<tenui:entityCard profileEntity="#{profileAction.getProfileMetadata(profileUri)}"
  qualifier="#{qualifier}"   
  cellStyleClass="#{cellStyleClass}"/>

enityCard.xhtml(facelet 自定义标签)

<ui:fragment rendered="#{profileEntity.featured}">...
<tenui:gridCell id="#{profileEntity.profileId}#{qualifier}" ...      
 <tenui:metaunit ..content="#{profileEntity.getMeta('memberName')}" 
  href="/#{profileEntity.profileDisplayUri}" 
  hrefStyleClass="a-styled grid-cell-name"/>
  .....
  ...several other EL expressions including #{profileEntity.xxx} 

问题是 #{profileAction.getProfileMetadata(profileUri)} 正在为 entityCard.xhtml 中的每个属性评估调用然后,我想我会将方法调用的返回值保存在 ac:set var(approach 2 中,如下所述) 但它没有帮助。

someOther.xhtml(方法 2)

<c:set var="profileMetadata" 
       value="#{profileAction.getProfileMetadata(profileUri)}"/>
<tenui:entityCard profileEntity="#{profielMetadata}"
  qualifier="#{qualifier}"   
  cellStyleClass="#{cellStyleClass}"/>

action 方法调用一个非常昂贵的存储过程,并且返回的对象有超过 20 个属性,这些属性在 entityCard.xhtml 中的 EL 中进行评估。

我还尝试了另一种方法,通过直接调用 action 方法来解析 ui:param 本身的值,但根本无济于事。问题依旧。

有人能指出我做错了什么吗?或者,如何避免对 profileAction.getProfileMetadata 调用的多次调用?

【问题讨论】:

  • 您是否尝试将操作范围更改为ViewScoped?它应该会有所帮助。
  • 我可以尝试,但我不太明白它背后的基本原理。有一个获取实体卡的 Ajax 调用,我真的不希望 Bean 持续存在。此外,为什么将范围更改为 View 会对 EL 评估产生任何影响?
  • 这只是建议,ViewScoped 只要用户在同一个视图中就可以存活。您写道有 ajax 调用。如果是这样,则每次 ajax 调用都会重新创建范围。也许这就是为什么你的方法每次都被调用的原因。
  • 对不起,我应该解释得更好。有一个单一的 ajax POST 调用(由 Firebug 控制台正式验证),它加载 some.xhtml,并传递 3 个参数。这反过来又调用 someOther.xhtml,它使用 Requestscoped bean 方法的返回值初始化自定义标记。然后,自定义标记评估该返回对象的几个属性。但相反,它似乎正在评估方法调用本身,以获取它需要在返回的对象上获取的每个属性!
  • 代替&lt;c:set&gt;,你能试试&lt;ui:param&gt;吗?

标签: jsf jsf-2 jstl el


【解决方案1】:

您需要将&lt;c:set&gt;scope 属性设置为所需范围之一,requestviewsessionapplication。否则默认为none

假设您希望它是request,应该这样做:

<c:set var="profileMetadata" scope="request"
       value="#{profileAction.getProfileMetadata(profileUri)}" />

【讨论】:

  • 哇!这就像一个魅力!万分感谢!我仍然很好奇如果我根本不使用 c:set 为什么会重复调用 EL 中的该方法调用。
  • 因为默认情况下评估是延迟的。结果默认情况下不存储在任何范围内。请注意,在 getter 方法中调用业务逻辑被认为是不好的做法。另请参阅*.com/questions/2090033/…您的案例可能是一个极端案例,根据目前提供的信息无法可靠地判断。
  • 谢谢! ${...} 而不是 #{...} 会强制立即评估吗?
  • 在 JSP 中,是的;在 Facelets 中,没有。另请参阅 *.com/questions/4812755/… 在 Facelets 中始终坚持使用 #{}