这里使用JSF2.0技术实现中国行政区划管理,通过范例可以看到JadePool实现了与JSF框架和Primefaces的完美组合。本范例完整演示了以下操作:1、导入中国大陆行政区划记录,并将记录保存到数据库中;2、实现多功能的分页查询;3、在DataTable行中修改行政区划记录。数据来源于国家统计局于2012年11月份公布的中国大陆行政区划。这些数据被打包在jadepool-1.0-GBK.jar文件中,可以通过cn.jadepool.util.China的division()方法导出。
一、修改模板文件
1、将模板文件IndexTemplate.xhtml中的<p:menuitem value="行政区划" url="#" />修改为:<p:menuitem value="中国行政区划" outcome="cn_address" />,outcome指向本系统内的一个JSF页面文件,不需要文件的后缀名。
2、增加一个导航到首页的菜单项<p:menuitem value="返回首页" outcome="index" icon="ui-icon-home"/>,icon用来在菜单项前增加一个图标。
3、在底部布局中,增加一个消息提示组件<p:growl/>,需要在<h:form/>中添加。代码如下:
<p:layoutUnit position="south" size="40" closable="true" collapsible="true">
<h:form id="bottomForm" style="padding: 4px;text-align:center;">
...
<p:growl id="bottomGrowl" showDetail="true" />
</h:form>
</p:layoutUnit>
修改后的模板文件见附件1。
二、创建AddressBean受管Bean
AddressBean受管Bean源代码见附件2。
AddressBean用来提供行政区划的数据,实现应用程序逻辑和业务逻辑。除了set、get方法外,其它的属性、方法均作了详细的注释。由于使用JadePool作为持久化工具,实现数据更新、查询的操作都非常方便。
三、创建中国行政区划管理页面
创建模板客户端网页文件cn_address.xhtml,源代码见附件3。
创建后,将文件的字符集编码修改GBK。
在cn_address.xhtml页面中实现了以下操作:
1、导入中国行政区划记录,并将记录保存到数据库中;
2、实现多功能的分页查询;
3、在DataTable行中修改行政区划记录。
导入的页面代码:
<p:commandButton style="float: left;" value="初始化地名" action="#{addressBean.reUpdateDiming}" icon="ui-icon-disk" update="@form :bottomForm:bottomGrowl"/>
导入实现的java代码:
/**
* 导入中国大陆的行政区划
*
* @return null 导航到指定的页面,null值代表返回当前的页面
*/
public String reUpdateDiming() {
Jade j = new Jade();
List<Map> v = cn.division();
for (Map m : v) {
j.save("cn_address", m);//这是为了保护已经修改的成果
}
dimingList = j.query("select * from cn_address");
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("导入地名", "导入地名记录" + dimingList.size() + "条!"));
return null;
}
分页查询的页面代码:
<p:dataTable id="addressDataTable"
value="#{addressBean.dimingModel}"
var="m"
rowIndexVar="i"
paginator="true"
paginatorPosition="bottom"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,15,20,25,30,35,40,45,50,55,60"
selection="#{addressBean.dimingSelected}"
selectionMode="single"
editable="true"
>
......
在分页中调用的查询数据,如:
<p:column headerText="标准名称" style="15%;" sortBy="#{m.addressname}" >
#{m.addressname}
</p:column>
需要指出的是ListMapDataModel dimingModel数据模型是直接将JadePool查询结果转换而来的,而且可以直接在JSF的UI组件中调用,如:<p:inputText value="#{m.longitude}" />。将其修改后又能直接保存到数据库中,因此,极大地方便了JadePool用户。代码如:onEdit方法中保存修改的代码
Record r = new Record();
Map dm = r.one(this.dimingList, "addresscode", m.get("addresscode"));
Jade j = new Jade();
j.save("cn_address", dm);
//......
修改记录时的页面效果见图

