准备工作
- 先期准备
老规矩,还是来看看项目构建的目录机构图,首先这个项目是由四个子项目组成:
可以看到其他三个项目中都是有各种类的,tian-parent中只有一个pom.xml,这是因为,这个项目是用来做聚合和继承来使用的,聚合值得是把其他三个项目组合到一起,继承是指,其他三个项目有选择地继承这个项目的部分的包依赖。 - 项目的组成
tian-parent
-pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.tian</groupId>
<artifactId>tian-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<url>http://maven.apache.org</url>
<!-- 导入了三个模块,把这三个模块聚合在一起 -->
<!-- 聚合是模块的位置 -->
<modules>
<module>../tian-core</module>
<module>../tian-log</module>
<module>../tian-service</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>tian-log</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>tian-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
子模块的构建
- tian-core这个模块其实还是一个项目的数据操作部分分离开来的,也就是我们所熟知的dao层,这里我们也使用了dbunit这个框架,在做单元测试隔离了模块测试的垃圾数据对数据库的影响,本模块的数据操作部分使用的是hibernate5.0.7,测试部分使用的是JDBC。
- IUserDao
package dao;
import model.User;
public interface IUserDao {
public void add(User user);
public User loadByUsername(String usernane);
}
- UserDao
package dao.impl;
import org.hibernate.Session;
import utils.HibernateUtil;
import model.User;
import dao.IUserDao;
public class UserDao implements IUserDao {
@Override
public void add(User user) {
Session session = null;
try{
session = HibernateUtil.openSession();
session.beginTransaction();
session.save(user);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
}finally{
HibernateUtil.close(session);
}
}
@Override
public User loadByUsername(String usernane) {
Session session = null;
User user = null;
try{
session = HibernateUtil.openSession();
user = (User) session.createQuery("from User where username=?")
.setParameter(0, usernane).uniqueResult();
}catch(Exception e){
e.printStackTrace();
}finally{
HibernateUtil.close(session);
}
return user;
}
}
- User
package model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "t_user")
public class User {
private int id;
private String username;
private String password;
private String nickname;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public User(int id, String username, String password, String nickname) {
this.id = id;
this.username = username;
this.password = password;
this.nickname = nickname;
}
public User(String username, String password, String nickname) {
this.username = username;
this.password = password;
this.nickname = nickname;
}
public User() {
}
}
- HibernateUtil.java
package utils;
import model.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class HibernateUtil {
private final static SessionFactory FACTORY = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml").build();
Metadata metadata = new MetadataSources(standardRegistry)
.addAnnotatedClass(User.class)
.getMetadataBuilder()
.applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE)
.build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
return sessionFactory;
}
public static SessionFactory getSessionFactory() {
return FACTORY;
}
public static Session openSession() {
return FACTORY.openSession();
}
public static void close(Session session) {
if(session!=null) session.close();
}
}
- TestUserDao.java
package dao;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import model.User;
import org.dbunit.DatabaseUnitException;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import utils.AbstractDbUnitTestCase;
import utils.EntitiesHelper;
import dao.impl.UserDao;
public class TestUserDao extends AbstractDbUnitTestCase{
private IUserDao userDao;
@Before
public void setUp() throws DataSetException, IOException{
userDao = new UserDao();
backupOneTable("t_user");
}
@Test
public void testLoad() throws DatabaseUnitException, SQLException{
IDataSet ds = createDateSet("t_user");
DatabaseOperation.CLEAN_INSERT.execute(dbunitCon, ds);
User tu = userDao.loadByUsername("admin");
EntitiesHelper.assertUser(tu);
}
@Test
public void testAdd() throws DatabaseUnitException, SQLException{
IDataSet ds = createDateSet("t_user");
DatabaseOperation.TRUNCATE_TABLE.execute(dbunitCon, ds);
User user = new User("admin","123","管理员");
userDao.add(user);
Assert.assertTrue(user.getId()>0);
User tu = userDao.loadByUsername("admin");
EntitiesHelper.assertUser(tu,user);
}
@After
public void tearDown() throws FileNotFoundException, DatabaseUnitException, SQLException{
resumeTable();
}
}
- AbstractDbUnitTestCase.java
- DbUtil.java
- EntitiesHelper.java
- log4j.properties
- t_user.xml
上面三个类参见上一篇博客,这里太长了,就不在冗余的复制啦。 - hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 配置hibernate的基本属性 -->
<!-- 方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 链接数据库 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/maven_hibernate?useUnicode=true&characterEncoding=UTF-8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123</property>
<!-- 是否显示及格式化sql语句 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- 生成数据表的策略 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 加入实体类的映射文件 -->
<mapping class="model.User"/>
</session-factory>
</hibernate-configuration>
下面就是比较重要的pom.xml文件了
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.tian</groupId>
<artifactId>tian-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 继承的绝对路径是pom文件 -->
<relativePath>
../tian-parent/pom.xml
</relativePath>
</parent>
<artifactId>tian-core</artifactId>
<packaging>jar</packaging>
<name>tian-core Maven Webapp</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
</project>
执行clean package命令,编译测试打包通过,本子项目就没有问题了,可以进入到下一个子项目的开发了。
tian-log项目的开发
如下图所示,应为在本工程中只是为了搭建这个过程,所以这个日志模块是空的,只有一个空壳。
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.tian</groupId>
<artifactId>tian-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../tian-parent/pom.xml</relativePath>
</parent>
<artifactId>tian-log</artifactId>
<packaging>jar</packaging>
<name>tian-log</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
</project>
如下是结构示意图
运行clean package打包,编译测试打包完成。tian-service项目开开发
如上图是结构示意图。
本子项目的单独开发,利用了easymock框架。
- IUserService.java
package org.tian.service;
import model.User;
public interface IUserService {
public void add(User user);
public User loadByUsername(String username);
}
- UserService.java
package org.tian.service.impl;
import model.User;
import org.tian.service.IUserService;
import dao.IUserDao;
public class UserService implements IUserService {
private IUserDao userDao;
public UserService(IUserDao userDao) {
super();
this.userDao = userDao;
}
public UserService() {
}
@Override
public void add(User user) {
userDao.add(user);
}
@Override
public User loadByUsername(String username) {
return userDao.loadByUsername(username);
}
}
- TestUserService.java
package org.tian.service;
import model.User;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.tian.service.impl.UserService;
import utils.EntitiesHelper;
import dao.IUserDao;
import static org.easymock.EasyMock.*;
public class TestUserService {
private IUserDao userDao;
private IUserService userServcie;
private User baseUser;
@Before
public void setUp(){
userDao = createStrictMock(IUserDao.class);
userServcie = new UserService(userDao);
baseUser = new User("admin","123","admin");
}
@Test
public void testAdd(){
userDao.add(baseUser);
expectLastCall();
replay(userDao);
userServcie.add(baseUser);
}
@Test
public void testLoadByUsername(){
expect(userDao.loadByUsername("admin")).andReturn(baseUser);
replay(userDao);
User tu = userServcie.loadByUsername("admin");
EntitiesHelper.assertUser(tu, baseUser);
}
@After
public void tearDown(){
verify(userDao);
}
}
- EntitiesHelper.java
关于这个测试的一些工具类,我必须多说两句,这个是在tian-core的test包中,本项目中导入tian-core的包,是不包含这个测试工具类,所以本子项目吧这个类重新在test包中复制了一份,其实如果在一个大型项目中,是可以单独吧这些工具类个打个包的。
最后在pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.tian</groupId>
<artifactId>tian-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../tian-parent/pom.xml</relativePath>
</parent>
<artifactId>tian-service</artifactId>
<packaging>jar</packaging>
<name>tian-service</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>tian-log</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>tian-core</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
</dependency>
</dependencies>
</project>
运行clean package ,编译测试打包就可以完成了。
总结分析
其实,最后,我们可以想想,每个子项目我们都打包运行,如果子项目很多,那可不就烦死 ,这就用到了,maven的聚合功能,在tian-parent中,可以看到有
<!-- 导入了三个模块,把这三个模块聚合在一起 -->
<!-- 聚合是模块的位置 -->
<modules>
<module>../tian-core</module>
<module>../tian-log</module>
<module>../tian-service</module>
</modules>
这段代码就是聚合,要注意的是,聚合是子模块(子项目根路径)的位置,而继承则是parent子项目pom.xml文件。
在tian-parent上执行clean package命令就可看到三个模块的编译、测试、打包过程。
补充:
在tian-parent的pom.xml上添加
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>compile</phase>
<goals><goal>jar</goal><goal>test-jar</goal></goals>
</execution>
</executions>
</plugin>
这个其实是添加打包源码的插件,在tian-parent上执行clean package命令就可看到三个模块的编译、测试、打包过程,图如下所示:
打包成rar文件,并把所有的jar包都包含进去:
在tian-parent的pom.xml中添加
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-rar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<goals><goal>rar</goal></goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<includeJar>true</includeJar>
</configuration>
</plugin>
在tian-service中pom.xml添加:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-rar-plugin</artifactId>
</plugin>
最后在parent中执行clean package:
可以看到rar里面有依赖jar和三个子项目的jar