摘要: JpetStore提供了一个整套的测试代码对于想进行单元测试却不知道如何进行单元测试的人(me)来说,是一个很好的学习机会。
JpetStore的单元测试代码与它的系统源文件是独立分离的,在test文件夹中。打开文件夹可以很清楚的发现该文件夹的内容组成结构与源文件基本一致。
JpetStore分为领域层(domain),持久层(peristence),服务层(service),表现层(presentation),它的测试也分这几个层来进行。
阅读全文
posted @
2007-01-22 15:18 涤生 阅读(3306) |
评论 (0) |
编辑 收藏
摘要: 本文是在参阅了http://ivanl.javaeye.com/blog/24739基础上完成的
在看JPetStore的代码时,发现它的分页处理主要是通过返回PaginatedList对象来完成的。如:在CatalogService类中
public PaginatedList getProductListByCategory(String categoryId) {
return productDao.getProductListByCategory(categoryId);
}
分页是操作数据库型系统常遇到的问题。分页实现方法很多,但效率的差异就很大了。iBatis是通过什么方式来实现这个分页的了。查看它的实现部分:
阅读全文
posted @
2007-01-18 16:27 涤生 阅读(8446) |
评论 (6) |
编辑 收藏
关键字: OO UML,泛化,依赖,关联,聚合
类与类之间的关系对于理解面向对象具有很重要的作用,以前在面试的时候也经常被问到这个问题,在这里我就介绍一下。 类与类之间存在以下关系: (1)泛化(Generalization) (2)关联(Association) (3)依赖(Dependency) (4)聚合(Aggregation)
UML图与应用代码例子:
1.泛化(Generalization)
[泛化]
表示类与类之间的继承关系,接口与接口之间的继承关系,或类对接口的实现关系。一般化的关系是从子类指向父类的,与继承或实现的方法相反。 [具体表现] 父类 父类实例=new 子类() [UML图](图1.1)
图1.1Animal类与Tiger类,Dog类的泛化关系
[代码表现]
-
class
Animal{}
-
class
Tiger
extends
Animal{}
-
public
class
Test
-
{
-
public
void
test()
-
{
-
Animal a=
new
Tiger();
-
}
-
}
2.依赖(Dependency)
[依赖]
对于两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间主要体现为依赖关系。 [具体表现] 依赖关系表现在局部变量,方法的参数,以及对静态方法的调用 [现实例子] 比如说你要去拧螺丝,你是不是要借助(也就是依赖)螺丝刀(Screwdriver)来帮助你完成拧螺丝(screw)的工作 [UML表现](图1.2)
图1.2 Person类与Screwdriver类的依赖关系
[代码表现]
- public class Person{
-
- public void screw(Screwdriver screwdriver){
- screwdriver.screw();
- }
- }
3.关联(Association) [关联] 对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时,这两个对象之间为关联关系。 [具体表现] 关联关系是使用实例变量来实现 [现实例子] 比如客户和订单,每个订单对应特定的客户,每个客户对应一些特定的订单;再例如公司和员工,每个公司对应一些特定的员工,每个员工对应一特定的公司 [UML图] (图1.3)
图1.3 公司和员工的关联关系
[代码表现]
- public class Company{
- private Employee employee;
- public Employee getEmployee(){
- return employee;
- }
- public void setEmployee(Employee employee){
- this.employee=employee;
- }
-
- public void run(){
- employee.startWorking();
- }
- }
(4)聚合(Aggregation)
[聚合]
当对象A被加入到对象B中,成为对象B的组成部分时,对象B和对象A之间为聚集关系。聚合是关联关系的一种,是较强的关联关系,强调的是整体与部分之间的关系。 [具体表现] 与关联关系一样,聚合关系也是通过实例变量来实现这样关系的。关联关系和聚合关系来语法上是没办法区分的,从语义上才能更好的区分两者的区别。 [关联与聚合的区别] (1)关联关系所涉及的两个对象是处在同一个层次上的。比如人和自行车就是一种关联关系,而不是聚合关系,因为人不是由自行车组成的。 聚合关系涉及的两个对象处于不平等的层次上,一个代表整体,一个代表部分。比如电脑和它的显示器、键盘、主板以及内存就是聚集关系,因为主板是电脑的组成部分。 (2)对于具有聚集关系(尤其是强聚集关系)的两个对象,整体对象会制约它的组成对象的生命周期。部分类的对象不能单独存在,它的生命周期依赖于整体类的对象的生命周期,当整体消失,部分也就随之消失。比如张三的电脑被偷了,那么电脑的所有组件也不存在了,除非张三事先把一些电脑的组件(比如硬盘和内存)拆了下来。 [UML图](图1.4)
图1.3 电脑和组件的聚合关系
[代码表现]
- public class Computer{
- private CPU cpu;
- public CPU getCPU(){
- return cpu;
- }
- public void setCPU(CPU cpu){
- this.cpu=cpu;
- }
-
- public void start(){
-
- cpu.run();
- }
- }
|
posted @
2007-01-17 10:07 涤生 阅读(569) |
评论 (0) |
编辑 收藏
摘要: 本文参考了
iBatis DAO入门与进阶(http://www.matrix.org.cn/resource/article/44/44058_iBatis+DAO.html)
iBatis DAO事务探索(http://www.blogjava.net/RongHao/archive/2006/01/20/28817.html)
今天继续研究了JPetStore的持久层,其中由于看了一篇文章的误导,导致我对其中的事务处理深表怀疑。通过阅读源代码与看上面两篇文章,对这个问题才认识清楚。和我当初预想的一致。
阅读全文
posted @
2007-01-16 21:15 涤生 阅读(2795) |
评论 (2) |
编辑 收藏
摘要: 问题就出现在这,Item类中包含了Product类,出现NestedSqlException错误。
查阅了ibatis帮助,此处sql_map的嵌套类写法是正确的。我又将这个sql语句拷贝到MsSqlServer中执行,结果也是正确的。陷入困惑。
阅读全文
posted @
2007-01-16 13:38 涤生 阅读(3356) |
评论 (6) |
编辑 收藏
今天在看JPetStore代码时,对他的链接中的请求参数感到疑惑,最后发现是自己的对Struts框架不熟悉导致的。
我是从Net阵营中刚转入Java里的,在Net中对请求参数的名称无特殊限制,只要在页面中取参数的值即可。当然这个功能在Java中也具备。即request.Getparameter()
今天我在看JpetStore代码时,在点击
http://127.0.0.1:8083/JPetStore/shop/viewCategory.shtml?categoryId=BIRDS时,当跟踪函数viewCategory时发现此时categoryID已经赋值了,我却找不到在什么地方赋值的,好是花费了一番周执。
查看此段链接对应的struts.xml
<action path="/shop/viewCategory" type="org.apache.struts.beanaction.BeanAction"
name="catalogBean" scope="session"
validate="false">
<forward name="success" path="/catalog/Category.jsp"/>我首先跟踪BeanAction的excute函数发现在此之前就已经赋值,说明和BeanAction无关,是Struts系统本身的结构。我故意将链接修改,修改成
http://127.0.0.1:8083/JPetStore/shop/viewCategory.shtml?category=BIRDS此时出现错误,错误如下:
java.lang.IllegalArgumentException: Cannot invoke com.ibatis.jpetstore.presentation.CatalogBean.setCategory - argument type mismatch
org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:1778)
org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:1759)
org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1648)
org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:1677)
org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:1022)
org.apache.commons.beanutils.BeanUtilsBean.populate(BeanUtilsBean.java:811)
org.apache.commons.beanutils.BeanUtils.populate(BeanUtils.java:298)
org.apache.struts.util.RequestUtils.populate(RequestUtils.java:493)
org.apache.struts.action.RequestProcessor.processPopulate(RequestProcessor.java:805)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:203)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1194)
org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:414)
javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
根据这个错误堆栈可知,它实际上采用的是反射,setProperty,此时找不到category的Setter函数报错。然后我查看了一下RequestProcessor的默认实现代码
// Process any ActionForm bean related to this request
ActionForm form = processActionForm(request, response, mapping);
processPopulate(request, response, form, mapping); 这段函数功能为:
1)调用processActionForm( )方法检查是否存在为ActionMapping配置的ActionForm 。如果存在,则在有效区
域内查找是否存在该ActionForm 的实例,存在,则复用,不存在,则创建一个实例。然后将实例保存与再配置
文件中配置好的有效区域(request,session,application)内,并用Action元素的name属性作为该实例的关键字。
2)调用processPopulate( )方法,如果存来存在为ActionMapping配置的ActionForm,则封装请求对象中的数据
到ActionForm 中,在进行封装之前,先调用ActionForm 的reset( )方法进行属性值的默认化。
根据以上的分析,可得知,在调用链接前struts框架会自动的将所有的请求参数封装入指定的formbean中。所以请求参数的名称应该是对应formbean的一个属性。
这就是struts中请求参数的处理过程。主要是我对struts还没有完全掌握,加上Net的影响,才花费了一圈发现这个原因。
posted @
2007-01-15 20:56 涤生 阅读(962) |
评论 (0) |
编辑 收藏
JpetStore中的Action与普通Struts的Action处理方式不一样。遍历JpetStore的src文件夹,并无一个具体的Action,那么它是如何来完成普通Struts的Action工作了?
查看JpetStore的Struts.xml可以发现,它的Action只有一个,即“org.apache.stuts.beanaction.Beanaction”。通过Eclipse查看beanaction.jar的源代码,可以发现Beanaction继承与普通Action,即具备普通的action的功能。那么它无具体Action的奥妙在哪,继续研究BeanAction的代码,截取BeanAction的excute方法中核心部分代码如下:
/**//*遍历此方法的业务逻辑可知,*的优先级最高,如果是*,则不调用任何方法直接Forward,类似于ForwardAction*/
private static final String NO_METHOD_CALL = "*";
…….
/**//*所有的FormBean都继承于BaseBean*/
BaseBean bean = (BaseBean) form;
ActionContext.initCurrentContext(request, response);
if (bean != null) {
// Explicit Method Mapping
/**//*下面是检查struts.xml配置中是否有parameter属性*/
Method method = null;
String methodName = mapping.getParameter();
if (methodName != null && !NO_METHOD_CALL.equals(methodName)) {
try {
/**//*通过反射,根据得到的方法名称取得方法的句柄*/
method = bean.getClass().getMethod(methodName, null);
synchronized (bean) {
/**//*下面是关键一句,调用basebean拥有的接口ActionInterceptor的实现DefaultActionInterceptor,来完成具体方法的调用*/
forward = bean.getInterceptor().intercept(new ActionInvoker(bean, method));
}
……..
/**//*无Parameter属性,检查path路径的最后一个/后的名称,即为调用的方法名*/
// Path Based Method Mapping
if (method == null && !NO_METHOD_CALL.equals(methodName)) {
methodName = mapping.getPath();
if (methodName.length() > 1) {
int slash = methodName.lastIndexOf("/") + 1;
methodName = methodName.substring(slash);
if (methodName.length() > 0) {
try {
method = bean.getClass().getMethod(methodName, null);
synchronized (bean) {
forward = bean.getInterceptor().intercept(new ActionInvoker(bean, method));
}
……..
/**//*根据调用方法返回的String,得到页面的转移路径*/
return mapping.findForward(forward);
通过研究上面这段代码,我们可知,JpetStore中没有具体Action实现的关键原因即在于下面这几句
/**//*通过反射,根据得到的方法名称取得方法的句柄*/
method = bean.getClass().getMethod(methodName, null);
synchronized (bean) {
/**//*下面是关键一句,调用basebean拥有的接口ActionInterceptor的实现DefaultActionInterceptor,来完成具体方法的调用*/
forward = bean.getInterceptor().intercept(new ActionInvoker(bean, method));
}
即将原来Action中的excute方法的实现转移到FormBean中,这样实现显得更为简捷,方便。研究ActionInvoke,它的核心代码如下:
public String invoke() {
try {
return (String) method.invoke(bean, null);
} catch (Exception e) {
throw new BeanActionException("Error invoking Action. Cause: " + e, e);
}
}
至此可知,它调用的是formbean中的函数。且从这段代码可知,formbean的这类特殊函数,此处称为action方法,要符合两个特征:1)无参数;2)返回值为string,此返回string即是Struts-config.xml的全局或局部的forward。
以上是整个beanaction的实现机制。个人感觉此种实现方法对于开发者而言已经类似于ASP.NET的.aspx与.cs开发模式了。下面是通过实例来说明一下BeanAction如何控制formbean的
Struts-config.xml的配置里有3种映射方式,来告诉BeanAction把控制转到哪个form bean对象的哪个方法来处理。
(1)parameter=”*’直接跳转;(2)Parameter中含具体的方法名;(3)Path中最后一个/后的方法名
以这个请求连接为例http://localhost/jpetstore4/shop/viewOrder.shtml
1. URL Pattern
<action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
name="orderBean" scope="session"
validate="false">
<forward name="success" path="/order/ViewOrder.jsp"/>
</action>
此种方式表示,控制将被转发到"orderBean"这个form bean对象 的"viewOrder"方法(行为)来处理。方法名取"path"参数的以"/"分隔的最后一部分。
2. Method Parameter
<action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
name="orderBean" parameter="viewOrder" scope="session"
validate="false">
<forward name="success" path="/order/ViewOrder.jsp"/>
</action>
此种方式表示,控制将被转发到"orderBean"这个form bean对象的"viewOrder"方法(行为)来处理。配置中的"parameter"参数表示form bean类上的方法。"parameter"参数优先于"path"参数。
3. No Method call
<action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
name="orderBean" parameter="*" scope="session"
validate="false">
<forward name="success" path="/order/ViewOrder.jsp"/>
</action>
此种方式表示,form bean上没有任何方法被调用。如果存在"name"属性,则struts把表单参数等数据填充到form bean对象后,把控制转发到"success"。否则,如果name为空,则直接转发控制到"success"。
这就相当于struts内置的org.apache.struts.actions.ForwardAction的功能
<action path="/shop/viewOrder" type="org.apache.struts.actions.ForwardAction" parameter="/order/ViewOrder.jsp " scope="session" validate="false"> </action>
|
posted @
2007-01-12 16:34 涤生 阅读(3874) |
评论 (8) |
编辑 收藏
对初接触者来说,到底如何开始使用abator,资源比较少,本文记载了我今日初次使用的过程,希望对和我一样的初学者有所帮助
获得
http://ibatis.apache.org/abator.html
Eclipse可以自动的进行Update获取此Plugin,官方的安装步骤
Automatic Eclipse Install
If you've already installed a prior version of Abator, simply run the Eclipse Install/Update tool and the new version will be found automatically.
If you've not already installed Abator, then you can use the built in Eclipse install support by following these steps:
- Take the "Help>Software Updates>Find and Install" Menu Option
- Select the "Search for new features to install" radio button, press "Next"
- Press the "New Remote Site" button
- Enter the following information:
- Name:
- Abator for Eclipse Update Site
- URL:
- http://ibatis.apache.org/tools/abator
- Press OK
- Check the box next to "Abator for Eclipse Update Site"
- Follow the remainder of the install wizard
2、安装好后将在New菜单中看到一个新的文件类型Abator for iBATIS Configuration File,此是Abator的配置文件,配置文件的详细说明见http://ibatis.apache.org/docs/tools/abator/
3、新建一个配置文件,进行修改,根据自己的实际需求进行修改
关键点:
1)jdbcconnection,按照一般的配置即可,需要说明的是它需要指定访问JdbcDriver的classPathEntry,对于MsSqlServer而言,要将这三个jar文件均包含在内,否则会出现jdbc访问错误。
2)配置三个Pakage
3)配置表,此处需说明的是对于MsSqlServer不能写TableSchema,我初次指定TableSchema,结果未找到对应的表
简单的配置如下,复杂的见配置文件的详细说明。示例配置文件如下
<abatorConfiguration>
<abatorContext> <!-- TODO: Add Database Connection Information -->
<jdbcConnection driverClass="com.microsoft.jdbc.sqlserver.SQLServerDriver"
connectionURL="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=whm;SelectMethod=cursor"
userId="sa"
password="sa">
<classPathEntry location="C:/Program Files/Apache Software Foundation/Tomcat 5.0/common/lib/mssqlserver.jar" />
<classPathEntry location="C:/Program Files/Apache Software Foundation/Tomcat 5.0/common/lib/msutil.jar" />
<classPathEntry location="C:/Program Files/Apache Software Foundation/Tomcat 5.0/common/lib/msbase.jar" />
</jdbcConnection>
<javaModelGenerator targetPackage="com.dwerp.itatis.domain" targetProject="BhbManage" />
<sqlMapGenerator targetPackage="com.dwerp.itatis.persistence.xml" targetProject="BhbManage" />
<daoGenerator type="IBATIS" targetPackage="com.dwerp.itatis.persistence.sqlmapdao" targetProject="BhbManage" />
<table tableName="BHBGL">
</table>
</abatorContext>
</abatorConfiguration>
4、右键单击配置文件,点击Generate iBatis Artifacts,生成文件。
posted @
2007-01-11 21:37 涤生 阅读(2005) |
评论 (1) |
编辑 收藏
学习的最好方法莫过于研究示例程序。本文是鄙人今日在Eclipse中运行iBATIS的JpetStore的记录,供同仁参考
1、下载iBAITS(
http://ibatis.apache.org/javadownloads.cgi)
2、下载JPetStore-5.0(
http://ibatis.apache.org/javadownloads.cgi)
准备工作完成,下面开始将示例程序转移到Eclipse中
1、在Eclipse中新建一个空的WebProject,如:JPetStore
2、将下载的JPetStore-5.0文件夹的内容拷贝至JPetStore,其中由于Eclipse默认的Web文件夹是WebRoot所以JPetStore-5.0中的Web文件单独拷贝到新建的Project的Web文件夹WebRoot下。简单的是说,就是要保证空的WebProject中的所拥有文件模型不动,将下载的内容拷贝到相应的文件夹下
3、刷新Eclipse,此时会看到src下显示为错误,错误的原因是此时对应的包未引入,由于Eclipse默认的是WebRoot/lib下的包文件,所以将主目录下即JPetStore/devlib与JPetStore/lib引入到项目中
有两种方法:直接将此两个文件夹下的内容直接拷贝到JPetStore/WebRoot/lib下,或者,通过Import命令引入
4、至此就已经完成项目迁移工作,下面就是
1)建数据库,鄙人用的是MsSqlServer,在JPetStore/src/ddl中有各种数据库的sql文件
2)修改iBATIS的database.propertis,见上篇拙作
3)在Eclipse通过Tomcat部署
即可看到PetShop的网站了
http://127.0.0.1:8083/JPetStore希望对和我一样的初学者有所帮助
posted @
2007-01-11 21:22 涤生 阅读(4269) |
评论 (4) |
编辑 收藏
希望此文能对初次使用ibatis访问MsSqlserver的朋友起个借鉴
1、在http://ibatis.apache.org/javadownloads.cgi下载ibatis,我下载的是2.2.0,由于还没有看Spring,所以下载此版本,带 iBATIS DAO 框架。以后版本都不再含有此框架。见网站说明:
Note: iBATIS 2.2.0 is the last release that includes the iBATIS DAO framework. After 2.2.0, the DAO iBATIS framework is removed from the downloads. We suggest converting iBATIS framework DAOs to the Spring Framework.
2、下载后将lib文件夹下的三个jar文件加入机器的Classpath中
此时,iBATIS 的框架已经搭建好
下面介绍一下如何访问MsSqlServer。
1、机器已经下载了Jdbc for MSsqlServer的jar文件,共三个文件,微软网站有下载。
2、可以通过Eclipse自带的DataBase Explorer测试是否能访问MsSqlServer
此时,通过iBATIS访问MsSqlServer的前期条件均已经准备好,下面进行配置
1、配置sql-map-config.xml文件,核心部分如下
<sqlMapConfig>
<properties resource="com/zyque/struts/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"/>
<property name="JDBC.DefaultAutoCommit" value="true" />
</dataSource>
</transactionManager>
<sqlMap resource="com/zyque/ibatis/BhbGl.xml"/>
</sqlMapConfig>
2、从上可以看出数据库读取的是database.properties,此配置如下
driver=com.microsoft.jdbc.sqlserver.SQLServerDriver
url=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=whm;SelectMethod=cursor
username=sa
password=sa
此处注意的是在访问MsSqlServer时候,需将SelectMethod=cursor,原因见上篇博客
通过这两步就可以通过ibatis访问MsSqlServer了
访问示例代码(参考的ibatis的入门指南,ibatis官方网站有下载),此处未对代码进行功能隔离封装,便于向嬖人之流的初学者学习
Bhbm elm = null;
String p_mc = "FM_BHJLDW";
String resource = "com/zyque/ibatis/sql-map-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
elm = (Bhbm) sqlMap.queryForObject ("getBhbByName", p_mc);
上面演示的一个简单查询,其余的示例可以看入门指南。并非本文的重点。
posted @
2007-01-11 21:01 涤生 阅读(980) |
评论 (1) |
编辑 收藏
--问题1:出现ClassNotFoundException,这个问题是由于你没有把driver类放到你的classpath中,也就是说
你的程序找不到驱动类,包括三个包:msutil.jar,msbase.jar,mssqlserver.jar
到微软网站下载此驱动到微软官方网站下载 jdbc3,安装后在C:\Program Files\Microsoft SQL Server 2000 Driver for JDBC\lib中可找到此三个驱动
使用 Microsoft SQL Server 2000 JDBC 驱动程序时,您可能会遇到以下异常:
java.sql.SQLException:[Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode.
原因
在手工事务模式 (AutoCommit=false) 下,如果使用直接 (SelectMethod=direct) 模式,当您尝试对使用 JDBC 驱动程序的 SQL Server 数据库执行多个语句时,将会出现此问题。直接模式是该驱动程序的默认模式。
解决方案
当您使用手工事务模式时,必须将驱动程序的 SelectMethod 属性设置为 Cursor,或者确保您按照本文“更多信息”一节指定的方式在每个连接上只使用一个活动语句。
配置实例(数据库链接字符串,注意url)
driver=com.microsoft.jdbc.sqlserver.SQLServerDriver
url=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=whm;SelectMethod=cursor
username=sa
password=sa
手动写的链接字符串
Connection con=DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=whm;SelectMethod=cursor","userName","password");
posted @
2007-01-10 20:24 涤生 阅读(267) |
评论 (0) |
编辑 收藏