原文:
http://www.ruanxun.com/HArticle86951.aspx本文将以一个实际例子来讲解整合iBATIS和Spring在WEB开发中的应用。在例子中,将应用DAO,FACADE这些常用的设计模式。
1、需求说明
    假定我们要实现一个用户注册和登录的需求。注册时将用户信息保存到数据库,登录时使用注册的信息进行校验。
2、数据库设计
    我们建2个表,一个存放基本的用户信息(T_USERS),一个放附加的信息(T_USER_INFO)。这2个表是1对1的关系,其实可以只建一个表,但在实际的开发中,我们常常会把它们拆分,把常用的信息放到主表中,不常用的放到辅表中,这样可以提升性能。本文使用的数据库是ORACLE,表结构如下:
| T_USERS 用户信息主表 |  
| 字段名 | 
字段说明 | 
字段类型 |  
| userid | 
用户在系统中的流水号,为PRIMARY KEY | 
NUMBER(6,0) NOT NULL |  
| ualias | 
用户别名,在登录时输入的名字 | 
VARCHAR2(20) NOT NULL |  
| password | 
密码 | 
VARCHAR2(30) NULL |  
| realname | 
真实姓名 | 
VARCHAR2(20) NULL |  
| email | 
email | 
VARCHAR2(30) NOT NULL |  
| usertypeid | 
用户类型 | 
CHAR(2) NOT NULL |  
| SQL |  
CREATE TABLE T_USERS (   userid NUMBER(6,0) NOT NULL,   usertypeid CHAR(2) NOT NULL,   ualias VARCHAR2(20) NOT NULL,   password VARCHAR2(30) NULL,   email VARCHAR2(30) NOT NULL,   realname VARCHAR2(20) NULL ); CREATE UNIQUE INDEX XAK1T_USERS ON T_USERS (  ualias ASC ); CREATE UNIQUE INDEX XAK2T_USERS ON T_USERS ( email ASC ); ALTER TABLE T_USERS ADD ( PRIMARY KEY (userid) ) ;
 
  |    | 
| T_USER_INFO 用户信息辅表 |  
| 字段名 | 
字段说明 | 
字段类型 |  
| userid | 
用户在系统中的流水号为KEY | 
NUMBER(6,0) NOT NULL |  
| regdate | 
注册日期 | 
DATE NULL |  
| lastlogdate | 
最近一次登录日期 | 
DATE NULL |  
| logtimes | 
登录次数 | 
NUMBER(6) NULL |  
| SQL |  
CREATE TABLE T_USER_INFO (     userid NUMBER(6,0) NOT NULL,     regdate DATE NULL,     lastlogdate DATE NULL,     logtimes NUMBER(6) NULL ); ALTER TABLE T_USER_INFO ADD ( PRIMARY KEY (userid) ) ; ALTER TABLE T_USER_INFO ADD ( FOREIGN KEY (userid) REFERENCES T_USERS ) ;
 
 
 
  |    | 
| SEQUENCE Sequence_userid 用户流水号产生 |  
| SQL |  
CREATE SEQUENCE Sequence_userid  INCREMENT BY 1  START WITH 1  MAXVALUE 999999 MINVALUE 1 NOCYCLE NOORDER ;
 
 
  |    | 
 
3、构建源代码包目录
  com(1)
    |-wysm(2)
      |-netstar(3)
        |-domain(4) (POJO) 
        |-persistence(4) (持久化层) 
          |-iface(5) (DAO 接口) 
          |-sqlmapdao(5) (iBATIS DAO实现) 
            |-sql(6) (iBATIS sqlmap定义文件) 
        |-service(4) (FACADE接口) 
          |-ibatis(5) (FACADE iBATIS实现) 
       |-test(4)(JAVA环境测试)
