问题是后台Bean Methode被调用多次
好吧,我已经阅读了@BalusC的答案
JSF是一种服务器端语言,根据HTTP请求在网络服务器上运行,并生成HTML / CSS / JS代码,该代码随HTTP响应返回。在生成HTML输出期间,所有$ {}和#{}形式的EL表达式都将在服务器端执行。 JavaScript是一种客户端语言,可在网络浏览器上运行并在HTML DOM树上运行。 HTML onclick属性应指定一个JavaScript函数,该函数将在特定HTML DOM事件的客户端执行。
所以我理解了为什么我的背部被多次调用的原因,所以我该如何解决这个问题
这是我回来的方法
@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次
答案 0 :(得分:1)
当在JavaScript代码内部使用jsf EL时,由于其中一个是静态的而另一个是动态的,因此使用多个JavaScript问题是正常的,您可以使用backbean jsf outputscript组件来做到这一点。
您可以将该JavaScript代码作为一个函数放在您的resource / js文件夹中的一个js文件中,并使用如下所示的Managed 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()");
答案 1 :(得分:0)
您在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()
)仅被调用一次(但不能保证...)无论如何,最好遵循里卡多和霍尔格的建议,从Why JSF calls getters multiple times的答案中建议将您的bean更改为:
@ManagedBean (name="villeBean")
@ViewScoped
public class Villes {
private String villesList;
public String listeVilles{
if(villesList == null) {
villesList = dao.listeVilles();
}
return villesList;
}
}
优势:
dao.listeVilles()
,业务逻辑(#{villeBean.listeVilles()}
)仅被调用一次。风险:
#{villeBean.listeVilles()}
仍会呈现并传输可能庞大的列表。答案 2 :(得分:0)
事实证明,您实际上想在localStorage
中拥有一个客户端缓存,并在该客户端缓存有效时阻止业务逻辑调用,
必须采用AJAX方式:
我建议实现一个有条件渲染的javascript ,该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>
可以通过以下建议的命令操作来触发更新:How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
<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解决方案或上述质量检查中提出的其他建议。
此命令操作将导致呈现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();
}
}