JSF笔记 - 托管Bean的详细介绍

1、托管Bean的介绍:

托管Bean的基本功能:

提供一组属性与页面中UI组件对应; 提供一组对页面组件执行功能的方法。

托管Bean可以绑定的形式:

绑定到一个组件的值(value) 绑定到一个组件的实例(bingding) 绑定到一个转换器实例(<f:converterXxx>) 绑定到一个验证器实例(<f:validatorXxx>) 绑定到一个监听器实例(<f:xxxListener>)

1.1、绑定到一个组件的实例(bingding)的使用举例:

在show.jsp页面中添加如下组件:

<f:view>

组件显示


<h:form id=”loginForm”>
<h:inputText binding=”#{show.bindingTest }”></h:inputText>
<h:commandButton action=”#{show.setBinding }” value=”显示”></h:commandButton>
</h:form>
</f:view>

在托管Bean中添加如下属性并添加setBinding方法,此方法用于设置组件实例的显示:

public class ShowBean {

private HtmlInputText bindingTest;
public HtmlInputText getBindingTest() {
    return bindingTest;
}
public void setBindingTest(HtmlInputText bindingTest) {
    this.bindingTest = bindingTest;
}

public String setBinding(){
    bindingTest.setValue("Java");
    bindingTest.setStyle("color:#cfdcff");
    return null;
}

}

在faces-config-beans.xml配置文件中配置托管Bean:


<!-- 指定Bean名称 –>
show
<!-- 指定Bean全限定类名 –>
com.itzhai.login.ShowBean
<!-- 指定托管Bean的有效范围:request,session,application –>
request

并不需要设置导航规则,因为方法中返回为null。

部署项目,启动服务器,访问:http://localhost:8080/JSFTest/show.jsf

在页面中点击组件显示按钮就会显示出组件了。

这个JSF应用有点类似于Ajax,但是并没有采用Ajax技术:

依然以同步方式提交请求 视图状态是保存在服务器端的,这样,即使客户端刷新页面,显示的效果依然存在。 JSF应用通过在托管Bean中变成控制指定的UI组件,这种方式比Ajax灵活性差。

2、托管Bean的编写:

与普通的Java Bean一样,为其提供一个无参构造函数,每个属性提供getter和setter方法。

3、托管Bean的常用子标签:

<!-- 配置托管Bean –>


<!-- 指定Bean名称 –>
login
<!-- 指定Bean全限定类名 –>
com.itzhai.login.LoginBean
<!-- 指定托管Bean的有效范围:request,session,application –>
request

4、为应用增加导航规则:


<!-- 导航规则的输入页面 –>
/login.jsp

success
/index.jsp


failure
/login.jsp

其配置类似于Struts2中Action的配置。

5、托管Bean的方法:

托管Bean的方法主要有如下几种:

① 处理导航的方法

通常用comandButton或者commandLink两个标签中的action属性将单击事件绑定到托管Bean内处理导航的方法。

处理的方法名格式必须为:

public String xxx()

其返回值必须是String类型,这个返回值是一个逻辑视图,JSF导航规则将会根据该逻辑视图导航到真实的物理视图。

② 处理Action事件的方法

通常用commandButton或者commandLink两个标签中的actionListener属性将单击事件绑定到托管Bean内处理Action事件的方法。

处理的方法格式必须为:

public void xxx(ActionEvent ae)

该方法被触发时,该形参就代表了触发该方法的事件对象。

对于处理Action事件的方法而言,它没有返回值,因此它不会导致应用导航到其他页面,但程序可以通过该方法来改变应用的状态,从而改变该页面的显示。

下面是一个使用actionListener属性的例子:

首先编写actioneventtest.jsp页面:

<%@ page contentType=”text/html;charset=UTF-8” language=”java” %>
<%@ taglib prefix=”f” uri=”http://java.sun.com/jsf/core" %>
<%@ taglib prefix=”h” uri=”http://java.sun.com/jsf/html" %>