4、iBATIS sqlmap定义
| com.wysm.netstar.persistence.sqlmapdao.sql/sql-map-config.xml |  
<?xml version="1.0" encoding="UTF-8" ?>  <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"      "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">  <sqlMapConfig>    <properties resource="com/wysm/netstar/properties/database.properties"/>    <transactionManager type="JDBC">      <dataSource type="SIMPLE">        <property value="${driver}" name="JDBC.Driver"/>        <property value="${url}" name="JDBC.ConnectionURL"/>        <property value="${username}" name="JDBC.Username"/>        <property value="${password}" name="JDBC.Password"/>      </dataSource>    </transactionManager>    <sqlMap resource="com/wysm/netstar/persistence/sqlmapdao/sql/User.xml"/>    <sqlMap resource="com/wysm/netstar/persistence/sqlmapdao/sql/Sequence.xml"/>    <sqlMap resource="com/wysm/netstar/persistence/sqlmapdao/sql/UserInfo.xml"/>  </sqlMapConfig>  
  |    | 
| 数据库连接属性文件 com.wysm.netstar.properties.database.properties |  
#################################### # Database Connectivity Properties #################################### driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:ORA92SER username=netstar password=netstar    
  |    | 
| com.wysm.netstar.persistence.sqlmapdao.sql/Sequence.xml |  
<?xml version="1.0" encoding="UTF-8" ?>  <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      "http://ibatis.apache.org/dtd/sql-map-2.dtd">  <sqlMap namespace="Sequence">    <select id="getSequenceUserId" resultClass="int">      select sequence_userid.nextval from dual    </select>  </sqlMap>  
  |    | 
| com.wysm.netstar.persistence.sqlmapdao.sql/User.xml |  
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="User"> <typeAlias alias="user" type="com.wysm.netstar.domain.User"/> <select id="getUserByUserAlias" resultClass="user" parameterClass="string">   SELECT     USERID as userId,     UALIAS as userAlias,     PASSWORD as password,     REALNAME as realName,     EMAIL as email,     USERTYPEID as userTypeId   FROM T_USERS   WHERE UALIAS = #userAlias# </select> <select id="getUserByUserAliasAndPassword" resultClass="user" parameterClass="user">   SELECT     USERID as userId,     UALIAS as userAlias,     PASSWORD as password,     REALNAME as realName,     EMAIL as email,     USERTYPEID as userTypeId   FROM T_USERS   WHERE UALIAS = #userAlias# AND     PASSWORD = #password# </select> <select id="getUserByEmail" resultClass="user" parameterClass="string">   SELECT     USERID as userId,     UALIAS as userAlias,     PASSWORD as password,     REALNAME as realName,     EMAIL as email,     USERTYPEID as userTypeId   FROM T_USERS   WHERE EMAIL=#email# </select> <update id="updateUser" parameterClass="user">   UPDATE T_USERS SET     UALIAS= #userAlias#,     PASSWORD=#password#,     REALNAME=#realName#,     EMAIL = #email#,     USERTYPEID = #userTypeId#   WHERE USERID = #userId# </update> <insert id="insertUser" parameterClass="user">   INSERT INTO T_USERS     (USERID,       UALIAS,       PASSWORD,       REALNAME,       EMAIL,       USERTYPEID)     VALUES       (#userId#, #userAlias#,#password#,#realName#, #email#, #userTypeId#) </insert> <delete id="deleteUser" parameterClass="int"> DELETE FROM T_USERS   WHERE USERID=#userId# </delete> <select id="existUserId" parameterClass="int"> select count(*) FROM T_USERS   WHERE USERID=#userId# </select> </sqlMap>
  |    | 
| com.wysm.netstar.persistence.sqlmapdao.sql/UserInfo.xml |  
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="User"> <typeAlias alias="userInfo" type="com.wysm.netstar.domain.UserInfo"/> <select id="getUserInfoByUserId" resultClass="userInfo" parameterClass="int">   SELECT     USERID,     REGDATE,     LASTLOGDATE,     LOGTIMES     FROM T_USER_INFO   WHERE USERID = #userId# </select> <update id="updateUserInfo" parameterClass="userInfo">   UPDATE T_USER_INFO SET     REGDATE= #regDate#,     LASTLOGDATE=#lastLogDate#,     LOGTIMES=#logTimes#   WHERE USERID = #userId# </update> <insert id="insertUserInfo" parameterClass="userInfo">   INSERT INTO T_USER_INFO     (USERID,     REGDATE,     LASTLOGDATE,     LOGTIMES)   VALUES     (#userId#, #regDate#,#lastLogDate#,#logTimes#) </insert> <delete id="deleteUserInfo" parameterClass="int">   DELETE FROM T_USER_INFO     WHERE USERID=#userId# </delete> </sqlMap>
 
  |    | 
 
