前面介绍了基于 Archiva 的私服搭建工作,现在全项目组就可以在私服下共用 Maven 开发环境了。
接下来在 Maven 环境下,基于 Struts2+Spring4.2+Hibernate4.1 框架,体验 Web 应用的开发过程。为了展现 Maven 开发的优势,将按如下步骤进行。
基于 MyEclipse 的 maven-archetype-quickstart 创建 Maven 工程(同前面创建基本的 Maven 工程一样)。因为用的是公共 POM 模块,这里不需要写代码,只需将 Hibernate 和相关的依赖配置在 pom.xml 中,并且在 pom.xml 中将 packaging 方式设置成 pom,表示是一个公共的父 pom。代码如下:
- <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>cn.com.mvn.ssh.pom</groupId>
- <artifactId>Hibernate4MySQLPOM</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
- <name>Hibernate4MySQLPOM</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.7</version>
- <scope>test</scope>
- </dependency>
- <!--hibernate -->
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- <version>${project.build.hibernate.version}</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-ehcache</artifactId>
- <version>${project.build.hibernate.version}</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate.javax.persistence</groupId>
- <artifactId>hibernate-jpa-2.0-api</artifactId>
- <version>1.0.0.Final</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.34</version>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/internal</url>
- </repository>
- <snapshotRepository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/snapshots</url>
- </snapshotRepository>
- </distributionManagement>
- </project>
注意 pom.xml 中的第 9 行,<packaging>pom</packaging>表示当前的 pom 是一个独立的 pom 父模块,可以独立安装到仓库中,被其他工程继承使用。
同时注意最后的 distributionManagement 配置,该配置可以让工程以构件的形式发布到指定的私服。
右击“工程”,选择 Run As→Maven install 命令,就可以把当前 pom 安装到前面搭建好 Archiva 私服。安装后,可以在 Archiva 管理界面的 Browse 导航页中,看到 Hibernate4MySQLPOM 构件。
同前面 Hibernate 的 POM 创建一样,可以创建基于 Spring 的 POM 公共构件模块。具体工程创建就不演示了,直接复制到 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>cn.com.mvn.pom</groupId>
- <artifactId>SpringPOM</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
- <name>SpringPOM</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <!-- 3.2.16.RELEASE,3.1.4.RELEASE -->
- <project.build.spring.version>4.2.7.RELEASE
- </project.build.spring.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.7</version>
- <scope>test</scope>
- </dependency>
- <!-- spring -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-core</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aop</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-beans</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aspects</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-orm</artifactId>
- <version>${project.build.spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-validator</artifactId>
- <version>5.0.0.Final</version>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/internal</url>
- </repository>
- <snapshotRepository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/snapshots</url>
- </snapshotRepository>
- </distributionManagement>
- </project>
同样注意粗体提示部分。右击“工程”,选择 Run As→Maven install 命令,安装 POM 构件。
重复前面的流程,直接复制 pom.xml 代码和安装 pom 后的管理界面。需要注意,在 pom.xml 中,除了 Struts 的依赖之外,还有 jsp/servlet 的依赖和 Struts 同 Spring 集成的插件依赖。
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>cn.com.mvn.pom</groupId>
- <artifactId>StrutsPOM</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
- <name>StrutsPOM</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <!-- jsp servlet -->
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet.jsp</groupId>
- <artifactId>jsp-api</artifactId>
- <version>2.1</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>jstl</artifactId>
- <version>1.2</version>
- </dependency>
- <!-- struts2 -->
- <!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-core -->
- <dependency>
- <groupId>org.apache.struts</groupId>
- <artifactId>struts2-core</artifactId>
- <version>2.3.16</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-spring-plugin -->
- <dependency>
- <groupId>org.apache.struts</groupId>
- <artifactId>struts2-spring-plugin</artifactId>
- <version>2.3.4.1</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.7</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/internal</url>
- </repository>
- <snapshotRepository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/snapshots</url>
- </snapshotRepository>
- </distributionManagement>
- </project>
在实际项目中,一般会使用面向接口编程,从而实现调用者和被调用者的完全解耦,方便项目的团队开发和后期的扩展。鉴于这样的考虑,Hibernate 持久层的实现分两步进行:第 1 步定义公共 DAO 接口和类;第 2 步基于 Hibernate 完成 DAO 接口的实现。详细介绍如下。
创建一个普通的 Maven 工程:MvnSSHDemo.DAO。目录结构如图 1 所示。
图 1 DAO项目结构
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>cn.com.mvn.ssh.demo</groupId>
- <artifactId>MvnSSHDemo.DAO</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>MvnSSHDemo.DAO</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.7</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/internal</url>
- </repository>
- <snapshotRepository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/snapshots</url>
- </snapshotRepository>
- </distributionManagement>
- </project>
这里有两类代码:一类是实体类(MvnUser),另一类是实体 DAO 接口(IMvnUserDAO)。因为 MvnUser 里面有个状态(status)属性,定义了一个枚举状态类(Status)。具体内容如下。
1)Status.java 代码如下所示:
- package cn.com.mvn.ssh.demo.entity;
- public enum Status {
- ACTIVE("Active"), INACTIVE("Inactive"), DELETED("Deleted"), LOCKED("Locked");
- private String status;
- private Status(final String status) {
- this.status = status;
- }
- public String getStatus() {
- return status;
- }
- public void setStatus(String status) {
- this.status = status;
- }
- public String toString() {
- return this.status;
- }
- }
2)MvnUser.java 如下所示:
- package cn.com.mvn.ssh.demo.entity;
- public class MvnUser {
- private int urId;
- private String urUserName;
- private String urPassword;
- private int urAge;
- private String urStatus = Status.ACTIVE.getStatus();// Active
- public int getUrId() {
- return urId;
- }
- public void setUrId(int urId) {
- this.urId = urId;
- }
- public String getUrUserName() {
- return urUserName;
- }
- public void setUrUserName(String urUserName) {
- this.urUserName = urUserName;
- }
- public String getUrPassword() {
- return urPassword;
- }
- public void setUrPassword(String urPassword) {
- this.urPassword = urPassword;
- }
- public int getUrAge() {
- return urAge;
- }
- public void setUrAge(int urAge) {
- this.urAge = urAge;
- }
- public String getUrStatus() {
- return urStatus;
- }
- public void setUrStatus(String urStatus) {
- this.urStatus = urStatus;
- }
- }
3)IMvnUserDAO.java 代码如下所示:
- package cn.com.mvn.ssh.demo.dao;
- import java.util.List;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- /**
- * MvnUser实体对象的持久层代码,封装了对MvnUser实体对象的CRUD方法
- *
- * @author Noble
- * @version 1.0
- */
- public interface IMvnUserDAO {
- /**
- * 在数据库中,添加一个新的MvnUser对象
- *
- * @param user 需要添加的用户实体对象,该对象需要有用户名、密码、年龄和状态属性
- *
- * @return void
- * @throws RuntimeException 添加失败或出现其它意外
- */
- public void addUser(MvnUser user);
- /**
- * 更新MvnUser对象。该对象中需要设置年龄、状态和id属性,属性和状态是要更新的新值,id为条件
- *
- * @param user 需要更新的MvnUser对象
- *
- * @return void
- * @throws RuntimeException 更新失败或出现其它意外
- */
- public void update(MvnUser user);
- /**
- * 删除MvnUser对象,该对象中需要有要删除对象的id属性,id属性为删除条件
- *
- * @param user 要删除的MvnUser对象
- *
- * @return void
- * @throws RuntimeException 删除失败或出现其它意外
- */
- public void deleteUser(MvnUser user);
- /**
- * 根据id查询对应的MvnUser对象
- *
- * @param id 要查询的MvnUser对象的id
- * @return MvnUser id对应的MvnUser对象,如果没有对象,返回null
- * @throws RuntimeException 出现意外情况
- */
- public MvnUser findUserById(int id);
- /**
- * 根据用户名查询对应的MvnUser对象
- *
- * @param userName 要查询的MvnUser对象的用户名
- * @return MvnUser 用户对应的MvnUser对象,如果没有对象,返回null
- * @throws RuntimeException 出现意外情况
- */
- public MvnUser findUserByUserName(String userName);
- /**
- * 查找数据库中所有的用户对象,以List集合的形式返回
- *
- * @return List<MvnUser> 所有用户对象的集合
- * @throws RuntimeException 出现意外情况
- */
- public List<MvnUser> findUsers();
- }
右击“工程”,选择 Run As→Maven install 命令,MyEclipse 会自动将工程代码编译打包。如果没有错误,最后会以构件的形式安装在本地仓库中。结果如图 5 所示。
为了方便公司其他开发人员使用,接下来将该项目以构件的形式发布到前面搭建好的私服。为了使发布成功,请按前面的私服介绍搭建并启动私服,同时在当前工程的 pom.xml 中,添加 distributionManagement 配置,详细参考前面的 pom.xml。具体操作和效果图如下所示。
右击“工程”,选择 Run As→Maven build… 命令。
在 Goals 中输入 deploy,单击 Run 按钮。
团队商量确定好接口,接下来就是对接口的实现和基于接口上的开发工作了。因为有共同的接口,所以这两个工作可以同步进行。这种现象同计算机配件一样(硬盘、内存、CPU、显卡等),事先定义好标准(插口),不同厂商就可以按同样的标准各自生产,然后顺利组装在一起,不用管是哪个厂家、在哪里、用哪条流水线生产的。
接下来介绍 DAO 接口的实现,分以下 4 步进行。
这个步骤比较简单,创建工程的方式同以前一样,具体创建过程不重复,项目结构如图 2 所示。
图 2 Hibernate DAO项目结构
注意如下:
① 因为前面创建了公共的 Hibernate POM 工程,里面有描述好了 Hibernate 相关的依赖(目的是让所有开发人员重用,不再重复编写),并且以构件的形式安装发布好了。这里要体现的是怎样继承前面定义好的 pom。
② 同样地,因为新工程里面要实现 MvnSSHDemo.DAO 中定义的接口,并且用到里面定义的公共类,而且根据前面的介绍,MvnSSHDemo.DAO,也以构件的形式安装发布到私服中了。在这里,要介绍一下怎样在自己的工程里面设置团队内部发布的构件。
这两点注意事项主要体现在 pom.xml 中,pom.xml 内容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <project
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
- xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>cn.com.mvn.pom</groupId>
- <artifactId>Hibernate4MySQLPOM</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <groupId>cn.com.mvn.ssh.demo.dao.hibernate</groupId>
- <artifactId>MvnSSHDemo.DAO.Hibernate</artifactId>
- <name>MvnSSHDemo.DAO.Hibernate</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>cn.com.mvn.ssh.demo</groupId>
- <artifactId>MvnSSHDemo.DAO</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>cn.com.mvn.pom</groupId>
- <artifactId>SpringPOM</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <type>pom</type>
- </dependency>
- </dependencies>
- <distributionManagement>
- <repository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/internal</url>
- </repository>
- <snapshotRepository>
- <id>archivaServer</id>
- <url>http://localhost:8080/repository/snapshots</url>
- </snapshotRepository>
- </distributionManagement>
- </project>
其中 7~11 行,它描述的是当前的 pom.xml,继承了 Hibernate4-MySQLPOM 构件中定义的 pom 内容,其中 groupId、artifactId 和 version 共同形成构件的坐标。
当 pom 需要继承别人定义好的 pom 时,只需要使用如上 parent 配置指定就行。不过这里的继承同 Java 中继承一样,只能单继承,而且只能继承 packaging 类型为 pom 的构件(这点可以看 Hibernate4MySQLPOM 中的 pom.xml 文件,里面的 packaging 是 pom)。
20~30 行,描述的是两个依赖。第 1 个依赖是前面定义的 DAO 接口和公共类的构件依赖。通过查看代码,其实同使用从网上找的其他依赖一样。
第 2 个虽然也是使用前面定义的 Spring 的公共 pom 依赖,但是有点不同,里面包含了一个<type>pom</type>,这个元素指定的是依赖的 packaging 类型。
依赖的 packaging 类型默认是 jar(前面所有 pom.xml 中没有指定 type 的情况),如果 pom 引用的依赖是 pom 类型,就需要在 dependency 中添加 type 元素,指定是类型 pom,形同这里用到的第 2 个依赖,否则构建的时候会报错。
基于 Hibernate 的 DAO 实现代码主要有如下几个类。
① MvnUser4Hibernate.java,该类继承了 MvnUser 类,里面用注解描述了实体信息,代码如下所示。
- package cn.com.mvn.ssh.demo.entity.hibernate;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- @Entity
- @Table(catalog = "mvn_db", name = "mvn_user")
- public class MvnUser4Hibernate extends MvnUser {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "ur_id")
- public int getUrId() {
- // TODO Auto-generated method stub
- return super.getUrId();
- }
- @Column(name = "ur_user_name", length = 20, unique = true, nullable = false)
- public String getUrUserName() {
- // TODO Auto-generated method stub
- return super.getUrUserName();
- }
- @Column(name = "ur_password", length = 10, nullable = false)
- public String getUrPassword() {
- // TODO Auto-generated method stub
- return super.getUrPassword();
- }
- @Column(name = "ur_age")
- public int getUrAge() {
- // TODO Auto-generated method stub
- return super.getUrAge();
- }
- @Column(name = "ur_status", length = 20, nullable = true)
- public String getUrStatus() {
- // TODO Auto-generated method stub
- return super.getUrStatus();
- }
- }
② AbstractDAO.java,该类定义了实体的公共持久化方法,所有的 DAO 实现类就继承它,代码如下所示。
- package cn.com.mvn.ssh.demo.dao.hibernate;
- import java.io.Serializable;
- import java.lang.reflect.ParameterizedType;
- import java.util.List;
- import org.hibernate.Criteria;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- import cn.com.mvn.ssh.demo.entity.hibernate.MvnUser4Hibernate;
- public abstract class AbstractDAO<PK extends Serializable, T> {
- private final Class<T> persistentClass;
- @SuppressWarnings("unchecked")
- public AbstractDAO() {
- this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
- .getActualTypeArguments()[1];
- }
- @Autowired
- private SessionFactory sessionFactory;
- protected Session getSession() {
- return sessionFactory.getCurrentSession();
- }
- @SuppressWarnings("unchecked")
- public T getByKey(PK key) {
- return (T) getSession().get(persistentClass, key);
- }
- public void persist(T entity) {
- getSession().persist(entity);
- }
- public void delete(T entity) {
- getSession().delete(entity);
- }
- public void update(T entity) {
- getSession().merge(entity);
- }
- public List<T> findAll() {
- Criteria cri = this.createEntityCriteria();
- cri.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);// 消除重复对象
- return cri.list();
- }
- protected Criteria createEntityCriteria() {
- return getSession().createCriteria(persistentClass);
- }
- }
③ MvnUserDAOImpl.java,该类实现了 MvnUser 实体类的所有持久化方法,代码如下所示。
- package cn.com.mvn.ssh.demo.dao.hibernate.impl;
- import java.util.List;
- import org.hibernate.Criteria;
- import org.hibernate.criterion.Restrictions;
- import org.springframework.stereotype.Repository;
- import org.springframework.transaction.annotation.Transactional;
- import cn.com.mvn.ssh.demo.dao.IMvnUserDAO;
- import cn.com.mvn.ssh.demo.dao.hibernate.AbstractDAO;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- import cn.com.mvn.ssh.demo.entity.hibernate.MvnUser4Hibernate;
- @Repository("userDAO")
- @Transactional // 标记使用事务,为了方便DAO设置,是临时的,正式事务应该设置在服务层
- public class MvnUserDAOImpl extends AbstractDAO<Integer, MvnUser4Hibernate> implements IMvnUserDAO {
- public void addUser(MvnUser user) {
- MvnUser4Hibernate u = this.convertToMvnUser4Hibernate(user);
- super.persist(u);
- }
- public void update(MvnUser user) {
- MvnUser4Hibernate u = this.convertToMvnUser4Hibernate(user);
- super.update(u);
- }
- public void deleteUser(MvnUser user) {
- MvnUser4Hibernate u = this.convertToMvnUser4Hibernate(user);
- super.delete(u);
- }
- public MvnUser findUserById(int id) {
- return super.getByKey(id);
- }
- public MvnUser findUserByUserName(String userName) {
- Criteria criteria = super.createEntityCriteria();
- criteria.add(Restrictions.eq("urUserName", userName));
- return (MvnUser) criteria.uniqueResult();
- }
- public List<MvnUser> findUsers() {
- Criteria criteria = super.createEntityCriteria();
- return criteria.list();
- }
- private MvnUser4Hibernate convertToMvnUser4Hibernate(MvnUser user) {
- MvnUser4Hibernate u = (MvnUser4Hibernate) this.findUserById(user.getUrId());
- // 这里不要轻易new一个同已经存在的一样的对象,否则会抛
- // org.hibernate.NonUniqueObjectException:
- // a different object with the same identifier value was
- // already associated withthe session异常
- if (u == null) {
- u = new MvnUser4Hibernate();
- u.setUrId(user.getUrId());
- }
- u.setUrAge(user.getUrAge());
- u.setUrPassword(user.getUrPassword());
- u.setUrStatus(user.getUrStatus());
- u.setUrUserName(user.getUrUserName());
- return u;
- }
- }
④ HibernateConfiguration.java,Hibernate 的配置类,描述 Hibernate 的配置信息,代替 hibernate.cfg.xml,代码如下所示。
- package cn.com.mvn.ssh.demo.dao.hibernate.config;
- import java.util.Properties;
- import javax.sql.DataSource;
- import org.hibernate.SessionFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.ComponentScan;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.PropertySource;
- import org.springframework.core.env.Environment;
- import org.springframework.jdbc.datasource.DriverManagerDataSource;
- import org.springframework.orm.hibernate4.HibernateTransactionManager;
- import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
- import org.springframework.transaction.annotation.EnableTransactionManagement;
- //配置类
- @Configuration
- @EnableTransactionManagement // 要支持事务管理
- @ComponentScan({ "cn.com.mvn.ssh.demo.dao.hibernate.config" })
- @PropertySource(value = { "classpath:db.properties" }) // 自动读入的属性文件
- public class HibernateConfiguration {
- // 自动注入 Spring的环境对象(上下文)
- @Autowired
- private Environment environment;
- // 创建一个SessionFactory
- @Bean(name = "sessionFactory")
- public LocalSessionFactoryBean sessionFactory() {
- LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
- // 数据源
- sessionFactory.setDataSource(dataSource());
- // 指定数据实体类的包
- sessionFactory.setPackagesToScan(new String[] { "cn.com.mvn.ssh.demo.entity.hibernate" });
- // hibernate的属性信息
- sessionFactory.setHibernateProperties(hibernateProperties());
- return sessionFactory;
- }
- // 初始化数据源对象
- @Bean(name = "dataSource") // 将当前方法返回的对象,当成普通Bean对象,放入IOC容器中
- public DataSource dataSource() {
- DriverManagerDataSource dataSource = new DriverManagerDataSource();
- // 设置连接数据库的四要素
- dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
- dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
- dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
- dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
- return dataSource;
- }
- // 将Hibernate除连接数据库之外的配置,封装到Properties
- private Properties hibernateProperties() {
- Properties properties = new Properties();
- properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
- properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
- properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
- properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
- return properties;
- }
- @Bean
- @Autowired
- public HibernateTransactionManager transactionManager(SessionFactory s) {
- HibernateTransactionManager txManager = new HibernateTransactionManager();
- txManager.setSessionFactory(s);
- return txManager;
- }
- }
⑤ db.properties,描述数据库连接信息和 Hibernate 的一些配置信息,代码如下所示。
测试代码基于 JUnit,相对比较简单,只有一个类,针对 MvnUserDAOImpl.java 进行测试,另外还有一个 Spring 的配置文件 applicationContext.xml。
需要注意的是,测试的所有代码和资源文件,都分别放在 src/test 目录下对应的子目录中。在 Maven 中具体文件的存放位置是固定的。测试代码和配置文件的内容如下所示。
① TestMvnUserDAOImpl.java 代码如下所示:
- package cn.com.mvn.ssh.demo.dao.hibernate.impl;
- import org.junit.After;
- import org.junit.Before;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import cn.com.mvn.ssh.demo.dao.IMvnUserDAO;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- import cn.com.mvn.ssh.demo.entity.Status;
- import junit.framework.Assert;
- public class TestMvnUserDAOImpl {
- private IMvnUserDAO userDAO;
- private ApplicationContext ctx = null;
- @Before
- public void init() {
- ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- userDAO = (IMvnUserDAO) this.ctx.getBean("userDAO");
- // userDAO = (IMvnUserDAO) this.ctx.getBean(MvnUserDAOImpl.class);
- }
- @Test
- public void testAddUser() {
- MvnUser user = new MvnUser();
- user.setUrAge(11);
- user.setUrPassword("11");
- user.setUrStatus(Status.ACTIVE.getStatus());
- user.setUrUserName("userName11");
- this.userDAO.addUser(user);
- MvnUser u = this.userDAO.findUserByUserName("userName11");
- Assert.assertTrue(u != null && u.getUrAge() == 11);
- this.userDAO.deleteUser(u);
- }
- @Test
- public void testFindUserById() {
- MvnUser user = this.userDAO.findUserById(1);
- Assert.assertEquals("zhangsan", user.getUrUserName());
- }
- @Test
- public void testUpdate() {
- MvnUser user = this.userDAO.findUserById(1);
- user.setUrAge(99);
- this.userDAO.update(user);
- user = this.userDAO.findUserById(1);
- Assert.assertEquals(99, user.getUrAge());
- }
- @After
- public void destory() {
- this.userDAO = null;
- this.ctx = null;
- }
- }
② applicationContext.xml 代码如下所示。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <!--spring自动扫描组件类的包,包括子包和子子包等 -->
- <context:component-scan
- base-package="cn.com.mvn.ssh.demo"></context:component-scan>
- </beans>
右击“工程”,选择 Run As→Maven test 命令,Maven 会自动对 JUnit 写的测试代码进行测试,并且显示测试结果。
右击“工程”,选择 Run As→Maven install 命令,Maven 会自动将工程代码编译,运行完测试代码,通过后,打包成构件,发布到本地仓库。
右击“工程”,选择 Run As→Maven build… 命令,在弹出框的 Goals 输入框中输入 deploy,单击 Run 按钮,Maven 会自动将工程构件发布到指定的私服仓库。需要注意,一定要在 pom.xml 中配置 distributionManagement.
同 DAO 层定义的接口类似,先将 Service 的接口定义好,并且发布成一个单独的构件,在自己的计算机上创建一个新的工程,继承 SpringPOM,集成 DAO 接口的依赖和 Service 接口的依赖,独立进行 Service 的实现代码编写和测试。
因为要对 Service 实现方法进行测试,编码的时候可以面向接口编程。测试的时候,肯定要基于 DAO 的实现才能操作数据库。所以在测试的时候还需要额外添加前面 Hibernate 的 DAO 实现依赖,不过该依赖的 score 是 test,即只在测试的时候有效。详细情况请注意接下来介绍的工程 pom.xml 中的备注。
下面按类似 Hibernate 的 DAO 实现的思路,介绍 Service 的实现模块。
同之前一样,创建一个 Maven 工程,工程目录结构如图 3 所示。
图 3 Maven Service项目结构
根据本节开始的介绍,需要在 pom.xml 中做如下设置。
请查看如下 pom.xml,注意加粗部分内容和注释,细心的读者会发现里面没有添加 DAO 接口的构件依赖,只添加 Service 接口的构件依赖,同前面介绍的第 2 点要求不符合。
原因是 Service 接口构件内部有配置好对应 DAO 接口构件的依赖,只要在这里配置 Service 接口构件的依赖,Maven 会在加载 Service 接口构件依赖的同时,自动地连带着将 Service 接口构件内部所需要的其他依赖加进来。
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>
- <!--继承SpringPOM构件 -->
- <parent>
- <groupId>cn.com.mvn.pom</groupId>
- <artifactId>SpringPOM</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <groupId>cn.com.mvn.ssh.demo</groupId>
- <artifactId>MvnSSHDemo.Service.impl</artifactId>
- <packaging>jar</packaging>
- <name>MvnSSHDemo.Service.impl</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <!--Service接口构件依赖 -->
- <dependency>
- <groupId>cn.com.mvn.ssh.demo</groupId>
- <artifactId>MvnSSHDemo.Service</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
- <!--Hibernate DAO实现构件依赖 -->
- <dependency>
- <groupId>cn.com.mvn.ssh.demo.dao.hibernate</groupId>
- <artifactId>MvnSSHDemo.DAO.Hibernate</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <!--作用范围 -->
- <scope>test</scope>
- </dependency>
- </dependencies>
- </project>
Service 的实现代码相对比较简单,只是要有 Spring 容器管理相关的基础,因为里面用到 Spring 内部的组件注解、依赖注入注解和事务管理注解,详情请看代码和 Spring 相关的资料。
- package cn.com.mvn.ssh.demo.service.impl;
- import java.util.List;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- import cn.com.mvn.ssh.demo.dao.IMvnUserDAO;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- import cn.com.mvn.ssh.demo.service.IUserService;
- @Service("userService") // 注册成服务组件
- @Transactional // 要求启动事务
- public class UserServiceImpl implements IUserService {
- @Autowired // 自动根据类型注入
- @Qualifier("userDAO") // 根据name注入
- private IMvnUserDAO userDAO;
- @Transactional(propagation = Propagation.REQUIRED) // 需要進行事务管理
- public void createUser(MvnUser user) {
- // 验证输入的用户是否为null
- if (user == null) {
- throw new RuntimeException("创建的user不能为null");
- }
- // 验证用户名是否有存在
- MvnUser u = this.userDAO.findUserByUserName(user.getUrUserName());
- if (u != null) {
- throw new RuntimeException(u.getUrUserName() + " 已经存在");
- }
- this.userDAO.addUser(user);
- }
- @Transactional(propagation = Propagation.REQUIRED) // 需要進行事务管理
- public void editUser(int age, String status, int id) {
- // 根据id找到以前的用户对象
- MvnUser user = this.userDAO.findUserById(id);
- // 判断用户是否存在,不存在抛异常,存在就更新
- if (user == null) {
- throw new RuntimeException("id为" + id + "用户不存在");
- } else {
- user.setUrAge(age);
- user.setUrStatus(status);
- this.userDAO.update(user);
- }
- }
- @Transactional(propagation = Propagation.REQUIRED) // 需要進行事务管理
- public void deleteUser(int id) {
- // 根据id找到以前的用户对象
- MvnUser user = this.userDAO.findUserById(id);
- // 判断用户是否存在,不存在抛异常,存在就删除
- if (user == null) {
- throw new RuntimeException("id为" + id + "用户不存在");
- } else {
- this.userDAO.deleteUser(user);
- }
- }
- @Transactional(readOnly = true) // 只读,不需要进行事务管理
- public MvnUser searchUser(int id) {
- MvnUser user = null;
- user = this.userDAO.findUserById(id);
- return user;
- }
- @Transactional(readOnly = true) // 只读,不需要进行事务管理
- public MvnUser searchUser(String userName) {
- MvnUser user = null;
- user = this.userDAO.findUserByUserName(userName);
- return user;
- }
- @Transactional(readOnly = true) // 只读,不需要进行事务管理
- public List<MvnUser> searchUsers() {
- List<MvnUser> userList = null;
- userList = this.userDAO.findUsers();
- return userList;
- }
- }
因为测试代码的测试环境是依赖 Spring 容器的,所以测试部分的内容除了有针对 UserServiceImpl.java 的测试案例类之外,还需要配置一个 applicationContext.xml。而且还要注意,不管是测试类还是测试资源,都需要放在 src/test 的对应子目录下。
① TestUserServiceImpl.java 代码如下所示:
- package cn.com.mvn.ssh.demo.service.impl;
- import java.util.List;
- import org.junit.After;
- import org.junit.Before;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import cn.com.mvn.ssh.demo.entity.MvnUser;
- import cn.com.mvn.ssh.demo.entity.Status;
- import cn.com.mvn.ssh.demo.service.IUserService;
- import junit.framework.Assert;
- public class TestUserServiceImpl {
- private IUserService userService;
- private ApplicationContext ctx = null;
- @Before
- public void init() {
- this.ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- this.userService = (IUserService) ctx.getBean("userService");
- }
- @Test
- public void testCreateUser() {
- MvnUser user = new MvnUser();
- user.setUrAge(11);
- user.setUrPassword("11");
- user.setUrStatus(Status.ACTIVE.getStatus());
- user.setUrUserName("service1");
- this.userService.createUser(user);
- MvnUser u = this.userService.searchUser("service1");
- boolean bool = u != null && u.getUrAge() == 11 && u.getUrStatus().equals(Status.ACTIVE.getStatus());
- Assert.assertTrue(bool);
- // 删除用户
- this.userService.deleteUser(u.getUrId());
- }
- @Test
- public void testEditUser() {
- MvnUser user = new MvnUser();
- user.setUrAge(11);
- user.setUrPassword("11");
- user.setUrStatus(Status.ACTIVE.getStatus());
- user.setUrUserName("service1");
- this.userService.createUser(user);
- MvnUser u = this.userService.searchUser("service1");
- this.userService.editUser(88, Status.INACTIVE.getStatus(), u.getUrId());
- u = this.userService.searchUser("service1");
- Assert.assertTrue(u.getUrAge() == 88 && u.getUrStatus().equals(Status.INACTIVE.getStatus()));
- this.userService.deleteUser(u.getUrId());
- }
- @Test
- public void testDeleteUser() {
- MvnUser user = new MvnUser();
- user.setUrAge(11);
- user.setUrPassword("11");
- user.setUrStatus(Status.ACTIVE.getStatus());
- user.setUrUserName("service1");
- this.userService.createUser(user);
- MvnUser u = this.userService.searchUser("service1");
- this.userService.deleteUser(u.getUrId());
- MvnUser u2 = this.userService.searchUser(u.getUrId());
- Assert.assertTrue(u != null && u2 == null);
- }
- @Test
- public void testSearchUserById() {
- MvnUser user = this.userService.searchUser(1);
- Assert.assertNotNull(user);
- }
- @Test
- public void testSearchUserByUserName() {
- MvnUser user = this.userService.searchUser("zhangsan");
- Assert.assertNotNull(user);
- }
- @Test
- public void testSearchUsers() {
- List<MvnUser> userList = this.userService.searchUsers();
- Assert.assertTrue(userList != null && userList.size() > 0);
- }
- @After
- public void destory() {
- this.userService = null;
- this.ctx = null;
- }
- }
2)applicationContext.xml 代码如下所示:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <context:component-scan base-package="cn.com.mvn.ssh.demo"/>
- </beans>
这里的测试安装和发布同 Hibernate DAO 实现里面的一样。右击“工程”,选择 Run As→Maven test 命令。
由于篇幅有限,请看下一节《Maven搭建SSH框架(二)》继续阅读。