一、輸入界面:input.jsp與控制器
<%@ page c language="java"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<HTML>
<HEAD>
<TITLE>添加新家長(cháng)</TITLE>
</HEAD>
<BODY>
<s:form action="add.action">
<s:textfield name="name" label="父親名字:"/>
<s:textfield name="gender" label="性別:"/>
<s:textfield name="sonName" label="兒子名:"/>
<s:textfield name="sonAge" label="兒子年齡:"/>
<s:submit value="提交"/>
</s:form>
</BODY>
</HTML>
struts 2配置文件:struts.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.i18n.encoding" value="GBK"/>
<constant name="struts.custom.i18n.resources" value="messageResource"/>
<package name="lee" extends="struts-default">
<action name="add" class="org.yeeku.action.AddPersonAndSon">
<result>welcome.html</result>
</action>
</package>
</struts>
Action類(lèi)(控制器):
package org.yeeku.action;
import com.opensymphony.xwork2.ActionSupport;
import javax.servlet.http.*;
import org.yeeku.service.*;
import org.yeeku.factory.*;
public class AddPersonAndSon extends ActionSupport
{
private String name;
private String gender;
private String sonName;
private int sonAge;
public String execute()throws Exception
{
String[] sonNames = {sonName};
int[] sonAges = {sonAge};
//通過(guò)業(yè)務(wù)邏輯工廠(chǎng)取得業(yè)務(wù)邏輯組件
PersonService ps = (PersonService)AppFactory.instance().getApp("personService"); //調用業(yè)務(wù)邏輯方法處理用戶(hù)請求
ps.createPersonAndSon(name , gender , sonNames , sonAges);
return SUCCESS;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void setGender(String gender)
{
this.gender = gender;
}
public String getGender()
{
return this.gender;
}
public void setSonName(String sonName)
{
this.sonName = sonName;
}
public String getSonName()
{
return this.sonName;
}
public void setSonAge(int sonAge)
{
this.sonAge = sonAge;
}
public int getSonAge()
{
return this.sonAge;
}
}
我們并不在Struts 2的Action中調用Hibernate API,Action也不直接依賴(lài)于任何業(yè)務(wù)邏輯組件,而只是依賴(lài)于業(yè)務(wù)邏輯工廠(chǎng)類(lèi),面向業(yè)務(wù)邏輯組件接口編程。這個(gè)過(guò)程是如何實(shí)現的請繼續往下看。運行圖:
所填數據將會(huì )保存到數據庫struts2hibernate中,這個(gè)數據庫請事先在MYSQL中創(chuàng )建。
從數據中可以看到剛提交的數據:
二、持久層設計
包括Hibernate持久化訪(fǎng)問(wèn)所需的PO和Hibernate映射文件。
父親實(shí)體類(lèi)代碼:
package org.yeeku.model;
import java.util.*;
public class Person{
private int id;
private String name;
private String gender;
private Set< Son> sons = new HashSet< Son>();
public Person() { }
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setSons(Set sons) {
this.sons = sons;
}
public int getId() {
return (this.id);
}
public String getName() {
return (this.name);
}
public String getGender() {
return (this.gender);
}
public Set< Son> getSons()
{
return this.sons;
}
}
對應的映射文件:Person.hbm.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.yeeku.model">
<!-- 每個(gè)class元素映射一個(gè)持久化類(lèi) -->
<class name="Person" table="person">
<id name="id">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="gender"/>
<set name="sons" inverse="true">
<key column="person_id"/>
<one-to-many class="Son"/>
</set>
</class>
</hibernate-mapping>
上面的Person實(shí)體存在一個(gè)一對多的關(guān)聯(lián)實(shí)體:Son,代碼如下:
package org.yeeku.model;
import java.io.Serializable;
public class Son implements Serializable
{
private int id;
private String sonName;
private int sonAge;
private Person parent;
public Son()
{
}
public Son(String sonName , int sonAge)
{
this.sonName = sonName;
this.sonAge = sonAge;
}
public void setSonName(String sonName) {
this.sonName = sonName;
}
public void setSonAge(int sonAge) {
this.sonAge = sonAge;
}
public void setId(int id)
{
this.id = id;
}
public void setParent(Person p)
{
this.parent = p;
}
public String getSonName() {
return (this.sonName);
}
public int getSonAge() {
return (this.sonAge);
}
public int getId()
{
return id;
}
public Person getParent()
{
return parent;
}
}
對應的映射文件:Son.hbm.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.yeeku.model">
<!-- 每個(gè)class元素映射一個(gè)持久化類(lèi) -->
<class name="Son" table="son">
<id name="id">
<generator class="identity"/>
</id>
<property name="sonName"/>
<property name="sonAge"/>
<many-to-one name="parent" column="person_id" not-null="true"/>
</class>
</hibernate-mapping>
最后是Hibernate配置文件:hibernate.cfg.xml,指定了數據庫連接信息和連接池等。
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/struts2hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<!-- C3P0 connection pool -->
<property name="hibernate.c3p0.max_size">500</property>
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">true</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping resource="Person.hbm.xml"/>
<mapping resource="Son.hbm.xml"/>
</session-factory>
</hibernate-configuration>
三、DAO層設計
由兩個(gè)DAO組件和一個(gè)DAO工廠(chǎng)組成,兩個(gè)DAO組件的代碼大致相同,這里以Person實(shí)體對應的DAO組件為例來(lái)介紹DAO組件
的實(shí)現。
1、Dao接口
package org.yeeku.dao.base;
public interface Dao
{
}
2、PersonDao接口
package org.yeeku.dao;
import org.hibernate.Session;
import org.yeeku.model.*;
import org.yeeku.dao.base.Dao;
import java.util.*;
public interface PersonDao extends Dao {
//包括四個(gè)CRUD操作
void save(Session sess , Person p);
void delete(Session sess , Person p);
void delete(Session sess , int id);
void update(Session sess , Person p);
}
3、Dao組件的實(shí)現類(lèi)PersonDaoImpl.java
package org.yeeku.dao.impl;
import org.hibernate.Session;
import org.yeeku.model.*;
import org.yeeku.dao.*;
import java.util.*;
public class PersonDaoImpl implements PersonDao
{
public void save(Session sess , Person p)
{
sess.save(p);
}
public void delete(Session sess , Person p)
{
sess.delete(p);
}
public void delete(Session sess , int id)
{
sess.delete(sess.get(Person.class , new Integer(id)));
}
public void update(Session sess , Person p)
{
sess.update(p);
}
}
4、DAO工廠(chǎng)
DAO工廠(chǎng)是一個(gè)簡(jiǎn)單的工廠(chǎng)類(lèi),該工廠(chǎng)類(lèi)使用XML文件管理DAO組件,采用XML配置文件管理DAO組件可以讓DAO工廠(chǎng)靈活
管理所有DAO組件,避免每次增加DAO組件時(shí)都要修改代碼。這種DAO組件配置文件的代碼結構如下:(daoContext.xml)
<?xml version="1.0" encoding="GBK"?>
<daoContext>
<dao id="sonDao" class="org.yeeku.dao.impl.SonDaoImpl"/>
<dao id="personDao" class="org.yeeku.dao.impl.PersonDaoImpl"/>
</daoContext>
可以看出在其中配置了兩個(gè)DAO組件,因為每個(gè)DAO組件在JAVA EE應用中僅需要一個(gè)實(shí)例就足夠了,因此DAO工廠(chǎng)類(lèi)提供一個(gè)
緩存池來(lái)緩存每一個(gè)DAO實(shí)例,并負責在應用啟動(dòng)時(shí)創(chuàng )建所有的DAO組件。代碼如下:
package org.yeeku.factory;
import org.yeeku.dao.base.Dao;
import org.yeeku.dao.*;
import org.yeeku.dao.impl.*;
import org.yeeku.consttool.*;
import org.dom4j.*;
import org.dom4j.io.*;
import java.util.*;
import java.io.*;
public class DaoFactory
{
private Map daoMap = new HashMap();
private static DaoFactory df;
private DaoFactory()throws Exception
{
Document doc = new SAXReader().read(new File(ConstantsUtil.realPath + "\\daoContext.xml"));
Element root = doc.getRootElement();
List el = root.elements();
for (Iterator it = el.iterator();it.hasNext() ; )
{
Element em = (Element)it.next();
String id = em.attributeValue("id");
String impl = em.attributeValue("class");
Class implClazz = Class.forName(impl);//通過(guò)反射,根據類(lèi)名創(chuàng )建DAO組件的實(shí)例
Dao d = (Dao)implClazz.newInstance();
daoMap.put(id , d); //將創(chuàng )建的組件放入緩存池中
}
}
public static DaoFactory instance()throws Exception
{
if (df == null)
{
df = new DaoFactory();
}
return df;
}
public Dao getDao(String id)
{
return daoMap.get(id);
}
}
系統每增加一個(gè)DAO組件時(shí),無(wú)需要修改任何代碼,僅僅需要在daoContext.xml文件中增加配置即可。
四、業(yè)務(wù)邏輯層設計
業(yè)務(wù)邏輯組件代碼無(wú)需與DAO實(shí)現類(lèi)耦合,業(yè)務(wù)邏輯組件的代碼面向DAO組件的接口編程,將業(yè)務(wù)邏輯組件和DAO組件的耦合
降低到接口層次,業(yè)務(wù)邏輯層組件設計與DAO層的設計思路大致相同,只是DAO組件實(shí)現的是數據庫訪(fǎng)問(wèn)功能,而業(yè)務(wù)邏輯
組件實(shí)現的是業(yè)務(wù)邏輯功能。
1、業(yè)務(wù)邏輯組件接口代碼
package org.yeeku.service;
import org.yeeku.exception.PersonException;
public interface PersonService {//增加父親和多個(gè)子女
void createPersonAndSon(String name , String gender , String[] sonName , int[] sonAge) throws PersonException;
}
2、業(yè)務(wù)邏輯組件的實(shí)現類(lèi)
package org.yeeku.service.impl;
import org.yeeku.service.*;
import org.yeeku.dao.*;
import org.yeeku.factory.*;
import org.yeeku.model.*;
import org.yeeku.tools.*;
import org.yeeku.exception.PersonException;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class PersonServiceImpl implements PersonService{
public void createPersonAndSon(String name , String gender , String[] sonName , int[] sonAge) throws PersonException {
try { //業(yè)務(wù)邏輯組件依賴(lài)于DAO工廠(chǎng),從工廠(chǎng)中取出兩個(gè)DAO組件
PersonDao pd = (PersonDao)DaoFactory.instance().getDao("personDao");
SonDao sd = (SonDao)DaoFactory.instance().getDao("sonDao");
//使用HibernateUtil打開(kāi)Hibernate Session。
Session s = HibernateUtil.currentSession();
Transaction tx = s.beginTransaction();
Person p = new Person();
p.setName(name);
p.setGender(gender);
pd.save(s , p);
for (int i = 0 ; i < sonName.length ; i++ ) {
Son son = new Son(sonName , sonAge);
son.setParent(p);
sd.save(s, son);
}
tx.commit();
HibernateUtil.closeSession();
}
catch (Exception e) {
e.printStackTrace();
throw new PersonException("業(yè)務(wù)異常");
}
}
}
本實(shí)例中的業(yè)務(wù)邏輯組件也采用XML配置文件進(jìn)行管理,業(yè)務(wù)邏輯組件工廠(chǎng)一樣根據XML配置文件來(lái)加載系統中的業(yè)務(wù)邏輯組件。
業(yè)務(wù)邏輯組件的配置文件如下:(appContext.xml)
<?xml version="1.0" encoding="GBK"?>
<appContext>
<app id="personService" class="org.yeeku.service.impl.PersonServiceImpl"/>
</appContext>
業(yè)務(wù)邏輯組件工廠(chǎng)根據該文件來(lái)初始化所有業(yè)務(wù)邏輯組件,并將業(yè)務(wù)邏輯組件放入緩存池中,讓控制器Action僅依賴(lài)于業(yè)務(wù)邏輯組件工廠(chǎng),與業(yè)務(wù)邏輯組件的耦合降低到接口層次。業(yè)務(wù)邏輯組件的工廠(chǎng)類(lèi)代碼如下:
package org.yeeku.factory;
import org.yeeku.dao.base.Dao;
import org.yeeku.dao.*;
import org.yeeku.dao.impl.*;
import org.yeeku.service.*;
import org.yeeku.service.impl.*;
import org.yeeku.consttool.*;
import org.dom4j.*;
import org.dom4j.io.*;
import java.util.*;
import java.io.*;
public class AppFactory
{
private Map appMap = new HashMap();
private static AppFactory df;
private AppFactory()throws Exception
{
Document doc = new SAXReader().read(new File(ConstantsUtil.realPath + "\\appContext.xml"));
Element root = doc.getRootElement();
List el = root.elements();
for (Iterator it = el.iterator();it.hasNext() ; )
{
Element em = (Element)it.next();
String id = em.attributeValue("id");
String impl = em.attributeValue("class");
Class implClazz = Class.forName(impl);//用反射根據類(lèi)名創(chuàng )建業(yè)務(wù)邏輯組件
Object d = implClazz.newInstance();
appMap.put(id , d); //將業(yè)務(wù)邏輯組件放入緩存池中
}
}
public static AppFactory instance()throws Exception
{
if (df == null)
{
df = new AppFactory();
}
return df;
}
public Object getApp(String id)//根據業(yè)務(wù)邏輯組件的ID獲取業(yè)務(wù)邏輯組件
{
return appMap.get(id);//直接從緩存池中取出業(yè)務(wù)邏輯組件
}
}
系統每增加一個(gè)業(yè)務(wù)組件時(shí),無(wú)需要修改任何代碼,僅僅需要在appContext.xml文件中增加配置。
聯(lián)系客服