12.UserService实现
在这一章我们要实现UserService并且使他通过测试。
作为我们早先的应用架构的讨论,Value Object是从一个或更多的实体的属性的特殊封装,从应用层到其他层屏蔽实体的需要。要实现在UserService中的getAllUsers()方法,我们现在要定义一个User实体。要保证简单,我们要作一个UserVO属性和User实体的一对一的映射。User实体的模型正如下面显示的样子。
注意,我们没有明确的建模id属性-所有的实体被假定有类型为Long的id属性。如果这种默认的假设不存在,你才需要给id建模,例如你的id属性名字或类型不同。
注意,AndroMDA会映射User实体到数据库表USER。然后USER在一些数据库中是保留字,这里联系也会告诉你如何覆写AndroMDA的默认代码生成行为。
现在让我们在timetracker模型中建立User实体。请跟随下面的连接看在具体的工具中如何操作。
- ArgoUML (under construction)
- MagicDraw 9.5
- MagicDraw 11.5
- RSM 6
接下来我们要增加一些依赖关系到模型中,告诉AndroMDA关于我们已经建模的元素的之间的关系。首先是从User实体到UserVO的依赖。这个依赖如下面的显示,并且告诉AndroMDA在User和UserVO对象中生成转换关系。转换的方法在数据访问对象UserDaoBase中被生成。他们小心一些简单的转换,然后如果你的value object是复杂的(例如,如果我们有从相关实体中读取的属性),然后你可以覆写默认的转换方法来填充额外的属性。因为我们的UserVo足够简单,默认的转换方法会工作的很出色。
- ArgoUML (under construction)
- MagicDraw 9.x
- MagicDraw 11.5
- RSM 6
接下来在UserService和User实体增加关联。这种关联如下图表示,告诉AndroMDA给UserService访问到User实体。从实现层面,这注入了UserDao实例到UserService。正如你可能猜到的,UserDao是允许客户端读取和写入user实体的数据访问对象。
请根据下面的连接来增加依赖关系。
- ArgoUML (under construction)
- MagicDraw 9.x
- MagicDraw 11.5
- RSM 6
现在,让我们要求AndroMDA来为User实体生成代码
1. 在命令提示符窗口执行命令mvn install。注意build不会成功,因为test仍然失败,然后代码生成部分是成功的。
打开目录C:/timetracker/core/target/src/org/andromeda/timetracker/domain,注意到有五个文件在这个目录中。
1. User.java:这是实现User实体的主要的类。包含从模型中的三个属性和他们的getter和setter。androMDA自动增加一个id属性,表示User实例在数据库中的唯一标识。另外,AndroMDA自动为实体生成equals()和hashCode()方法。注意,User是一个抽象类-他不能被实例化。下面描述的UserImpl,是集成User的具体实现类。它能使用嵌入在User类中的工厂模式来实例化。
2. UserImpl.java:是上面提及到的User类的实现。意味着能被任何代码所包含,开发人员能增加到User实体中。
3. UserDao.java:对任何实体的数据访问对象创建为三个类。一个接口,一个抽象类和一个具体实现。UserDao是User数据访问对象的接口。它描述了DAO的CRUD方法。
4. UserDaoBase:UserDaoBase实现在UserDao接口中描述的所有的CRUD方法。
5. User.hbm.xml:这事Hibernate映射文件,映射User实体和相应的数据库。
现在,打开C:/timetracker/core/src/main/java/org/andromeda/timetracker/domain,注意有一个额外的文件在这个目录被生成:
1.UserDaoImpl.java:UserDaoImpl是UserDaoBase的具体实现,意味着开发人员要在User数据访问对象中增加的代码。
注意,target目录仅仅用于指向自动生成文件。在这里没有文件应该被修改,因为代码生成会完全的抹掉他们,删掉所有的修改。这也是一种最佳实践,不要把这些代码check in到源码仓库中。
到现在,你应该觉得奇怪,在哪加入你定制的代码。在上面我们讨论开发者可以在UserImpl.java和UserDaoImpl.java中增加定制代码,但是为什么UserImpl.java被生成到target目录中?well,andromda相当聪明。你没有告诉他你想写定制的代码在UserImpl.java中。然而,你一旦告诉AndroMDA你想在这个类中写定制的代码,他会把这个类生成在core目录的src目录中。现在你可以自由修改UserImpl.java类,并且在里面增加任何代码。AndroMDA绝不会覆盖src目录的文件。他们仅自动生成一次。
谈到定制代码,注意我们甚至没有写一行代码来实现UserService!AndroMDA已经为我们作了大量的工作,例如UserService的创建,UserVO,UserDao,Hibernate映射文件等等。所有的这些已经填充UserServiceImpl中的“handle”方法。在UserServiceImpl类中增加下面的代码中的粗体部分。
// license-header java merge-point
/**
* This is only generated once! It will never be overwritten.
* You can (and have to!) safely modify it by hand.
*/
package org.andromda.timetracker.service;
import java.util.Collection;
import org.andromda.timetracker.domain.UserDao;
import org.andromda.timetracker.vo.UserVO;
/**
* @see org.andromda.timetracker.service.UserService
*/
public class UserServiceImpl
extends org.andromda.timetracker.service.UserServiceBase
{
/**
* @see org.andromda.timetracker.service.UserService#getAllUsers()
*/
protected org.andromda.timetracker.vo.UserVO[] handleGetAllUsers()
throws java.lang.Exception
{
Collection userVOs = getUserDao().loadAll(UserDao.TRANSFORM_USERVO);
return (UserVO[])userVOs.toArray(new UserVO[0]);
}
}
这里我们作了一个直接的调用userDao中的loadAll()。我们提供了UserDao.TRANSFORM_USERVO参数给loadAll方法,要求方法在返回前把user实体转换为uservo。我们然后转换返回的集合到方法声明中的定义的数组,并且返回数组。你能看到实现这个方法有多么简单,不需要写DAO或者转换数据库记录为对象,AndroMDA会为这些事情关照你。
Well,我们认为UserService现在完全的实现。让我们测试一下,执行下面的命令运行UserServiceTest。注意这次我们不执行mvn install,因为这个命令会生成代码并且重建整个应用,因为自从上次生成后我们没有做任何模型变更,只运行test。
C:/timetracker>mvn -f core/pom.xml test
...
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running Services Test
SQL Error: 1146, SQLState: 42S02
Table 'timetracker.user' doesn't exist
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 3.996 sec <<< FAILURE!
Results :
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] There are test failures.
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 2 seconds
[INFO] Finished at: Wed Jun 28 16:32:02 EDT 2006
[INFO] Final Memory:
26M
/
53M
[INFO] ------------------------------------------------------------------------
Aha,我们忘记在数据库中创建User表了。下面的步骤创建这个表,产生测试数据并且再次测试。
1. 在命令提示符窗口运行下面的命令,要求AndroMDA创建我们的数据库schema。
Mvn –f core/pom.xml andromdapp:schem –Dtasks=create
确认已经看到了BUILD SUCCESS的消息。
2. 打开MySQL Query Browser,作为timetracker登录,你可以在timetracker schema中看到users表
3. 选择file->New Script tab并且粘贴下面的代码
insert into USERS (ID, USERNAME, FIRST_NAME, LAST_NAME)
values (1, 'nbhatia', 'Naresh', 'Bhatia');
insert into USERS (ID, USERNAME, FIRST_NAME, LAST_NAME)
values (2, 'lcoude', 'Louis', 'Coude');
insert into USERS (ID, USERNAME, FIRST_NAME, LAST_NAME)
values (3, 'ecrutchfield', 'Eric', 'Crutchfield');
insert into USERS (ID, USERNAME, FIRST_NAME, LAST_NAME)
values (4, 'cmicali', 'Chris', 'Micali');
4. 点击执行按钮
5. 现在,回来测试:
mvn –f core/pom.xml test
6.
打开C:/timetracker/core/timetracker-test.log
检查一下测试日志的结果。你可以看到文件末尾打印出的用户名。
16:59:28.362 INFO - nbhatia
16:59:28.362 INFO - lcoude
16:59:28.362 INFO - ecrutchfield
16:59:28.362 INFO - cmicali