JSF页面中使用js函数回调后台bean方法并获取返回值的方法

时间:2023-02-20 08:26:20

由于primefaces在国内使用的并不是太多,因此,国内对jsf做系统、详细的介绍的资料很少,即使有一些资料,也仅仅是对国外资料的简单翻译或者是仅仅讲表面现象(皮毛而已),它们的语句甚至还是错误的,很可能会误导使用者。

相对来说,看国内的那些仅仅是翻译过来的文章或书籍不如直接看国外的官方文档或资料来的实在,在我讲述jsf页面中如何使用js调用后台bean方法之前,先给大家说几个国外的资料。在primefaces官方网站上,你可以搜索到几乎所有你需要的东西,primefaces官网为:http://www.primefaces.org/showcase/index.xhtml 如过觉得自己英语不好的童鞋,可以前往primefaces国内镜像网站查阅资料: http://www.primefaces.cn/ ,只是国内的这个网站正在翻译中,有些东西还不完善;如果有想细致的了解primefaces的朋友,还可以下载primefaces的官方文档,最新的官方文档为5.2,全英文,我在这里给大家提供我下载好的primefaces官方文档:http://pan.baidu.com/s/1mg3i9Ry ,在这个文档里你可以通过他们的示例来组合出来很多有趣的东西。

好,接下来进入正文。

某些情况下,在开发jsf项目时,我们需要必须使用html组件来达到一些使用Jsf组件不能达到的目标。例如有时候我们希望,当触发某些html组件或标签时,触发后台方法甚至接收后台方法传过来的返回值。这回让我们很头疼,因为primefaces并没有给我们说如何使用js来调用后台bean方法。那么,我们就需要结合js和jsf同时才可以达到这个目的。

达到这个目的又两个方法。

1 使用jsf的inputHidden标签

这几乎算不上真正的js调用后台的方法,因为它无法向后抬bean传递值,但是简单的后台向页面传递数据可以使用这个方法

<h:inputHidden id="input" value="#{advancedQueryManager.aliaColums}"></h:inputHidden>

首先,在jsf中触发某个组件时,要及时update这个inputHidden标签,例如下面的组件

<p:selectOneMenu id="module"
    value="#{advancedQueryManager.selectedModule}">
    <f:selectItem itemLabel="----" itemValue="" />
    <f:selectItems value="#{advancedQueryManager.allModule}" />
    <p:ajax event="change" update="input"
        oncomplete="getVlue()"
        listener="#{advancedQueryManager.onModuleChange()}"></p:ajax>
</p:selectOneMenu>

这里面的组件就会当这个下拉值变化时,就会触发后台的方法

onModuleChange()

当,方法结束后,它会update(刷新)这个

h:inputHidden

如果你的这个inputHidden中的值是随下拉的变化和变化的呢,那么,你就可以在任何的js函数中获取到这个inputHidden中的值,然后进行处理,

function getVlue() {
    /* document.getElementById("commBtn").onclick; */
    alert("a");
    var aliaColums = document.getElementById("input").value;
    dataJson = eval("(" + aliaColums + ")");
        addqueryroot('.query', true);
}

我这里的inputHidden 盛的是一个json格式的字符串,我通过js函数就可以动态的获取这个json,进而进行其他的操作。当然,可以在任何html标签中调用这个js函数,然后获取这个json字符串。

2 使用commandButton来达到复杂的异步刷新取值

在这里说下,普通的html标签结合js函数结合commandButton可以达到什么效果呢?那就是在你触发任何html标签时,你都可以通过这个commandButton组件来将你在html标签中选定的值传递到后台,经过后台bean处理后,它会返回处理结果,js函数就可以接收到这个处理结果,然后再将这个结果整合到其他的组件中。

首先,创建这个隐藏的commandButton,注意,这个commandButton本身不具有隐藏的属性,可以通过其他有隐藏属性的组件将其包裹,以达到隐藏的目的,我通过一个div来达到这个目的。在这个commandButton中,我们发现,action的作用就是当点击这个commandButton时,它会调用后台方法,而attribute中的name 属性和value属性的作用会在下面将。

