准备工作

  1. 先期准备
    老规矩,还是来看看项目构建的目录机构图,首先这个项目是由四个子项目组成:

    可以看到其他三个项目中都是有各种类的,tian-parent中只有一个pom.xml,这是因为,这个项目是用来做聚合和继承来使用的,聚合值得是把其他三个项目组合到一起,继承是指,其他三个项目有选择地继承这个项目的部分的包依赖。
  2. 项目的组成
    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>

如下是结构示意图

maven聚合工程显示项目图谱_maven


运行clean package打包,编译测试打包完成。tian-service项目开开发

maven聚合工程显示项目图谱_hibernate_02


如上图是结构示意图。

本子项目的单独开发,利用了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命令就可看到三个模块的编译、测试、打包过程,图如下所示:

maven聚合工程显示项目图谱_maven_03

打包成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:

maven聚合工程显示项目图谱_java_04

可以看到rar里面有依赖jar和三个子项目的jar

maven聚合工程显示项目图谱_java_05