繁体   English   中英

如何仅在加载页面时使用 javascript 调用 JSF 支持 bean 方法

[英]How to call JSF backing bean method using javascript only when The page is loaded

问题是后面的 Bean Methode 被调用了很多次

好吧,我已经阅读了@BalusC 的这个答案

JSF 是一种服务器端语言,它根据 HTTP 请求在 Web 服务器上运行,并生成 HTML/CSS/JS 代码,这些代码与 HTTP 响应一起返回。 在生成 HTML 输出期间,所有 ${} 和 #{} 形式的 EL 表达式将在服务器端执行。 JavaScript 是一种客户端语言,它运行在 web 浏览器上并在 HTML DOM 树上工作。 HTML onclick 属性应指定一个 JavaScript 函数,该函数将在客户端针对特定 HTML DOM 事件执行。

如何仅在 onclick/oncomplete/on... 事件发生而不是在页面加载时调用 JSF 支持 bean 方法

所以我明白为什么我的背部被多次调用,那么我该如何解决这个问题

这是我的背靠 Methode

@ManagedBean (name="villeBean)"
@ViewScoped
public class Villes {
 public String listeVilles{
   return dao.listeVilles();
 }
}

这是我的 js 代码

if(localStorage['ville'] == null || localStorage['date']==null){
        localStorage.setItem('date',new Date());
        localStorage.setItem('ville',#{villeBean.listeVilles()});
}
else{ 
  var oldDate = new Date(localStorage['date']).getTime();;
  var currentDate = new Date().getTime();
  var distance =  currentDate - oldDate ;
  var days = Math.floor(distance / (1000 * 60 * 60 * 24));
  if (days >= 15){
    localStorage.setItem('date',date);
    localStorage.setItem('ville',#{villeBean.listeVilles()});
  }
} 

问题是后面的方法被调用了 2 次

可以使用backbean jsf outputscript组件来做,当你在javascript代码中使用jsf EL时,出现多个请求问题是正常的,因为一个是静态的,另一个是动态的。

您可以将该 javascript 代码放在一个 js 文件中作为您的资源/js 文件夹中的一个函数,并使用这样的托管 bean 调用该函数:

    UIOutput output = new UIOutput();       
    output.setRendererType("javax.faces.resource.Script");

    // JS FILE NAME DEFINED IN resource/js folder is put here ( example: myscript.js):
    output.getAttributes().put("name", "myscript.js");
    output.getAttributes().put("library", "js");        
    facesContext.getViewRoot().addComponentResource(facesContext, output, "form");

    UIOutput script = (UIOutput) facesContext.getApplication()
            .createComponent(facesContext,
                    JAVAX_FACES_OUTPUT_COMPONENT_TYPE,
                    JAVAX_FACES_TEXT_RENDERER_TYPE);

    UIOutput outputScript = (UIOutput) facesContext.getApplication()
            .createComponent(facesContext,
                    JAVAX_FACES_OUTPUT_COMPONENT_TYPE,
                    DEFAULT_SCRIPT_RENDERER_TYPE);

    /** AT HERE YOU SHOULD CALL YOUR JAVA SCRIPT FUNCTION WITH THE PARAMETERS OF YOUR BACK BEAN

 let's say that you have created something like that:

function addToLocalStorage(ville){
if(localStorage['ville'] == null || localStorage['date']==null){
        localStorage.setItem('date',new Date());
        localStorage.setItem('ville',ville});
}
}

  So you're going to call the function from backbean like that:
*/

    String ville = villeBean.listeVilles();
    script.setValue("addToLocalStorage(" + ville + ")");

    script.setTransient(true);

    script.setId(facesContext.getViewRoot().createUniqueId());

    outputScript.getChildren().add(script);

    outputScript.setTransient(true);
    outputScript.setId(facesContext.getViewRoot().createUniqueId());

    facesContext.getViewRoot().addComponentResource(facesContext,
            outputScript, TARGET_ATTR);

另一个选择是使用 Primefaces 套件中的 RequestContext,这样您就可以从 JSF 托管 bean 中调用 javascript 函数:

RequestContext.getCurrentInstance().execute("myfunction()");

事实证明,您实际上希望在localStorage有一个客户端缓存,并在该客户端缓存有效时阻止业务逻辑调用,您必须采用 AJAX 方式:

我建议实现一个有条件渲染的 javascript 它仅在需要时更新本地存储:

<h:panelGroup id="updateLocalStorageScript" style="display: none;">
    <h:outputScript rendered="#{villeBean.updateLocalStorage}">
        localStorage.setItem('date',date);
        localStorage.setItem('ville', #{villeBean.villesList});
    </h:outputScript>
</h:panelGroup>

更新可以由此处提议的命令操作触发: 如何使用本机 JavaScript 在 HTML DOM 事件上调用 JSF 托管 bean?

<h:form id="frmHidden" style="display: none;">
    <h:commandButton id="cmdDoUpdateLocalStorage" action="#{villeBean.doUpdateLocalStorage()}">
        <f:ajax execute="@this" render=":updateLocalStorageScript" />
    </h:commandButton>
</h:form>

当然,您也可以使用p:remoteCommand 、OmniFaces 解决方案或上述 QA 中提出的其他建议。

此命令操作会导致 javascript 被呈现并通过仅调用一次您的业务逻辑来初始化列表值。

@ManagedBean (name="villeBean)"
@ViewScoped
public class Villes {
    private boolean updateLocalStorage;

    private String villesList;

    public void doUpdateLocalStorage() {
        updateLocalStorage = true;
        villesList = dao.listeVilles();
    }

    public boolean isUpdateLocalStorage() {
        return updateLocalStorage;
    }

    public String getVillesList() {
        return villesList;
    }

}

从 javascript 条件块中触发该命令:

if(localStorage['ville'] == null || localStorage['date']==null){
    document.getElementById('frmHidden:cmdDoUpdateLocalStorage').onclick();
}
else{ 
  var oldDate = new Date(localStorage['date']).getTime();;
  var currentDate = new Date().getTime();
  var distance =  currentDate - oldDate ;
  var days = Math.floor(distance / (1000 * 60 * 60 * 24));
  if (days >= 15){
    document.getElementById('frmHidden:cmdDoUpdateLocalStorage').onclick();
  }
} 

您的 javascript 中有两个 EL-Expression #{villeBean.listeVilles()}实例,无论您的 javascript 条件如何,它们都被呈现(并因此被调用)服务器端。

像这样更改您的脚本,以便只调用一次:

var villesList = #{villeBean.listeVilles()};
if(localStorage['ville'] == null || localStorage['date']==null){
        localStorage.setItem('date',new Date());
        localStorage.setItem('ville', villesList);
}
else{ 
  var oldDate = new Date(localStorage['date']).getTime();;
  var currentDate = new Date().getTime();
  var distance =  currentDate - oldDate ;
  var days = Math.floor(distance / (1000 * 60 * 60 * 24));
  if (days >= 15){
    localStorage.setItem('date',date);
    localStorage.setItem('ville', villesList);
  }
} 

优势:

  • 业务逻辑( dao.listeVilles() )只被调用一次(但不能保证这个......)
  • 潜在的巨大列表只发送到浏览器一次,减少了数据传输开销。

无论如何,遵循 Ricardo 和 Holger 的建议是一个好主意,该建议来自于为什么 JSF 多次调用 getter建议将您的 bean 更改为:

@ManagedBean (name="villeBean")
@ViewScoped
public class Villes {

   private String villesList;

   public String listeVilles{
       if(villesList == null) {
           villesList = dao.listeVilles();
       }
       return villesList;
   }
}

优势:

  • 业务逻辑 ( dao.listeVilles() ) 仅在 xhtml 文件中出现任意次数的#{villeBean.listeVilles()}时调用一次。

风险:

  • 在您的 xhtml 中每次出现#{villeBean.listeVilles()}仍然呈现和传输潜在的巨大列表。
  • 使用 AJAX 时,您的视图可能会看到旧的/过时的数据,因为这是在同一视图范围内从未失效的缓存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM