| 
         
     
     | 
     | 
    
  
    | 
    从Jpetstore 开始IBATIS之旅 | 
   
  
     | 
   
  
     | 
   
  
    | 
     作者:未知  来源:月光软件站  加入时间:2005-5-13 月光软件站  | 
   
  
    |       
 
前一阵在研究O/R MAPPING,觉得HIBERNATE和IBATIS都是好东西,但IBATIS更容易上手,而且跟数据库打交道的时候只需把SQL 语句配置在XML里即可,不象HIBERNAMTE要写复合其规范的HQL。当然现在HIBERNATE大行其道肯定是有道理的,我过一阵子也打算好好学习一下。
 
       技术发展的太快,学习方法是很重要的。(看来开源确实促进了生产力的发展啊,由此推断,共产主义社会肯定会实现的啦。)我认为必须摒弃抱本书按部就班的学习方法,而应该是STUDY  IN ACTION,在实践中学习,缺啥补啥,大不了不断重构好了。当然前提是有一定的技术积累了。
     为了学习IBATIS,除了大致看了一下IBATIS的官方文档,我把主要精力放在研究作者的范例JPETSTORE上了,大家可以道WWW.IBATIS.COM去下载4.0版本的例子,3.X的不要下了,代码写的没有4.0的优美。
    然后再去下载MYSQL,TOMCAT,安装调试让JETSTORE跑起来。这个过程我就不讲了,大家动动脑筋找点成就感吧。
工欲善其事,必先利其器。我用的是JBUILDER9,因为我以前用DELPHI的对BORLAND的产品有感情啊(当然BORLAND不会对我有感情,因为。。。。。。^_^,中国特色)。
建一个新项目,保存后关掉PROJECT,然后把JPETSTORE的代码包拷贝到:project\src\下,再打开刚才的项目,顺利的话你就能看到项目下的一堆包啦。现在编译肯定是有问题的,别急别急,在项目里加载上JPETSTORE源码LIB目录下的所有.JAR和SERVLET.JAR,为了连MYSQL,你还得加载MYSQL的JDBC驱动。具体做法,你可以在JBUILDER9 Tools\config libraries 新建三个LIB,比如IBATISLIB里放上JPETSTORE源码LIB目录下的所有.JAR,servlet就不要建了,JB9里带了,再建一个MYSQLLIB放上MYSQL的JDBC驱动的.jar,然后修改JPETSTORE源码SRC\PROPERTIES\database.properties的内容,例如,我的是
driver=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost/jpetstore
username=jpetstore
password=ibatis9977
现在MAKE  PROJECT应该可以通过了。好啦,打开com.ibatis.jpetstore底下的所有.java文件吧。
Domain目录下放的是JAVABEAN,一般是跟表相对应的。
Persistence目录下放的是DAO接口和具体实现类,DAO即数据访问对象(DATA ACCESS OBJECT),是用来跟数据库打交道的。IBATIS的O/R MAPPING的使用方法也就在这个目录里面。
Presentation目录下放的是FORMBEAN,后面还要说到JPETSTORE范例对STRUTS的创造性使用。
Service目录下放的是SERVICE类,通过SERVICE对象调用DAO对象的方法来访问数据库的,这是一种常用的设计模式。
      常见的STRUTS编程应该是一个动作对应一个ACTION,例如写一个交友网站,用户登录和用户查询就得写分别写两个ACTION来处理。而JPETSTORE的作者克林顿(Clinton Begin,名字够响亮的)写了一个ACTION动态的调用FORMBEAN的不同方法来处理不同的动作。
代码如下,注意execute()的写法!
 
public class BeanAction extends Action {  
  public ActionForward execute(ActionMapping mapping,  ActionForm form, HttpServletRequest request,  HttpServletResponse response) 
      throws Exception { 
    String forward = "success"; 
    try { 
      ActionContext.initialize(request, response); 
      if (form != null) { 
        // Explicit Method Mapping 
        Method method = null; 
        String methodName = mapping.getParameter(); 
        if (methodName != null && !"*".equals(methodName)) { 
          try { 
            method = form.getClass().getMethod(methodName,   null);
            forward = (String) method.invoke(form, null); 
          } catch (Exception e) { 
            throw new BeanActionException("Error dispatching  
bean action via method parameter ('" + methodName + "').   
Cause: " + e, e); 
          } 
        } 
        // Path Based Method Mapping   
        if (method == null && !"*".equals(methodName)) {  
          methodName = mapping.getPath();   
          if (methodName.length() > 1) {   
            int slash = methodName.lastIndexOf("/") + 1;   
            methodName = methodName.substring(slash);   
            if (methodName.length() > 0) {   
              try {   
                method = form.getClass().getMethod   (methodName, null);   
                forward = (String) method.invoke(form, null);   
              } catch (Exception e) {   
                throw new BeanActionException("Error dispatching   
  bean action via URL pattern ('" + methodName + "').   
Cause: " + e, e);   
              }  
            }   
          }     
        }       
      }         
    } catch (Exception e) {   
      request.setAttribute("BeanActionException", e);   
      throw e;    
    }    
    return mapping.findForward(forward);   
  }   
}   
 
也就是通过对struts-config.xml的配置信息的读取来决定调用的方法,或者是不调用任何方法。
例如:
      
当ACTIONSERVLET收到请求/shop/viewCategory.shtml,(JPETSTORE里后缀定义的是“.shtml”)调用catalogBean的viewCategory方法。
怎么样,有创意吧,如果你愿意,就再也不用写那么多的ACTION了。
下面谈一谈IBATIS的O/R MAPPING吧。请大家打开目录your project\com\ibatis\jpetstore\persistence\sqlmapdao\sql,看到了什么?除了配置文件sql-map-config.xml以外,是一些和JAVABEAN相对应的XML,打开sql-map-config.xml和Acount.xml看看吧,再返到your project\com\ibatis\jpetstore\persistence目录,打开dao.xml发现他们的关系了吧。可能这时你搞不清这些XML有什么用处,别急,IBATIS官方文档里说的很清楚(有中文版的哦)。我大致说一下跟JAVABEAN对应的那些XML文件的作用吧,比如Acount.xml,是映射JAVABEAN和数据库的表的文件。你可以按照IBATIS的规范在里面写任意的SQL语句,参数和返回值可以是基本类型及其包装类,MAP,自定义的类。最常用的当然是返回自定义类实例了。不过如果返回值是自定义的类实例的话,你就需要先定义resultMap,比如:
<resultMap id="accountResult" class="account">
    <result property="username" column="USERID"/>
    <result property="email" column="EMAIL"/>
    <result property="firstName" column="FIRSTNAME"/>
    <result property="lastName" column="LASTNAME"/>
    <result property="status" column="STATUS"/>
    <result property="address1" column="ADDR1"/>
    <result property="address2" column="ADDR2"/>
    <result property="city" column="CITY"/>
    <result property="state" column="STATE"/>
    <result property="zip" column="ZIP"/>
    <result property="country" column="COUNTRY"/>
    <result property="phone" column="PHONE"/>
    <result property="languagePreference" column="LANGPREF"/>
    <result property="favouriteCategoryId" column="FAVCATEGORY" />
    <result property="listOption" column="MYLISTOPT" />
    <result property="bannerOption" column="BANNEROPT" />
    <result property="bannerName" column="BANNERNAME" />
  <resultMap>
然后再引用:
<select id="getAccountByUsername" resultMap="accountResult" parameterClass="string">
    select
          SIGNON.USERNAME as USERID,
          ACCOUNT.EMAIL,
          ACCOUNT.FIRSTNAME,
          ACCOUNT.LASTNAME,
          ACCOUNT.STATUS,
          ACCOUNT.ADDR1,
          ACCOUNT.ADDR2,
          ACCOUNT.CITY,
          ACCOUNT.STATE,
          ACCOUNT.ZIP,
          ACCOUNT.COUNTRY,
          ACCOUNT.PHONE,
          PROFILE.LANGPREF,
          PROFILE.FAVCATEGORY,
          PROFILE.MYLISTOPT,
          PROFILE.BANNEROPT,
          BANNERDATA.BANNERNAME
    from ACCOUNT, PROFILE, SIGNON, BANNERDATA
    where ACCOUNT.USERID = #value#
      and SIGNON.USERNAME = ACCOUNT.USERID
      and PROFILE.USERID = ACCOUNT.USERID
      and PROFILE.FAVCATEGORY = BANNERDATA.FAVCATEGORY
  <select>
再打开AccountSqlMapDao.java看看: 
public Account getAccount(String username) {
    return (Account) queryForObject("getAccountByUsername", username);
  }  
思考一下,看明白其中的关联了吧。
打开AccountService.JAVA:  
public Account getAccount(String username) { 
    return accountDao.getAccount(username); 
  } 
打开AccountBean.java: 
public String newAccount() { 
    try { 
      accountService.insertAccount(account); 
      account = accountService.getAccount (account.getUsername());//在这调用的 
      myList = catalogService.getProductListByCategory (account.getFavouriteCategoryId()); 
      authenticated = true; 
      repeatedPassword = null; 
      return "success"; 
    } catch (Exception e) { 
      throw new BeanActionException ("There was a problem  creating your Account Information.  Cause: " + e, e);
    } 
  } 
     看了半天,写个例子试试吧
 
package com.ibatis.jpetstore.service; 
import com.ibatis.dao.client.DaoManager; 
import com.ibatis.jpetstore.domain.*; 
import com.ibatis.jpetstore.persistence.DaoConfig; 
import com.ibatis.common.util.PaginatedList; 
import com.ibatis.jpetstore.persistence.iface.*; 
import java.util.*; 
public class IbatisTest { 
  private DaoManager daoManager =  DaoConfig.getDaomanager(); 
  private AccountDao accountDao; 
  
  public IbatisTest() { 
    accountDao = (AccountDao) daoManager.getDao (AccountDao.class); 
    Account account=accountDao.getAccount("j2ee", "j2ee"); 
    System.out.println(account.getFirstName()); 
    
  } 
  public static void main(String[] args) { 
     IbatisTest ibatisTest=new IbatisTest(); 
  } 
} 
你还可以试试insert,update,delete。
IBATIS里可是支持分页的,用起来很爽的,大家有空还是花点功夫钻研一下吧。
关于DEBUG:
我前两天照搬JPETSTORE的架构试着写了一个交友网站,基本上挺顺利,只是感觉DEBUG比较麻烦,通常为了找一个错花上几个小时。JBUILDER带的DEBUG我没用过,但可是肯定肯定和DELPHI上的DEBUG是有天壤之别的。而且JUNIT我也是刚开始学,也没用上。这里,我把自己比较土的办法介绍一下:
一,	当你写了新的O/R MAPPING的时候,可以先写个包含MAIN方法的类测试一下,就向我上面的测试例子一样。
二,	当你想跟踪变量值的时候,你可以利用IBATIS带的工具类ActionContext把变量写到SESSION里,比如你有你个FORMBEAN:UserBean.java,其中有一个方法是处理用户登录的,你为了跟踪用户的用户名和密码,可以这样写: 
public String logon() { 
try { 
  user = userService.getUser(user.getUsername(),  user.getPassword()); 
  if (user== null ) { 
    clear(); 
    return "failure"; 
  } else { 
    user.setPassword(null); 
    authenticated = true; 
    user.setMessageCount (messageService.getMessageNewCount(user.getUserId())); 
    ActionContext.getActionContext().setSimpleMessage ("newCount="+newCount.toString()+"   toUserId="+user.getUserId());//写入SESSION 
    return " failure ";}//导入到Error.jsp 
  }catch (Exception e){ 
     throw new BeanActionException ("There was a problem  logoning your Account Information.  Cause: " + e, e); 
  } 
} 
当然你需要包含下面的语句 
import com.ibatis.struts.ActionContext;  
 Error.jsp: 
<%@ taglib uri="struts-logic" prefix="logic" %> 
<%@ taglib uri="struts-bean" prefix="bean" %> 
<%@ taglib uri="struts-html" prefix="html" %> 
<%@ page import="java.io.PrintWriter"%> 
<logic:present name="message"> 
  <bean:write 
  name="message" /> 
</logic:present> 
//输出你需要的信息 
<logic:present name="errors"> 
  <logic:iterate id="error" name="errors"> 
     
       <bean:write name="error" /> 
     
  </logic:iterate> 
</logic:present> 
<logic:notPresent name="BeanActionException"> 
  <logic:notPresent name="message"> 
    Something happened... 
    But no further information was provided. 
  </logic:notPresent> 
</logic:notPresent> 
 
<logic:present name="BeanActionException">> 
  Error! 
  name="BeanActionException"  property="class.name"/> 
   
  <bean:write name="BeanActionException"  property="message"/> 
</logic:present> 
 
<logic:present name="BeanActionException"> 
  Stack 
   
<% 
  Exception e = (Exception)request.getAttribute ("BeanActionException"); 
  e.printStackTrace(new PrintWriter(out)); 
%> 
  
  
</logic:present> 
三,	为跟踪变量,你还可以利用LOG4J把变量值写到LOG里去,这种方法很常见,不明白就去www.google.com查吧。
四,	为避免写javabean出现大小写或其他的错误,强烈建议不要把BEAN当做普通CLASS来写,要用IDE 新建一个BEAN,这样IDE会帮你找出很多错误。我就吃了不少苦头。
入门了吗?有问题请留言。
为了贴上XML费了老鼻子劲,不容易啊。
我要开始研究SPRING和HIBERNATE啦。
 
 
  | 
   
  
     | 
   
  
     相关文章:相关软件:  | 
   
   
      |