原文及附件:
http://www.minioa.net/viewtopic.php?f=7&t=185&p=244#p244
0、需求设计
允许输入单位的基本信息,主要是单位名称和描述,业务非常简单,旨在讲解jsf、javabean、hibernate经典开发模式。
1、创建数据表core_org
每张表都包括6个系统字段,剩余的是业务字段。
ID_表示表的唯一标识,自动递增;CID_表示创建人的ID_;CDATE_表示记录创建日期;MID_表示最近一次修改人ID_;MDATE表示最近一次修改时间;UUID_表示记录的uuid,也算是一种唯一标识,主要用于这样的场景,比如编辑新闻时,新闻未提交就上传图片或附件,两者之前的关联依靠uuid。
orgName表示单位名称,orgDesc表示单位描述。
MySQL:
DROP TABLE IF EXISTS `minioa`.`core_org`;
CREATE TABLE `minioa`.`core_org` (
`ID_` int(10) unsigned NOT NULL auto_increment,
`CID_` int(10) unsigned default NULL,
`CDATE_` datetime default NULL,
`MID_` int(10) unsigned default NULL,
`MDATE_` datetime default NULL,
`UUID_` varchar(45) default NULL,
`orgName` varchar(100) default NULL,
`orgDesc` varchar(100) default NULL,
PRIMARY KEY (`ID_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、数据库映射文件core_org.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping auto-import="true" package="org.minioa.core">
<class name="Org" table="core_org">
<id name="ID_" column="ID_" type="java.lang.Integer">
<generator class="increment" />
</id>
<property name="CID_" column="CID_" type="java.lang.Integer" />
<property name="CDATE_" column="CDATE_" type="java.util.Date" />
<property name="MID_" column="MID_" type="java.lang.Integer" />
<property name="MDATE_" column="MDATE_" type="java.util.Date" />
<property name="UUID_" column="UUID_" type="java.lang.String" />
<property name="orgName" column="orgName" type="java.lang.String" />
<property name="orgDesc" column="orgDesc" type="java.lang.String" />
</class>
<!-- 选择全部记录 -->
<!-- Select all records -->
<sql-query name="core.org.records">
<![CDATA[
select ID_,CID_,CDATE_,MID_,MDATE_,UUID_,
orgName,orgDesc
from core_org
]]>
</sql-query>
<!-- 选择记录总数,便于分页 -->
<!-- Select records count, use for paging.-->
<sql-query name="core.org.records.count">
<![CDATA[
select count(*) as result from core_org
]]>
</sql-query>
<!-- 选择某一条记录 -->
<!-- Select one records by id.-->
<sql-query name="core.org.getrecordbyid">
<![CDATA[
select ID_,CID_,CDATE_,MID_,MDATE_,UUID_,
orgName,orgDesc
from core_org where ID_ = :id
]]>
</sql-query>
<!-- 更新某一条记录 -->
<!-- Update one records by id.-->
<sql-query name="core.org.updaterecordbyid">
<![CDATA[
update core_org set MID_ = :mId, MDATE_ = sysdate(),
orgName = :orgName, orgDesc = :orgDesc
where ID_ = :id
]]>
</sql-query>
<!-- 删除某一条记录 -->
<!-- Delete one records by id.-->
<sql-query name="core.org.deleterecordbyid">
<![CDATA[
delete from core_org where ID_ = :id
]]>
</sql-query>
</hibernate-mapping>
3、配置hibernate.cfg.xml
在<session-factory></session-factory>中加入<mapping resource="mysql/core_org.hbm.xml" />
4、创建Org.java
设置包
package org.minioa.core;
定义属性
private int ID_, CID_, MID_;
private String CDATE, MDATE;
private java.util.Date CDATE_, MDATE_;
private String UUID_, init;
定义setter和getter,JSF页面中使用时的属性必须具有setter和getter方法
public void setID_(int data) {
ID_ = data;
}
public int getID_() {
return ID_;
}
日期格式化
public static SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
orgName的校验规则
@NotEmpty(message = "单位名称必须填写")
@Length(min = 2, max = 12, message = "最少2个字符,最大12个字符")
private String orgName;
orgDesc的校验规则
@NotEmpty(message = "单位描述也必须填写")
private String orgDesc;
通过调用init来实现对页面的初始化,例如修改一个记录时
public String getInit() {
selectRecordById();
return init;
}
数据列表,为rich:dataTable提供数据源
private List<Org> recordsList;
public List<Org> getRecordsList() {
if (recordsList == null)
buildRecordsList();
return recordsList;
}
调用语言类,Lang的manage-bean-scope属性是application
public Lang lang;
public Lang getLang() {
if (lang == null)
lang = (Lang) FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().get("Lang");
return lang;
}
调用用户会话数据,MySession的manage-bean-scope属性是session
public MySession mySession;
public MySession getMySession() {
if (mySession == null)
mySession = (MySession) FacesContext.getCurrentInstance()
.getExternalContext().getSessionMap().get("MySession");
return mySession;
}
取得数据库连接会话
private Session session;
private Session getSession() {
if (session == null)
session = new HibernateEntityLoader().getSession();
if (!session.isOpen())
session = session.getSessionFactory().openSession();
return session;
}
类构造函数
public Org() {
}
类构造函数,用于创建recordsList
public Org(int id, int cId, String cDate, int mId, String mDate,String uuid, String name, String desc) {
setID_(id);
setCID_(cId);
setCDATE(cDate);
setMID_(mId);
setMDATE(mDate);
setUUID_(uuid);
setOrgName(name);
setOrgDesc(desc);
}
/**
* 将全部记录加入列表
*/
public void buildRecordsList() {
try {
getMySession();
recordsList = new ArrayList<Org>();
Query query = getSession().getNamedQuery("core.org.records");
Iterator it = query.list().iterator();
int id, cId, mId;
String cDate, mDate, uuid;
java.util.Date cDate_, mDate_;
String name, desc;
while (it.hasNext()) {
Object obj[] = (Object[]) it.next();
id = cId = mId = 0;
cDate = mDate = uuid = "";
cDate_ = mDate_ = null;
name = desc = "";
// 读取obj数据时,一定要确保obj不能为null
if (obj[0] != null)
id = Integer.valueOf(String.valueOf(obj[0]));
if (obj[1] != null)
cId = Integer.valueOf(String.valueOf(obj[1]));
if (obj[2] != null) {
java.sql.Timestamp t = (java.sql.Timestamp) obj[2];
cDate_ = new java.util.Date(t.getTime());
cDate = dtf.format(cDate_);
}
if (obj[3] != null)
mId = Integer.valueOf(String.valueOf(obj[3]));
if (obj[4] != null) {
java.sql.Timestamp t = (java.sql.Timestamp) obj[4];
mDate_ = new java.util.Date(t.getTime());
mDate = dtf.format(mDate_);
}
if (obj[5] != null)
uuid = String.valueOf(obj[5]);
if (obj[6] != null)
name = String.valueOf(obj[6]);
if (obj[7] != null)
desc = String.valueOf(obj[7]);
recordsList.add(new Org(id, cId, cDate, mId, mDate, uuid, name,desc));
}
it = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 读取一条记录
*/
public void selectRecordById() {
try {
Map params = FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap();
String id = (String) params.get("id");
Query query = getSession().getNamedQuery("core.org.getrecordbyid");
query.setParameter("id", id);
Iterator it = query.list().iterator();
while (it.hasNext()) {
this.mReset();
Object obj[] = (Object[]) it.next();
if (obj[0] != null)
ID_ = Integer.valueOf(String.valueOf(obj[0]));
if (obj[1] != null)
CID_ = Integer.valueOf(String.valueOf(obj[0]));
if (obj[2] != null) {
java.sql.Timestamp t = (java.sql.Timestamp) obj[2];
CDATE_ = new java.util.Date(t.getTime());
CDATE = dtf.format(CDATE_);
}
if (obj[3] != null)
MID_ = Integer.valueOf(String.valueOf(obj[0]));
if (obj[4] != null) {
java.sql.Timestamp t = (java.sql.Timestamp) obj[4];
MDATE_ = new java.util.Date(t.getTime());
MDATE = dtf.format(MDATE_);
}
if (obj[5] != null)
UUID_ = String.valueOf(obj[5]);
if (obj[6] != null)
orgName = String.valueOf(obj[6]);
if (obj[7] != null)
orgDesc = String.valueOf(obj[7]);
}
it = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
显示提示信息
getMySession().setMsg(getLang().getProp().getProperty( getMySession().getLanguage() + ".success").toString(), Integer.valueOf(1));
一定要使用try{}catch{},错误抛给前台有损程序员形象。
/**
* 新增一条记录,注意这里没有使用到insert语句,这是hibernate的特点
*/
public void mNewRecord() {
try {
Org bean = new Org();
bean.setOrgName(orgName);
bean.setOrgDesc(orgDesc);
bean.setCID_(0);
bean.setCDATE_(new java.util.Date());
getSession().save(bean);
bean = null;
…………
} catch (Exception ex) {
…………
}
}
取得页面传递过来的参数
Map params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String id = (String) params.get("id");
取得配置文件中名为core.org.updaterecordbyid的sql,
Query query = getSession().getNamedQuery("core.org.updaterecordbyid");
给参数赋值
query.setParameter("mId", 0);
/**
* 更新一条记录
*/
public void mUpdateRecord() {
try {
Map params = FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap();
String id = (String) params.get("id");
Query query = getSession().getNamedQuery("core.org.updaterecordbyid");
query.setParameter("mId", 0);
query.setParameter("orgName", orgName);
query.setParameter("orgDesc", orgDesc);
query.setParameter("id", id);
query.executeUpdate();
query = null;
…………
} catch (Exception ex) {
…………
}
}
/**
* 删除一条记录
*/
public void mDeleteRecordById() {
try {
Map params = FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap();
String id = (String) params.get("id");
Query query = getSession().getNamedQuery(
"core.org.deleterecordbyid");
query.setParameter("id", id);
query.executeUpdate();
query = null;
…………
} catch (Exception ex) {
…………
}
}
5、配置faces-config.xml
<managed-bean>
<managed-bean-name>Org</managed-bean-name>
<managed-bean-class>org.minioa.core.Org</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
managed-bean-nam设置别名,可以和类名不一样
managed-bean-scope还可以设置成application和session
6、创建org.xhtml页面
设置标签库
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
设置模板页
<ui:composition template="main.xhtml"></ui:composition>
设置网页title
<ui:define name="title">#{Lang.prop['zh-cn.org']}</ui:define>
设置网页body
<ui:define name="body"></ui:define>
设置tab选项卡
<rich:tabPanel id="tab" switchType="client" headerAlignment="left">
<rich:tab id="tab1" name="tab1" label="#{Lang.prop['zh-cn.list']}">
</rich:tab>
</rich:tabPanel>
构造a4j:form,如果form内未使用a4j标记,可以使用h:form
<a4j:form id="dataForm" style="margin-top:3px;">
数据表,其中value设置数据源,var设置数据源的别名,rowKeyVar设置行号变量
<rich:dataTable id="dataTable" rows="10" value="#{Org.recordsList}" var="item" style="width:100%;" rowKeyVar="rowNum">
<f:facet name="header">
<rich:columnGroup>
<rich:column>
……
</rich:column>
</rich:columnGroup>
</f:facet>
<rich:column style="text-align:center;width:21px;">
<h:outputText value="#{rowNum + 1}" />
</rich:column>
</rich:dataTable>
修改按钮,单击时传递记录id,刷新editForm,也就是对记录的初始化,代码RichFaces.switchTab('tab','tab2','tab2')表示选择修改选项卡
<a4j:commandLink reRender="editForm">
<h:graphicImage id="edit"
οnclick="RichFaces.switchTab('tab','tab2','tab2');"
title="#{Lang.prop['zh-cn.edit']}"
style="border:0px;width:18px;" url="images/edit.png">
</h:graphicImage>
<f:param name="id" value="#{item.ID_}" />
<f:param name="reload" value="false" />
</a4j:commandLink>
删除按钮,删除前要让用户确认一下
<a4j:commandLink reRender="msg"
action="#{Org.mDeleteRecordById}"
οnclick="if(!confirm('#{Lang.prop['zh-cn.deletewarning']}')) return false;document.getElementById('dataForm:dataTable:#{rowNum}:del').style.display = 'none';document.getElementById('dataForm:dataTable:#{rowNum}:edit').style.display = 'none'">
<h:graphicImage id="del" title="#{Lang.prop['zh-cn.delete']}"
style="border:0px;width:16px;margin-right:6px;"
url="images/delete.png">
</h:graphicImage>
<f:param name="id" value="#{item.ID_}" />
<f:param name="reload" value="false" />
</a4j:commandLink>
修改表单,要初始化表单。h:panelGrid用于布局,rich:message用于显示校验信息。
<a4j:outputPanel id="editForm">
#{Org.init}
<a4j:form>
<h:panelGrid columns="3" columnClasses="co1,co2,co3">
<h:outputText value="#{Lang.prop['zh-cn.name']}:" />
<h:inputText value="#{Org.orgName}" id="orgName" style="border:1px solid #E2E2E2;width:100px;font-size:9pt;">
<rich:ajaxValidator event="onblur" />
</h:inputText>
<rich:message for="orgName" />
……
</h:panelGrid>
</a4j:form>
</a4j:outputPanel>
补充说明:
xhtml中尽量使用jsf和richfaces标记,不要直接使用html标记,尤其是reRender所指向的区域,不要使用html标记。
编译类文件时需要将编译的.class文件复制到WEB-INF\classesx下,
而我们使用Eclipse或MyEclipse部属项目时,倾向于将项目编译输出路径设置成WEB-INF\classesx,由于类文件自动编译时,有时会导致classes文件会按照src中的重写,出现hibernate.cfg.xml丢失的情况,所以,我建议将hibernate.cfg.xml等文件放置在src中,然后在这里编辑。
7、将org.jsf加入菜单