Login


<!-- 使用JSF视图输出 –>
<f:view>

ActionEvent Test


<h:form id=”actionEventForm”>
<h:inputText binding=”#{actionEvent.eventTest }”></h:inputText>
<h:commandButton actionListener=”#{actionEvent.process }” value=”测试”></h:commandButton>
</h:form>
</f:view>

接下来编写托管Bean ActionEventBean

public class ActionEventBean {

//绑定UI组件本身的属性
private HtmlInputText eventTest;
public HtmlInputText getEventTest() {
    return eventTest;
}
public void setEventTest(HtmlInputText eventTest) {
    this.eventTest = eventTest;
}
public ActionEventBean(){}

//编写处理Action事件的方法
public void process(ActionEvent ae){
    eventTest.setValue(ae.getComponent());
    eventTest.setStyle("color:#cfcfff");
}

}

在faces-config-beans.xml文件中配置托管Bean:


<!-- 指定Bean名称 –>
actionEvent
<!-- 指定Bean全限定类名 –>
com.itzhai.login.ActionEventBean
<!-- 指定托管Bean的有效范围:request,session,application –>
request

在faces-confg-nav.xml设置导航规则,这里也可不用设置,因为页面没有跳转。


<!-- 导航规则的输入页面 –>
/actioneventtest.jsp

在web.xml中设置JSF参数:


javax.faces.STATE_SAVING_METHOD
<!-- 程序状态保存在服务器端 –>
server

这个程序必须设置把程序状态保存在服务器端,否则会出错:

严重: JSF1054: (Phase ID: RENDER_RESPONSE 6, View ID: /actioneventtest.jsp) Exception thrown during phase execution: javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl@5c7734]
2011-12-2 15:31:55 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet FacesServlet threw exception
java.io.NotSerializableException: javax.faces.component.html.HtmlCommandButton

③ 处理Value Change事件的方法

④ 处理输入校验的方法

6、在托管Bean中保存和获取Session中的数据:

为了获取Session中的信息,有两种方法:

通过FacesContext获取Servlet API,使用原生的Servlet API访问session、applicatoin等; 通过使用session范围的托管Bean。

第一种方式简洁直观,但是导致了托管Bean与JSF API,Servlet API耦合,属于典型的侵入式设计,还停留在原始的MVC框架阶段,没有使用到JSF的优势。

下面使用第二种方式实现:

这里假如UserBean是需要放在Session范围中的,可以在faces-config-beans中进行如下设置:


<!-- 指定Bean名称 –>
userbean
<!-- 指定Bean全限定类名 –>
com.itzhai.login.UserBean
<!-- 指定托管Bean的有效范围:request,session,application –>
session

假如LoginBean中需要获取Session中保存的UserBean,可以在faces-config-beans配置中注入参数:


<!-- 指定Bean名称 –>
loginbean
<!-- 指定Bean全限定类名 –>
com.itzhai.login.LoginBean
<!-- 指定托管Bean的有效范围:request,session,application –>
request

userbean
#{userbean}

6.1、通过FacesContext访问应用环境:

JSF页面在相应时,应用会创建一个新的视图并将它保存到FacesContext实例中,FacesContext实例包含了所有与处理请求、创建响应相关联的信息。接下来应用会获取该视图所需的对象引用,并调用FacesContext.renderResponse方法让应用开始向客户端生成响应。

FacesContext接口包含的方法:

ResponseStream getResponseStream()
ResponseWrite getResponseWriter()
ExternalContext getExternalContext()

其中的ExternalContext又提供了如下的方法:

getApplicationMap()
getInitParameter(String)
getInitParameterMap()
getRequestContextPath()
getRequestParameterMap()
getRequestServletPath()
getResponse()
getSession(boolean create)
getSessionMap()
redirect(String)

使用举例:

FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.getSessionMap().put(“username”, “arthinking”);

