如何在构建时创建变量?

How to create a variable in build time?

我有这个页面:

<c:forEach begin="0" end="#{tareaController.tipoFuncion.filas}" step="1" var="x">
    <p:row>
        <c:forEach begin="0" end="#{tareaController.tipoFuncion.columnas}" step="1" var="y">
            <c:choose>
                <c:when test="#{tareaController.configuracionEnPosicion(x,y) ne null}">
                    <p:column style="width: 80px" 
                              colspan="#{tareaController.configuracionEnPosicion(x,y).colSpan}"
                              rowspan="#{tareaController.configuracionEnPosicion(x,y).rowSpan}">
                        <p:outputLabel value="#{tareaController.atributoEnPosicion(x,y).labelAtributo}:" 
                                       rendered="#{!tareaController.validar.isBoton(tareaController.atributoEnPosicion(x, y).tipoAtributosOpcionales)}">
                            <c:if test="#{tareaController.configuracionEnPosicion(x,y).esObligatorio}">
                                *
                            </c:if>
                        </p:outputLabel>
                    </p:column>
                    <p:column colspan="#{tareaController.configuracionEnPosicion(x,y).colSpan}"
                              rowspan="#{tareaController.configuracionEnPosicion(x,y).rowSpan}"> 
                        <c:choose>
                            <c:when test="#{tareaController.validar.isSeparador(tareaController.atributoEnPosicion(x, y).tipoAtributosOpcionales)}">
                                <p:separator/>
                            </c:when>
                            <c:when test="#{tareaController.validar.isNumerico(tareaController.atributoEnPosicion(x,y).tipoAtributosOpcionales)}">
                                <pe:inputNumber decimalSeparator="#{tareaController.configuracionEnPosicion(x,y).separadorDecimal}" 
                                                thousandSeparator="#{tareaController.configuracionEnPosicion(x,y).separadorMiles}" 
                                                decimalPlaces="#{tareaController.configuracionEnPosicion(x,y).cantidadDecimales}" 
                                                disabled="#{mFuncion.soloLectura || !tareaController.tareaAceptada || tareaController.tomadaPorOtroUsuario || tareaController.configuracionEnPosicion(x,y).soloLectura}"
                                                maxValue="#{tareaController.configuracionEnPosicion(x,y).valorMaximo}"
                                                rendered="#{!tareaController.configuracionEnPosicion(x,y).ocultarAtributo}"
                                                value="#{tareaController.atributoEnPosicion(x,y).valorAtributoNumerico}" 
                                                style="width: #{tareaController.configuracionEnPosicion(x,y).ancho}px; height: #{tareaController.configuracionEnPosicion(x,y).alto}px;">
                                    <p:ajax global="false" update=":f_tarea:tabView:tab_#{tareaController.indiceTramite}:nombreRepetido, :f_tarea:b_completarT" listener="#{tareaController.validarTarea()}"/>
                                </pe:inputNumber>
                            </c:when>
                            <c:when test="#{tareaController.validar.isBoton(tareaController.atributoEnPosicion(x, y).tipoAtributosOpcionales)}">
                                <p:commandButton value="#{tareaController.atributoEnPosicion(x,y).labelAtributo}" 
                                                 actionListener="#{tareaController.ejecutarWs(tareaController.configuracionEnPosicion(x,y))}"
                                                 update=":f_tarea:tabView:tab_#{tareaController.indiceTramite}:pg_funcion_#{tareaController.indiceTramite}"/>
                            </c:when>
                            <c:when test="#{tareaController.validar.isFecha(tareaController.atributoEnPosicion(x,y).tipoAtributosOpcionales)}">
                                <p:calendar value="#{tareaController.atributoEnPosicion(x,y).valorAtributoFecha}" 
                                            maxdate="#{tareaController.configuracionEnPosicion(x,y).fechaMaxima}" 
                                            mindate="#{tareaController.configuracionEnPosicion(x,y).fechaMinima}"
                                            rendered="#{!tareaController.configuracionEnPosicion(x,y).ocultarAtributo}"
                                            disabled="#{mFuncion.soloLectura || !tareaController.tareaAceptada || tareaController.tomadaPorOtroUsuario || tareaController.configuracionEnPosicion(x,y).soloLectura || tareaController.atributoEnPosicion(x,y).bloquear}"
                                            size="20"
                                            pattern="#{tareaController.configuracionEnPosicion(x,y).formatoFecha}">
                                    <p:ajax global="false" update=":f_tarea:tabView:tab_#{tareaController.indiceTramite}:nombreRepetido, :f_tarea:b_completarT" listener="#{tareaController.validarTarea()}"/>
                                    <p:ajax event="dateSelect" global="false" update=":f_tarea:tabView:tab_#{tareaController.indiceTramite}:nombreRepetido, :f_tarea:b_completarT" listener="#{tareaController.validarTarea()}"/>
                                </p:calendar>
                            </c:when>
                            <c:otherwise test="#{tareaController.validar.isAlfanumerico(tareaController.atributoEnPosicion(x,y).tipoAtributosOpcionales)}">
                                <p:inputTextarea value="#{tareaController.atributoEnPosicion(x,y).valorAtributoAlfanumerico}" 
                                                 disabled="#{mFuncion.soloLectura || !tareaController.tareaAceptada || tareaController.tomadaPorOtroUsuario || tareaController.configuracionEnPosicion(x,y).soloLectura}"
                                                 rendered="#{!tareaController.configuracionEnPosicion(x,y).ocultarAtributo}"
                                                 style="width: #{tareaController.configuracionEnPosicion(x,y).ancho}px; 
                                                 height:  #{tareaController.configuracionEnPosicion(x,y).alto}px; 
                                                 word-break: normal;">
                                    <p:ajax global="false" update=":f_tarea:tabView:tab_#{tareaController.indiceTramite}:nombreRepetido, :f_tarea:b_completarT" listener="#{tareaController.validarTarea()}"/>
                                    <p:ajax event="select" global="false" update=":f_tarea:tabView:tab_#{tareaController.indiceTramite}:nombreRepetido, :f_tarea:b_completarT" listener="#{tareaController.validarTarea()}"/>
                                </p:inputTextarea>
                            </c:otherwise>
                        </c:choose>
                    </p:column>
                </c:when>
                <c:otherwise>
                    <p:column>
                        <h:panelGroup/>
                    </p:column>
                    <p:column>
                        <h:panelGroup/>
                    </p:column>
                </c:otherwise>
            </c:choose>
        </c:forEach>