<div id="hiddenForm" style="display: none;">
    <p:commandButton id="command"
        actionListener="#{advancedQueryManager.testReturn}"
        oncomplete="handleComplete(xhr, status, args)">
        <f:attribute name="attrname1" value="liu" />
        <f:attribute name="attrname2" value="bei" />
    </p:commandButton>
</div>

然后我们需要一个普通的html标签,就以一个普通的html button为例:

<input type="button" value="回调测试" onclick="test()" />

然后写一个js函数,来连接这个普通的button和jsf组件commandButton

function test() {
    $('#command').click();
}

这个函数的意思就是,当你点击这个"回调测试"的按钮时,它就相当于触发了jsf的cimmandButton按钮,这时,commandButton中的两个

<f:attribute name="attrname1" value="liu" />

中的两个属性就会自动绑定成一个类似于map形式的数据,name属性的值作为key,value中的值作为map中的value,它们将会被传递至后台。

然后,后台的bean 中需要有方法来接收两个值:

public void testReturn(ActionEvent event) {
    String attrvalue1 = (String) event.getComponent().getAttributes()
        .get("attrname1");
    String attrvalue2 = (String) event.getComponent().getAttributes()
        .get("attrname2");
    System.out.println(attrvalue1);
    System.out.println(attrvalue2);
    RequestContext requestContext = RequestContext.getCurrentInstance();
    requestContext.addCallbackParam("isValid", true);

}

在上面的代码中,我们可以看到,java程序已经成功的接收前端页面传过来的值,它最后也返回了一个类是于map格式的值,key为:isValid,value 为:true

最后,我们要写一下页面如何接收后台传递过来的值:

<script type="text/javascript">
    function handleComplete(xhr, status, args) {
        var isValid = args.isValid;
        alert(isValid);
    }
</script>

接下来,就会发现不仅仅后台可以正常打印出前端页面中的那两个值,同时前端的js函数也可以打印出后台传过来的值,当然,同样的,从前端传递到后台的值的个数和形式,你可以自己改,同时从后台接收到的数据,你也可以随意的进行任何操作。

但是请注意,这个

p:commandButton

组件有个问题,就是你不可以动态的通过js函数来将一些值赋给这个组件,但是这个组件里的值可以接受后台的属性值

<f:attribute name="attrname1" value="#{bean.val}" />

这样其实也并没有达到我们想要通过js来传给后台bean的目的,接下来的方法,就可以完全达到通过js动态的传值给后台bean方法,bean方法处理完返回数据给js。

3 使用p:remoteCommand来达到复杂的异步刷新取值

大家请注意,这个方法可以真正的解决在jsf中通过js调用后台bean方法并获取bean方法返回值的问题。

同样,首先我们要写两个jsf组件,来和后台bean结合

<h:inputHidden id="input1" value="#{advancedQueryManager.vals}"></h:inputHidden>
<h:form>
    <p:remoteCommand name="processSelection"
        action="#{advancedQueryManager.testReturn}" update=":input1"
        oncomplete="processResult();" />
</h:form>

解释一下,上面的的这个inputHidden的作用是接收后台bean处理后的返回值。remoteCommand的作用是将js中的动态的值传递到后台bean方法。

<script>
    function processResult() {
        //接收后台bean方法中传递过来的处理结果,接收方法是获取inputHidden中的值,并可根据自己的业务继续处理
        alert($('#input1').val());
    }

    function makeSelection() {
            //普通的html组件调用这个js
        //将想要传递到后台的动态值封装成json格式的值,传给p:remoteCommand,然后由这个组件传给bean方法
        processSelection([ {name : 'setVal',value : 'getIt'} ]);
    }
/script>

js函数使用方法在代码中,谁不懂可以再艾特我,这里不再解释。

最后是后台bean方法代码:

public void testReturn() {
        String selectedValue = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("setVal");
        System.out.println("------>"+selectedValue);
           //拦截到这个页面传过来的值后可以进行你自己的业务处理
           //并将处理结果返回给vals,这个vals是这个bean中的一个属性
           vals = "getResult";

}

至此,jsf中使用js函数将普通的html组件的值动态的传递到后台bean方法并接受后台处理结果已经成功得到解决。