7、托管Bean的分类:

Backing-Bean:相当于Struts1中的ActionForm Controller-Bean:相当于Struts1中的Action Model-Bean:充当应用状态模型,类似于上面的UserBean Utility-Bean:为应用的多个视图页面提供通用性质的工具。

使用Backing-Bean+Controller-Bean开发类似于Struts1的开发,使用Controller-Bean(即是把Backing-Bean中的数据也保存在这个Bean中)开发类似于Struts2中的开发。追求架构的话就使用第一种方式,追求实用的就推荐使用第二种方式。

而使用第一种方式与Struts1的区别在于:Strust1中Action通过execute方法以形参硬编码的方式来获取ActionForm,而JSF的controller-bean则通过依赖注入、以松耦合的方式来获取backing-bean。

下面演示第一种方式的使用:

编写backing-bean:

public class UserBean {

private String username;
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
private String password;
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}

}

编写controller-bean:

public class UserControllerBean {

private UserBean userBean;

public UserBean getUserBean() {
    return userBean;
}

public void setUserBean(UserBean userBean) {
    this.userBean = userBean;
}

public String valid(){
    if(userBean.getUsername().equals("arthinking")
            && userBean.getPassword().equals("123")){
        return "success";
    }
    return "failure";
}

}

接下来在faces-config-beans.xml配置文件中进行配置:

<!-- 配置backing-bean –>


userbean
com.itzhai.login.UserBean
request

<!-- 配置controller-bean –>


userControllerBean
com.itzhai.login.UserControllerBean
request

userBean
#{userbean }

这样就可在页面中这样访问了:

<%@ page contentType=”text/html;charset=UTF-8” language=”java” %>
<%@ taglib prefix=”f” uri=”http://java.sun.com/jsf/core" %>
<%@ taglib prefix=”h” uri=”http://java.sun.com/jsf/html" %>



Login


<!-- 使用JSF视图输出 –>
<f:view>

back-bean Test


<h:form id=”actionEventForm”>
<h:inputText binding=”#{userbean.username }”></h:inputText>
<h:commandButton actionListener=”#{userControllerBean.valid }” value=”测试”></h:commandButton>
</h:form>
</f:view>

8、初始化托管Bean的属性:

可以在faces-config-bean.xml文件中配置托管Bean时,通过配置参数的值得方式进行初始化。

例如有一个InitParaBean的参数需要初始化,包含String、Map和List类型的参数:

public class InitParaBean {

private String name;
private Map<String, String> music;
private List<String> type;
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public Map<String, String> getMusic() {
    return music;
}
public void setMusic(Map<String, String> music) {
    this.music = music;
}
public List<String> getType() {
    return type;
}
public void setType(List<String> type) {
    this.type = type;
}

}

可以在faces-config.xml文件中进行初始化:


initparabean
com.itzhai.bean.InitParaBean
request
<!-- 初始化String类型 –>

name
java.lang.String
音乐列表

<!-- 初始化Map类型 –>

music

java.lang.String
java.lang.String

蜗牛
周杰伦



<!-- 初始化List类型 –>

type

folk music


这样在页面中就可以直接使用这个托管Bean了,编写initparatest.jsp 页面:

<%@ page contentType=”text/html;charset=UTF-8” language=”java” %>
<%@ taglib prefix=”f” uri=”http://java.sun.com/jsf/core" %>
<%@ taglib prefix=”h” uri=”http://java.sun.com/jsf/html" %>



Login


<!-- 使用JSF视图输出 –>
<f:view>

InitPara Test


<h:outputText value=”#{initparabean.name }” />
<h:outputText value=”#{initparabean.music[‘蜗牛’] }” />
<h:outputText value=”#{initparabean.type }” />
</f:view>

启动服务器,访问:http://localhost:8080/JSFTest/initparatest.jsf 即可。

arthinking wechat
欢迎关注itzhai公众号