5、POJO定义 
| com.wysm.netstar.domain.User.java |  
package com.wysm.netstar.domain; 
  import java.io.*; 
  public class User implements Serializable {      private Integer userId;      private String userAlias;      private String password;      private String realName;      private String email;      private String userTypeId;      public User() {      } 
      public User(Integer userId) {          this.userId=userId;      } 
      public User(String userAlias) {          this.userAlias=userAlias;      } 
      public User(String userAlias,String password) {          this.userAlias=userAlias;          this.password=password;      } 
      public void setUserId(Integer userId) {          this.userId = userId;      } 
      public void setUserAlias(String userAlias) {          this.userAlias = userAlias;      } 
      public void setPassword(String password) {          this.password = password;      } 
      public void setUserTypeId(String userTypeId) { 
          this.userTypeId = userTypeId;      } 
      public void setRealName(String realName) {          this.realName = realName;      } 
      public void setEmail(String email) {          this.email = email;      } 
      public Integer getUserId() {          return userId;      } 
      public String getUserAlias() {          return userAlias;      } 
      public String getPassword() {          return password;      } 
      public String getUserTypeId() { 
          return userTypeId;      } 
      public String getRealName() {          return realName;      } 
      public String getEmail() {          return email;      }  }  
 
 
  |    | 
| com.wysm.netstar.domain.UserInfo.java |  
package com.wysm.netstar.domain;  import java.util.*;  import java.io.Serializable;  public class UserInfo implements Serializable {      private Integer userId;      private Date regDate;      private Date lastLogDate;      private Integer logTimes;      public UserInfo() {      }      public void setUserId(Integer userId) {          this.userId = userId;      }      public void setRegDate(Date regDate) {          this.regDate = regDate;      }      public void setLastLogDate(Date lastLogDate) {          this.lastLogDate = lastLogDate;      }      public void setLogTimes(Integer logTimes) {          this.logTimes = logTimes;      }      public Integer getUserId() {          return userId;      }      public Date getRegDate() {          return regDate;      }      public Date getLastLogDate() {          return lastLogDate;      }      public Integer getLogTimes() {          return logTimes;      }  }
 
 
  |    | 
 
6、DAO接口定义
| com.wysm.netstar.persistence.iface.BaseDao.java |  
package com.wysm.netstar.persistence.iface; public interface BaseDao { }  
 
 
  |    | 
| com.wysm.netstar.persistence.iface.SequenceDao.java |  
package com.wysm.netstar.persistence.iface; public interface SequenceDao extends BaseDao {     Integer getSequenceUserId(); }
 
 
 
  |    | 
| com.wysm.netstar.persistence.iface.UserDao.java |  
package com.wysm.netstar.persistence.iface; 
  import com.wysm.netstar.domain.User;  import java.util.List; 
  public interface UserDao extends BaseDao  {      public abstract List getUser(String userAlias);      public abstract List getUserByEmail(String email);      public abstract List getUser(String userAlias,String password);      public abstract void insertUser(User user);      public abstract void updateUser(User user);      public abstract boolean existUserId(Integer userid);  }
 
 
  |    | 
| com.wysm.netstar.persistence.iface.UserInfoDao.java |  
package com.wysm.netstar.persistence.iface; 
  import com.wysm.netstar.domain.UserInfo; 
  public interface UserInfoDao extends BaseDao  {      public abstract UserInfo getUserInfo(Integer userId);      public abstract void insertUserInfo(UserInfo userInfo);      public abstract void updateUserInfo(UserInfo userInfo);  }  
 
 
  |    | 
 
