这里使用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>