附件1:IndexTemplate.xhtml
<?xml version='1.0' encoding='GBK' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>China软件项目</title>
<h:outputStylesheet library="css" name="primefaces.css"/>
<style type="text/css">
.ui-selectoneradio td{border: 0px;padding: 4px;background-color: transparent;}/*去掉p:selectOneRadio中表格宽度*/
.my-north,.my-north div{margin: 0px;padding: 0px;border: 0px;color:white;background:url(none) transparent;background-color: #004360;}/*修改头部布局的样式*/
.my-menu{160px;}
.my-grid tbody td{border: 0px;}/*去掉td宽度*/
</style>
</h:head>
<h:body>
<p:layout fullPage="true">
<p:layoutUnit position="north" size="70" styleClass="my-north">
<h:panelGrid columns="2" style="height: 30px;">
<h:column>
<h1 style="padding: 8px;">China软件项目管理</h1>
</h:column>
<h:column>
<div style="padding: 4px;">
JSF2.0卓越的JavaWEB框架
</div>
</h:column>
</h:panelGrid>
</p:layoutUnit>
<p:layoutUnit position="south" size="40" closable="true" collapsible="true">
<h:form id="bottomForm" style="padding: 4px;text-align:center;">
<p:spacer width="10"/>
<h:outputText value="开发设计:胡开明"/>
<p:spacer width="10"/>
<h:outputText value="日期:2013年3月28日"/>
<p:spacer width="10"/>
<p:growl id="bottomGrowl" showDetail="true" />
</h:form>
</p:layoutUnit>
<p:layoutUnit position="west" size="180" header="China软件项目主菜单" collapsible="true">
<p:menu styleClass="my-menu">
<p:submenu label="基本数据管理">
<p:menuitem value="中国行政区划" outcome="cn_address" />
<p:menuitem value="民族" url="#" />
<p:menuitem value="产品分类" url="#" />
<p:menuitem value="国民经济行业分类" url="#" />
</p:submenu>
<p:submenu label="通讯录管理">
<p:menuitem value="商务通讯录" url="#" />
</p:submenu>
<p:submenu label="资讯管理">
<p:menuitem value="RSS订阅" url="#" />
<p:menuitem value="返回首页" outcome="index" icon="ui-icon-home"/>
</p:submenu>
</p:menu>
</p:layoutUnit>
<p:layoutUnit position="center">
<ui:insert name="content">各项业务实现部分</ui:insert>
</p:layoutUnit>
</p:layout>
</h:body>
</html>
附件2:AddressBean.java
/*
* AddressBean.java
* 胡开明
* 2013-01-25
*
*/
package china;
import cn.jadepool.sql.Jade;
import cn.jadepool.sql.Record;
import cn.jadepool.util.China;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.primefaces.event.RowEditEvent;
/**
* 通用的地名管理
*
* @author hkm
*/
@ManagedBean
@SessionScoped
public class AddressBean implements java.io.Serializable {
private Map dimingMap = new LinkedHashMap();//地名记录
private Map dimingSelected = new LinkedHashMap();//被选择的地名记录
private List<Map> dimingList = new ArrayList();//地名列表
private ListMapDataModel dimingModel = null;//地名数据模型
private List<Map> dimingShengList = new ArrayList();//省地名列表
private List<Map> dimingShiList = new ArrayList();//市地名列表
private List<Map> dimingXianList = new ArrayList();//县地名列表
private China cn = new China();
private String codeSheng = "";
private String codeShi = "";
private String codeXian = "";
/**
* Creates a new instance of AddressBean
*/
public AddressBean() {
init();
}
public String getCodeSheng() {
return codeSheng;
}
public void setCodeSheng(String codeSheng) {
this.codeSheng = codeSheng;
}
public String getCodeXian() {
return codeXian;
}
public void setCodeXian(String codeXian) {
this.codeXian = codeXian;
}
/**
* 执行省级编码更改事件
*/
public void codeShengChange() {
if (!"".equals(codeSheng)) {
dimingShiList = cn.divisionCityInProvince(codeSheng);
Jade j = new Jade();
dimingList = j.query("select * from cn_address where addresscode like '" + codeSheng.substring(0, 2) + "__00'");
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
}
}
/**
* 执行市级编码更改事件
*/
public void codeShiChange() {
if (!"".equals(codeShi)) {
dimingXianList = cn.divisionCountyInCity(codeShi);
Jade j = new Jade();
dimingList = j.query("select * from cn_address where addresscode like '" + codeShi.substring(0, 4) + "__'");
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
}
}
public void codeXianChange() {
if (!"".equals(codeXian)) {
}
}
public String getCodeShi() {
return codeShi;
}
public void setCodeShi(String codeShi) {
this.codeShi = codeShi;
}
public List<Map> getDimingShengList() {
return dimingShengList;
}
public void setDimingShengList(List<Map> dimingShengList) {
this.dimingShengList = dimingShengList;
}
public List<Map> getDimingShiList() {
return dimingShiList;
}
public void setDimingShiList(List<Map> dimingShiList) {
this.dimingShiList = dimingShiList;
}
public List<Map> getDimingXianList() {
return dimingXianList;
}
public void setDimingXianList(List<Map> dimingXianList) {
this.dimingXianList = dimingXianList;
}
public Map getDimingMap() {
return dimingMap;
}
public void setDimingMap(Map dimingMap) {
this.dimingMap = dimingMap;
}
public Map getDimingSelected() {
return dimingSelected;
}
public void setDimingSelected(Map dimingSelected) {
this.dimingSelected = dimingSelected;
}
public List<Map> getDimingList() {
return dimingList;
}
public void setDimingList(List<Map> dimingList) {
this.dimingList = dimingList;
}
public ListMapDataModel getDimingModel() {
return dimingModel;
}
public void setDimingModel(ListMapDataModel dimingModel) {
this.dimingModel = dimingModel;
}
/**
* 导入中国大陆的行政区划
*
* @return null 导航到指定的页面,null值代表返回当前的页面
*/
public String reUpdateDiming() {
Jade j = new Jade();
List<Map> v = cn.division();
for (Map m : v) {
j.save("cn_address", m);//这是为了保护已经修改的成果
}
dimingList = j.query("select * from cn_address");
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("导入地名", "导入地名记录" + dimingList.size() + "条!"));
return null;
}
/**
* 查询所有的地名记录
*
* @return null 导航到指定的页面,null值代表返回当前的页面
*/
public String queryDiming() {
Jade j = new Jade();
dimingList = j.query("select * from cn_address");
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
return null;
}
/**
* 查询省的记录
*
* @return null 导航到指定的页面,null值代表返回当前的页面
*/
public String queryDimingSheng() {
Jade j = new Jade();
dimingList = j.query("select * from cn_address where addresscode like '__0000'");
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
return null;
}
/**
* 查询县的记录
*
* @return null 导航到指定的页面,null值代表返回当前的页面
*/
public String queryDimingXian() {
String sql = "select * from cn_address where addresscode like '__0000'";
if (!"".equals(this.codeShi)) {
sql = "select * from cn_address where addresscode like '" + codeShi.substring(0, 4) + "__'";
} else if (!"".equals(this.codeSheng)) {
sql = "select * from cn_address where addresscode like '" + codeSheng.substring(0, 2) + "__00'";
}
Jade j = new Jade();
dimingList = j.query(sql);
dimingModel = new ListMapDataModel(dimingList, "addresscode");
j.commit();
return null;
}
/**
* 初始化省的记录
*/
private void init() {
queryDimingSheng();
dimingShengList = cn.divisionProvince();
}
/**
* 执行编辑操作
*
* @param event 数据模型行编辑事件
*/
public void onEdit(RowEditEvent event) {
Map m = (Map) event.getObject();
Record r = new Record();
Map dm = r.one(this.dimingList, "addresscode", m.get("addresscode"));
Jade j = new Jade();
j.save("cn_address", dm);
Boolean isusing = (Boolean) dm.get("isusing");
String c = (String) dm.get("addresscode");
if (isusing) {
if (c.endsWith("0000")) {
j.update("update cn_address set isusing='1' where addresscode like '" + c.substring(0, 2) + "____'");
} else if (c.endsWith("00")) {
j.update("update cn_address set isusing='1' where addresscode like '" + c.substring(0, 2) + "0000'");
j.update("update cn_address set isusing='1' where addresscode like '" + c.substring(0, 4) + "__'");
} else {
j.update("update cn_address set isusing='1' where addresscode like '" + c.substring(0, 2) + "0000'");//更新省
j.update("update cn_address set isusing='1' where addresscode like '" + c.substring(0, 4) + "00'");//更新市
j.update("update cn_address set isusing='1' where addresscode like '" + c + "'");//更新县
}
} else {
if (c.endsWith("0000")) {
j.update("update cn_address set isusing='0' where addresscode like '" + c.substring(0, 2) + "____'");
} else if (c.endsWith("00")) {
j.update("update cn_address set isusing='0' where addresscode like '" + c.substring(0, 2) + "0000'");
j.update("update cn_address set isusing='0' where addresscode like '" + c.substring(0, 4) + "__'");
} else {
j.update("update cn_address set isusing='0' where addresscode like '" + c.substring(0, 2) + "0000'");
j.update("update cn_address set isusing='0' where addresscode like '" + c.substring(0, 4) + "00'");
j.update("update cn_address set isusing='0' where addresscode like '" + c + "'");
}
}
j.commit();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("成功", "修改记录成功!"));
}
/**
* 取消编辑操作
*
* @param event 数据模型行编辑事件
*/
public void onCancel(RowEditEvent event) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("已经取消修改操作!"));
}
}
附件3:cn_address.xhtml
<?xml version='1.0' encoding='GBK' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./IndexTemplate.xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html">
<ui:define name="content">
<h:form id="form">
<p:tabView id="tv" widgetVar="tv" dynamic="true">
<p:tab title="中国大陆行政区划管理">
<p:dataTable id="addressDataTable"
value="#{addressBean.dimingModel}"
var="m"
rowIndexVar="i"
paginator="true"
paginatorPosition="bottom"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,15,20,25,30,35,40,45,50,55,60"
selection="#{addressBean.dimingSelected}"
selectionMode="single"
editable="true"
>
<p:ajax event="rowEdit" listener="#{addressBean.onEdit}" update=":form:tv:addressDataTable :bottomForm:bottomGrowl" />
<p:ajax event="rowEditCancel" listener="#{addressBean.onCancel}" update=":form:tv:addressDataTable :bottomForm:bottomGrowl" />
<p:column headerText="序号" style="5%;text-align: center;"> #{i+1} </p:column>
<p:column headerText="编号" style="8%;text-align: center;" sortBy="#{m.addresscode}" >
#{m.addresscode}
</p:column>
<p:column headerText="标准名称" style="15%;" sortBy="#{m.addressname}" >
#{m.addressname}
</p:column>
<p:column headerText="中文标签" style="8%;" sortBy="#{m.labelcn}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{m.labelcn}" style="90%;"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{m.labelcn}" size="16"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="英文标签" style="8%;" sortBy="#{m.labelen}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{m.labelen}" style="90%;"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{m.labelen}" size="16"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="经度" style="8%;" sortBy="#{m.longitude}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{m.longitude}" style="90%;"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{m.longitude}" size="8"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="纬度" style="8%;" sortBy="#{m.latitude}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{m.latitude}" style="90%;"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{m.latitude}" size="8"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="是否使用" style="5%;">
<p:cellEditor>
<f:facet name="output">
<p:selectBooleanCheckbox value="#{m.isusing}" disabled="true"/>
</f:facet>
<f:facet name="input">
<p:selectBooleanCheckbox value="#{m.isusing}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column style="5%;text-align: center;">
<p:rowEditor/>
</p:column>
<f:facet name="footer">
<h:panelGrid style=" 500px;text-align: left;" columns="6" styleClass="my-grid">
<p:commandButton style="float: left;" value="全部" action="#{addressBean.queryDiming}" icon="ui-icon-search" update="@form"/>
<p:commandButton style="float: left;" value="省级" action="#{addressBean.queryDimingSheng}" icon="ui-icon-search" update="@form"/>
<p:selectOneMenu style="float: left;140px;" value="#{addressBean.codeSheng}">
<p:ajax update="@form" process="@this" listener="#{addressBean.codeShengChange}"/>
<f:selectItem itemValue="" itemLabel="--请选择省级--"/>
<c:forEach var="m" items="#{addressBean.dimingShengList}">
<f:selectItem itemValue="#{m.addresscode}" itemLabel="#{m.addressname}"/>
</c:forEach>
</p:selectOneMenu>
<p:selectOneMenu style="float: left;140px;" value="#{addressBean.codeShi}">
<p:ajax update="@form" process="@this" listener="#{addressBean.codeShiChange}"/>
<f:selectItem itemValue="" itemLabel="--请选择市级--"/>
<c:forEach var="m" items="#{addressBean.dimingShiList}">
<f:selectItem itemValue="#{m.addresscode}" itemLabel="#{m.addressname}"/>
</c:forEach>
</p:selectOneMenu>
<p:commandButton style="float: left;" value="查询" action="#{addressBean.queryDimingXian}" icon="ui-icon-disk" update="@form"/>
</h:panelGrid>
</f:facet>
</p:dataTable>
<div style="padding:2px;"><p:spacer height="2"/></div>
</p:tab>
<p:tab title="初始化行政区划记录">
<div style="padding: 40px;text-align: center;">
<p:commandButton style="float: left;" value="初始化地名" action="#{addressBean.reUpdateDiming}" icon="ui-icon-disk" update="@form :bottomForm:bottomGrowl"/>
</div>
</p:tab>
</p:tabView>
</h:form>
</ui:define>
</ui:composition>