7、DAO iBATIS实现
| com.wysm.netstar.persistence.sqlmapdao.BaseSqlMapDao.java |  
package com.wysm.netstar.persistence.sqlmapdao;  import com.ibatis.dao.client.DaoManager;  import com.ibatis.dao.client.template.SqlMapDaoTemplate;  public class BaseSqlMapDao extends SqlMapDaoTemplate {    protected static final int PAGE_SIZE = 4;    public BaseSqlMapDao(DaoManager daoManager) {      super(daoManager);    }  }  
 
 
  |    | 
| com.wysm.netstar.persistence.sqlmapdao.SequenceSqlMapDao.java |  
package com.wysm.netstar.persistence.sqlmapdao;  import com.ibatis.dao.client.DaoManager;  import com.wysm.netstar.persistence.iface.SequenceDao;  public class SequenceSqlMapDao extends BaseSqlMapDao implements SequenceDao {    public SequenceSqlMapDao(DaoManager daoManager) {      super(daoManager);    }    public Integer getSequenceUserId(){        return (Integer)queryForObject("getSequenceUserId",new Object());    }  }    
 
 
  |    | 
| com.wysm.netstar.persistence.sqlmapdao.UserSqlMapDao.java |  
package com.wysm.netstar.persistence.sqlmapdao;  import com.ibatis.dao.client.DaoManager;  import com.wysm.netstar.domain.User;  import com.wysm.netstar.persistence.iface.UserDao;  import java.util.List;  import org.apache.log4j.Logger;  public class UserSqlMapDao extends BaseSqlMapDao implements UserDao {      static Logger logger=Logger.getLogger(UserSqlMapDao.class);    public UserSqlMapDao(DaoManager daoManager) {      super(daoManager);      logger.debug("In UserSqlMapDao daoManager null="+(daoManager==null));    }    public List getUser(String userAlias){        return queryForList("getUserByUserAlias",userAlias);    }    public List getUser(String userAlias,String password){        User user=new User(userAlias,password);        return queryForList("getUserByUserAliasAndPassword",user);    }    public void insertUser(User user){        update("insertUser", user);    }    public void updateUser(User user){        update("updateUser", user);    }    public List getUserByEmail(String email){        return queryForList("getUserByEmail",email);    }    public boolean existUserId(Integer userid){        Integer cnt=(Integer)this.queryForObject("existUserId",userid);        return  cnt.intValue()>0;    }  }     
 
 
  |    | 
| com.wysm.netstar.persistence.sqlmapdao.UserInfoSqlMapDao.java |  
package com.wysm.netstar.persistence.sqlmapdao;  import com.ibatis.dao.client.DaoManager;  import com.wysm.netstar.persistence.iface.UserInfoDao;  import com.wysm.netstar.domain.UserInfo;  public class UserInfoSqlMapDao extends BaseSqlMapDao implements UserInfoDao {    public UserInfoSqlMapDao(DaoManager daoManager) {      super(daoManager);    }    public UserInfo getUserInfo(Integer userId){        return (UserInfo)queryForObject("getUserInfoByUserId",userId);    }    public void insertUserInfo(UserInfo userInfo){        update("insertUserInfo", userInfo);    }    public void updateUserInfo(UserInfo userInfo){        update("insertUserInfo", userInfo);    }  }   
 
 
  |    | 
 