我的想法是,我可以配置该页面并将组件放置在我想要的位置,有很多不同的配置。它工作得很好,人们对此很满意,但我不是。如果您在页面上查看,我会在循环中的每个 运行 调用方法 configuracionEnPosicion(x,y) 和 atributoEnPosicion(x,y) 大约 300 次。这些方法像其他 3 个方法一样调用并执行 foreach 以在 x、y 中找到实际配置。令人惊讶的是,它的运行速度并不慢,但我觉得这是我可以避免的大量开销。

在我尝试将 configuracionEnPosicion(x,y) 和 atributoEnPosicion(x,y) 的结果及其各自的 getter 和 setter 保存在客户端的变量中之前,但是自从JSTL Core 标记 运行s 在构建时,在渲染时该变量未更新,导致该变量保持其最后一个值并给出不希望的行为。我的 "solution" 是实际的,但我的最后一个问题是:有没有一种方法可以存储该变量的值,以便我只能在构建时间或类似的时间保持它的活动?我想在每个 x 和 y 位置只调用一次这些方法,但我对 JSF 和 Primefaces 的了解不足以实现这一点。

附加信息:

你可以使用 c:set.

<c:set var="salary" scope="request" value="#{calculatePosition(x,y)}"/>

或者您可以使用 varstatus,具体取决于您的 fct 中发生的情况。 (这是 jsf 标签的文档,不是 jstl 标签,但它们是同一回事)。

我在@BalusC 评论后编辑了我的答案

您可以预先计算支持 bean PostConstruct 方法中的所有值。

  • 在支持 bean 级别声明一个二维数组:

    private ReturnedObjectClass[][] precalculatedArray;
    
  • 添加getter方法。

  • 在PostConstruct方法中初始化:

    precalculatedArray = new ReturnedObjectClass[x][y];
    
  • 用您的函数在 PostConstruct 方法中返回的对象填充它:

    precalculatedArray[i][j] = myBigFunction(i,j);
    

然后您可以使用以下方法从您的页面访问计算值:

    value="#{tareaController.precalculatedArray[x][y].propertyOfReturnedObjectClass}"

看起来像是 JSR 107: JCACHE - Java Temporary Caching API 的任务。但是您应该使用 CDI bean 而不是 JSF 托管 bean。这允许您编写如下代码:

 @CacheResult(cacheName = "configuracionEnPosicion")
 public String configuracionEnPosicion(int x, int y){
    .....
 }

还需要创建META-INF/beans.xml:

 <beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <interceptors>
         <class>org.jsr107.ri.annotations.cdi.CacheResultInterceptor</class>
         <class>org.jsr107.ri.annotations.cdi.CachePutInterceptor</class>
         <class>org.jsr107.ri.annotations.cdi.CacheRemoveEntryInterceptor</class>
         <class>org.jsr107.ri.annotations.cdi.CacheRemoveAllInterceptor</class>
    </interceptors>
</beans>

还需要在某处创建缓存:

@PostConstruct
public void init() {
    try {
        // Retrieve the system wide cache manager
        CacheManager cacheManager = Caching.getCachingProvider().getCacheManager();
        // Define a named cache with default JCache configuration
        MutableConfiguration<String, String> configuration = new MutableConfiguration<>();
        //specify expiry policy
        configuration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE));
        cache = cacheManager.createCache("configuracionEnPosicion", configuration);
    } catch (Exception e) {
        L.error("Can't init cache!", e);
    }
}

当然,您应该 select jcache 提供程序(ecache、infinispan 等)并向项目添加必要的依赖项。