8、Facade接口定义
| com.wysm.netstar.persistence.sqlmapdao.UserInfoSqlMapDao.java |  
package com.wysm.netstar.service; import com.wysm.netstar.domain.User; public interface UserService {     public void addNewUser(User user);//增加新用户     public boolean existUserAlias(String userAlias);//检查用户别名是否已经存在     public User existUser(String userAlias,String password);//用户密码验证     public boolean existEmail(String email);//检查EMAIL是否已经存在     public boolean existUserId(Integer userId);//用户流水号验证 }
   
 
 
  |    | 
 
9、FACADE实现
| com.wysm.netstar.service.ibatis.UserServiceImpl.java |  
package com.wysm.netstar.service.ibatis;  import java.util.*;  import org.apache.log4j.*;  import com.ibatis.dao.client.*;  import com.wysm.netstar.domain.*;  import com.wysm.netstar.persistence.iface.*;  import com.wysm.netstar.service.*;  public class UserServiceImpl implements UserService {      private UserDao userDao;      private SequenceDao sequenceDao;      private UserInfoDao userInfoDao;      private DaoManager daoMgr;      static Logger logger=Logger.getLogger(UserServiceImpl.class);      public UserServiceImpl() {  //        daoMgr = DaoConfig.getDaoManager();  //        this.userDao=(UserDao)daoMgr.getDao(UserDao.class);      }      private void initDaos(){          if (userDao==null){              this.userDao=(UserDao)daoMgr.getDao(UserDao.class);              this.sequenceDao=(SequenceDao)daoMgr.getDao(SequenceDao.class);              this.userInfoDao=(UserInfoDao)daoMgr.getDao(UserInfoDao.class);          }      }      public void addNewUser(User user){          Integer id=sequenceDao.getSequenceUserId();          user.setUserId(id);          UserInfo userInfo=new UserInfo();          userInfo.setUserId(id);          userInfo.setLastLogDate(null);          userInfo.setLogTimes(new Integer(0));          userInfo.setRegDate(new Date());          try{              daoMgr.startTransaction();              userDao.insertUser(user);              userInfoDao.insertUserInfo(userInfo);              daoMgr.commitTransaction();          }catch(Exception ex){              ex.printStackTrace();          }finally{              daoMgr.endTransaction();          }      }      public boolean existUserAlias(String userAlias){          List users=userDao.getUser(userAlias);          if (users!=null&&users.size()>0)              return true;          return false;      }      public User existUser(String userAlias,String password){          List users=userDao.getUser(userAlias,password);          if (users!=null&&users.size()>0)              return (User)users.get(0);          return null;      }      public boolean existEmail(String email){          List users=userDao.getUserByEmail(email);          if (users!=null&&users.size()>0)              return true;          return false;      }      public void setDaoMgr(DaoManager daoMgr) {          this.daoMgr = daoMgr;      } 
      public void setSequenceDao(SequenceDao sequenceDao) {         this.sequenceDao = sequenceDao;     }     public void setUserDao(UserDao userDao) {         this.userDao = userDao;     }     public void setUserInfoDao(UserInfoDao userInfoDao) {         this.userInfoDao = userInfoDao;     }     public boolean existUserId(Integer userId){          if (userId.intValue()==0)              return false;          return userDao.existUserId(userId);      }  }
  |    | 
 
10、iBATIS DAO支持定义 
| com.wysm.netstar.persistence/dao.xml |  
<?xml version="1.0" encoding="UTF-8"?> 
  <!DOCTYPE daoConfig      PUBLIC "-//ibatis.apache.org//DTD DAO Configuration 2.0//EN"      "http://ibatis.apache.org/dtd/dao-2.dtd"> 
  <daoConfig> 
    <context> 
      <transactionManager type="SQLMAP">        <property name="SqlMapConfigResource"          value="com/wysm/netstar/persistence/sqlmapdao/sql/sql-map-config.xml"/>      </transactionManager> 
      <dao interface="com.wysm.netstar.persistence.iface.UserDao"        implementation="com.wysm.netstar.persistence.sqlmapdao.UserSqlMapDao"/> 
      <dao interface="com.wysm.netstar.persistence.iface.SequenceDao"        implementation="com.wysm.netstar.persistence.sqlmapdao.SequenceSqlMapDao"/> 
      <dao interface="com.wysm.netstar.persistence.iface.UserInfoDao"        implementation="com.wysm.netstar.persistence.sqlmapdao.UserInfoSqlMapDao"/> 
    </context> 
  </daoConfig>  
  |    | 
| com.wysm.netstar.persistence.DaoConfig.java |  
package com.wysm.netstar.persistence;  import com.ibatis.common.resources.Resources;  import com.ibatis.dao.client.DaoManager;  import com.ibatis.dao.client.DaoManagerBuilder;  import java.io.Reader;  import java.util.Properties;  import org.apache.log4j.Logger;  public class DaoConfig {    private static final String resource = "com/wysm/netstar/persistence/dao.xml";    private static final DaoManager daoManager;    static Logger logger=Logger.getLogger(DaoConfig.class);    static {      try {        daoManager = newDaoManager(null);      } catch (Exception e) {        throw new RuntimeException("Description.  Cause: " + e, e);      }    }    public static DaoManager getDaoManager() {      return daoManager;    }    public static DaoManager newDaoManager(Properties props) {      try {        Reader reader = Resources.getResourceAsReader(resource);        return DaoManagerBuilder.buildDaoManager(reader, props);      } catch (Exception e) {        throw new RuntimeException("Could not initialize DaoConfig.  Cause: " + e, e);      }    }  }  
  |    | 
 
11、Spring Bean定义文件
| applicationContext.xml这个文件应该放在WEB包的 WEB-INF/下 |  
<?xml version="1.0" encoding="UTF-8"?>  <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 
  <beans>  <bean id="daoManager" class="com.wysm.netstar.persistence.DaoConfig" factory-method = "getDaoManager"/>
       <bean id="sequenceDao" class="com.wysm.netstar.persistence.iface.SequenceDao" factory-bean = "daoManager" factory-method="getDao">          <constructor-arg>              <value>com.wysm.netstar.persistence.iface.SequenceDao</value>          </constructor-arg>  </bean>
      <bean id="userDao" class="com.wysm.netstar.persistence.iface.UserDao" factory-bean = "daoManager" factory-method="getDao">          <constructor-arg>              <value>com.wysm.netstar.persistence.iface.UserDao</value>          </constructor-arg>      </bean> 
      <bean id="userInfoDao" class="com.wysm.netstar.persistence.iface.UserInfoDao" factory-bean = "daoManager" factory-method="getDao">          <constructor-arg>              <value>com.wysm.netstar.persistence.iface.UserInfoDao</value>          </constructor-arg>      </bean> 
     <bean name="userService" class="com.wysm.netstar.service.ibatis.UserServiceImpl" singleton="false">          <property name="daoMgr">              <ref bean="daoManager"/>          </property>          <property name="sequenceDao">              <ref bean="sequenceDao"/>          </property>          <property name="userDao">              <ref bean="userDao"/>          </property>          <property name="userInfoDao">              <ref bean="userInfoDao"/>          </property>      </bean> 
      <bean name="userService" class="com.wysm.netstar.service.ibatis.UserServiceImpl" singleton="false">          <property name="daoMgr">              <ref bean="daoManager"/>          </property>          <property name="sequenceDao">              <ref bean="sequenceDao"/>          </property>          <property name="userDao">              <ref bean="userDao"/>          </property>          <property name="useInfoDao">              <ref bean="useInfoDao"/>          </property>      </bean> 
  </beans>    
  |    | 
 
12、在JAVA环境下测试以上内容
| com.wysm.netstar.test.SpringTestCase.java |  
package com.wysm.netstar.test;  import junit.framework.TestCase;  import org.springframework.context.ApplicationContext;  import org.springframework.context.support.FileSystemXmlApplicationContext;  import com.wysm.netstar.actions.CatalogAction;  import com.wysm.netstar.service.UserService;  import com.wysm.netstar.domain.Catalog;  import java.util.List;  public class SpringTestCase extends TestCase {      private UserService userService;      private Catalog catalog;      protected void setUp() throws Exception {          super.setUp();          ApplicationContext ctx=new FileSystemXmlApplicationContext( "D:/JBProject/NetStarv0.1/netstar/WEB-INF/applicationContext.xml");          userService =(UserService)ctx.getBean("UserService");      }      protected void tearDown() throws Exception {          super.tearDown();      }      public void testSave(){          //自己写测试代码      }  }  
  |    |