欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

maven快速入门第十三讲——使用maven整合SSH

程序员文章站 2022-07-14 11:10:07
...

前言

在本讲中,我会使用maven来整合Hibernate-5.0.7.Final、Struts-2.3.24和Spring-4.2.4.RELEASE这三个框架,实现从数据库中查询所有客户的需求。

在正式编写代码实现这个需求之前,我们得做一些准备工作,提前创建一个数据库(例如s2sh_crm),并在该数据库下新建一张客户表,这里笔者使用的数据库是MySQL。

create database s2sh_crm;
use s2sh_crm;

CREATE TABLE `cst_customer` (
	`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
	`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
	`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
	`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
	`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
	`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
	`cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
	PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

经过前面几讲的学习:

想必你已经可以创建出一个如下结构的聚合工程了。
maven快速入门第十三讲——使用maven整合SSH
在使用maven整合SSH时,需要依赖struts-2.3.24、spring-framework-4.2.4.RELEASE以及hibernate-5.0.7.Final等,于是我们会在父工程的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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.meimeixia</groupId>
	<artifactId>crm-parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>
	
	<!-- 父工程下所包含的子模块(工程) -->
	<modules>
		<module>crm-dao</module>
		<module>crm-service</module>
		<module>crm-web</module>
	</modules>
	
	<!-- 定义版本常量 -->
	<properties>
		<spring.version>4.2.4.RELEASE</spring.version>
		<struts.verison>2.3.24</struts.verison>
		<hibernate.version>5.0.7.Final</hibernate.version>
	</properties>
	
	<dependencies>
		<!-- Struts2核心依赖 -->
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-core</artifactId>
			<version>${struts.verison}</version>
			<!-- 排除依赖 -->
			<exclusions>
				<exclusion>
					<artifactId>javassist</artifactId>
					<groupId>javassist</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- Hibernate核心依赖 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<!-- 下面这个会引入spring-beans-4.2.2.RELEASE.jar -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.2.2.RELEASE</version>
		</dependency>
		<!-- 下面这个会引入spring-beans-3.0.5.RELEASE.jar -->
		<!-- Struts2和Spring整合依赖 -->
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-spring-plugin</artifactId>
			<version>${struts.verison}</version>
		</dependency>
		<!-- 依赖管理的第二个原则:路径近者优先原则 -->
		<!-- 这个spring-beans-${spring.version}版本的jar包放到最后面去了,但是它还是生效了。那这是为啥啊? -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- Spring核心依赖 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-core</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		<!-- 有事务的时候,我们就需要用到了,例如去声明事务、做事务注解等 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-context-support</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		<!-- 切面 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-aop</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		<!-- 声明式事务 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-tx</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		<!-- Spring整合ORM框架依赖 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-orm</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-web</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		<dependency>
		    <groupId>org.aspectj</groupId>
		    <artifactId>aspectjweaver</artifactId>
		    <version>1.8.7</version>
		</dependency>
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-api</artifactId>
		    <version>1.7.12</version>
		</dependency>
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-log4j12</artifactId>
		    <version>1.7.12</version>
		</dependency>
		<!-- MySQL数据库驱动 -->
		<dependency>
		    <groupId>mysql</groupId>
		    <artifactId>mysql-connector-java</artifactId>
		    <version>5.1.48</version>
		    <scope>runtime</scope>
		</dependency>
		<!-- c3p0连接池 -->
		<dependency>
		    <groupId>com.mchange</groupId>
		    <artifactId>c3p0</artifactId>
		    <version>0.9.5.5</version>
		</dependency>
		<dependency>
		    <groupId>jstl</groupId>
		    <artifactId>jstl</artifactId>
		    <version>1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	
	<!-- 版本锁定 -->
	<dependencyManagement>
		<!-- 在这里锁定junit的版本为4.9 -->
		<dependencies>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>4.9</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	
	<build>
		<plugins>
			<!-- 设置编译版本为1.8 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
	                <!-- 源码版本 -->
	                <source>1.8</source>
	                <!-- 编译目标版本 -->
	                <target>1.8</target>
	                <!-- 指定编码 -->
	                <encoding>utf-8</encoding>
	            </configuration>
			</plugin>
			<!-- 配置tomcat插件 -->
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
				<configuration>
					<!-- 配置访问端口 -->
					<port>8080</port>
					<!-- 访问的项目路径 -->
					<path>/crm</path>
					<!-- 
						编码,为什么加这个编码呢?大家都知道,我们使用网络传输的时候,默认情况下使用的是iso8859-1编码
						(提交请求的时候,特别是使用get请求的时候),所以要进行一个编码转换! 
					-->
					<uriEncoding>utf-8</uriEncoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

从中可以看出父工程的pom.xml文件中抽取了一些重复的配置,比如:锁定jar包的版本、设置编译版本等,也可以看出子工程中要用到的依赖都在父工程的pom.xml文件中先定义好了,将来子工程在开发的时候就不需要再引坐标了。

温馨提示:此处并没有添加junit的依赖,只是锁定了junit的版本为4.9,各个子工程开发完毕之后,在编写JUnit单元测试用例时,还需要在其pom.xml文件中添加junit的依赖。

crm-dao子模块的开发与测试

创建Customer实体类和其相对应的映射配置文件

首先,在src/main/java目录下新建一个com.meimeixia.crm.domain包,并在该包下创建一个Customer实体类。

package com.meimeixia.crm.domain;

import java.io.Serializable;

/**
 * PO(Persistence Object):持久化类
 * 持久化类有如下7个规范:
 * 1. 公有类
 * 2. 公有无参构造
 * 3. 私有属性
 * 4. 公有的getter与setter
 * 5. 实现java.io.Serializable接口
 * 6. 不能用final修饰
 * 7. 如果是基础类型,要使用它的包装类 
 * 
 * @author liayun
 *
 */
public class Customer implements Serializable {

	private static final long serialVersionUID = 1L;//加上也行,不加也行
	
	private Long custId;
	private String custName;
	private String custSource;
	private String custIndustry;
	private String custLevel;
	private String custPhone;
	private String custMobile;
	
	public Long getCustId() {
		return custId;
	}
	public void setCustId(Long custId) {
		this.custId = custId;
	}
	public String getCustName() {
		return custName;
	}
	public void setCustName(String custName) {
		this.custName = custName;
	}
	public String getCustSource() {
		return custSource;
	}
	public void setCustSource(String custSource) {
		this.custSource = custSource;
	}
	public String getCustIndustry() {
		return custIndustry;
	}
	public void setCustIndustry(String custIndustry) {
		this.custIndustry = custIndustry;
	}
	public String getCustLevel() {
		return custLevel;
	}
	public void setCustLevel(String custLevel) {
		this.custLevel = custLevel;
	}
	public String getCustPhone() {
		return custPhone;
	}
	public void setCustPhone(String custPhone) {
		this.custPhone = custPhone;
	}
	public String getCustMobile() {
		return custMobile;
	}
	public void setCustMobile(String custMobile) {
		this.custMobile = custMobile;
	}
	
}

然后,我们就要创建一个与以上实体类相对应的映射配置文件了,即Customer.hbm.xml。你有没想过,这个映射配置文件应该放置在哪儿呢?那肯定是放在src/main/resources目录下。之前都是将这样的映射配置文件与其相对应的实体类放在同一个包下,所以我们也可以在src/main/resources目录下新建一个com.meimeixia.crm.domain包,并在该包下创建一个Customer.hbm.xml映射配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
<hibernate-mapping>
	<class name="com.meimeixia.crm.domain.Customer" table="cst_customer" >
        <id name="custId" type="java.lang.Long">
            <column name="cust_id" />
            <!-- 6种生成策略:identity、native、sequence、uuid、increment、assigned -->
        </id>
      
        <property name="custName" type="string">
            <column name="cust_name" length="32" not-null="true"></column>
        </property>
        <property name="custSource" column="cust_source"></property>
        <property name="custIndustry" column="cust_industry"></property>
        <property name="custLevel" column="cust_level"></property>
        <property name="custPhone" type="string">
            <column name="cust_phone" length="64"></column>
        </property>
        <property name="custMobile" type="string">
            <column name="cust_mobile" length="16"></column>
        </property>
    </class>
</hibernate-mapping>

创建相应的接口与实现类

首先,在src/main/java目录下新建一个com.meimeixia.crm.dao包,并在该包下创建一个ICustomerDao接口。

package com.meimeixia.crm.dao;

import java.util.List;

import com.meimeixia.crm.domain.Customer;

public interface ICustomerDao {
	
	public List<Customer> findAll();
	
}

然后,在src/main/java目录下再新建一个com.meimeixia.crm.dao.impl包,并在该包下创建以上接口的一个实现类。

package com.meimeixia.crm.dao.impl;

import java.util.List;

import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.meimeixia.crm.dao.ICustomerDao;
import com.meimeixia.crm.domain.Customer;

public class CustomerDao extends HibernateDaoSupport implements ICustomerDao {
	
	public List<Customer> findAll() {
		return (List<Customer>) getHibernateTemplate().find("from Customer");
	}
	
}

Spring框架整合Hibernate框架

首先,创建Hibernate核心配置文件,该核心配置文件的位置是在src/main/resources目录下面,名称是hibernate.cfg.xml。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
	
<hibernate-configuration>
	<session-factory>
		<!-- 配置Hibernate的方言 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		
		<!-- 下面两个是可选的配置哟! -->
		<!-- 打印sql语句 -->
		<property name="hibernate.show_sql">true</property>
		<!-- 格式化sql语句 -->
		<property name="hibernate.format_sql">false</property>
		
		<property name="hbm2ddl.auto">none</property>
		
		<!-- 懒加载 -->
		<property name="hibernate.enable_lazy_load_no_trans">true</property>
		
		<!-- 是否启用实体类的验证(实体类的验证,跟我们映射文件进行一个映射的匹配) -->
		<property name="javax.persistence.validation.mode">none</property>
	</session-factory>
</hibernate-configuration>

然后,就要整合Spring框架与Hibernate框架了。整合不麻烦,就看你看不看得懂了,反正我是看懂了。我们可以在src/main/resources目录下新建一个名为spring的包,并在该包下创建一个名称为applicationContext-dao.xml的Spring配置文件,内容如下:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">

	<!-- 配置数据源(也即c3p0连接池) -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/crm?characterEncoding=utf-8" />
		<property name="user" value="root" />
		<property name="password" value="liayun" />
	</bean>
	
	<!-- 配置sessionFactory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<!-- 加载Hibernate配置文件 -->
		<property name="configLocation" value="classpath:hibernate.cfg.xml" />
		<!-- (引入所有的映射文件)告诉Hibernate加载哪个映射文件 -->
		<property name="mappingLocations" value="classpath:com/meimeixia/crm/domain/*.hbm.xml"></property>
	</bean>
	
	<!-- 数据访问层 -->
	<bean id="customerDao" class="com.meimeixia.crm.dao.impl.CustomerDao">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
</beans>

至此,crm-dao子模块就开发完毕了。

编写JUnit单元测试用例

crm-dao子模块开发完毕之后,接下来,我们就要编写JUnit单元测试用例了。温馨提示:大家在实际项目开发中,开发完一个模块后,一定要记得编写JUnit单元测试用例进行测试,这是一个合格的程序员的基本素养。

首先,确保pom.xml文件中添加了junit的依赖。
maven快速入门第十三讲——使用maven整合SSH
然后,在src/test/java目录下新建一个com.meimeixia.crm.dao.test包,并在该包下创建一个单元测试类,例如CustomerDaoTest.java。

package com.meimeixia.crm.dao.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.meimeixia.crm.dao.impl.CustomerDao;

public class CustomerDaoTest {
	
	@Test
	public void tt() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-dao.xml");
		CustomerDao customerDao = (CustomerDao) ac.getBean("customerDao");
		System.out.println(customerDao.findAll().size());
	}

}

运行以上单元测试方法,可以看到eclipse控制台打印了如下图所示的内容。
maven快速入门第十三讲——使用maven整合SSH
从上图可以知道crm-dao子模块测试完美通过,没有任何毛病!接下来,就要开发crm-service子模块了。

crm-service子模块的开发与测试

创建相应的接口与实现类

首先,在src/main/java目录下新建一个com.meimeixia.crm.service包,并在该包下创建一个ICustomerService接口。

package com.meimeixia.crm.service;

import java.util.List;

import com.meimeixia.crm.domain.Customer;

public interface ICustomerService {
	
	public List<Customer> findAll();
	
}

然后,在src/main/java目录下再新建一个com.meimeixia.crm.service.impl包,并在该包下创建以上接口的一个实现类。

package com.meimeixia.crm.service.impl;

import java.util.List;

import com.meimeixia.crm.dao.ICustomerDao;
import com.meimeixia.crm.domain.Customer;
import com.meimeixia.crm.service.ICustomerService;

public class CustomerService implements ICustomerService {
	
	private ICustomerDao customerDao;

	public void setCustomerDao(ICustomerDao customerDao) {
		this.customerDao = customerDao;
	}

	@Override
	public List<Customer> findAll() {
		return customerDao.findAll();
	}
	
}

配置Spring的事务管理

这里,我会使用Spring基于XML配置文件方式的声明式事务管理来管理事务。于是,在src/main/resources目录下新建一个名为spring的包,并在该包下创建一个名称为applicationContext-service.xml的Spring配置文件,内容如下:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
	
	<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<!-- 通知 -->
	<tx:advice id="advice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED" />
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="*" read-only="true" />
		</tx:attributes>
	</tx:advice>
		
	<!-- 切面 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.meimeixia.crm.service.impl.*.*(..))" id="myPointCut"/>
		<aop:advisor advice-ref="advice" pointcut-ref="myPointCut"/>
	</aop:config>
	
	<!-- 业务 -->
	<bean id="customerService" class="com.meimeixia.crm.service.impl.CustomerService">
		<property name="customerDao" ref="customerDao"></property>
	</bean>
</beans>

从以上Spring配置文件的内容中可以看出,CustomerService实现类交给Spring来管理了。

编写JUnit单元测试用例

crm-service子模块开发完毕之后,接下来,我们就要编写JUnit单元测试用例了。首先,肯定要确保pom.xml文件中添加了junit的依赖。
maven快速入门第十三讲——使用maven整合SSH
然后,在src/test/java目录下新建一个com.meimeixia.crm.test.service包,并在该包下创建一个单元测试类,例如CustomerServiceTest.java。

package com.meimeixia.crm.service.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.meimeixia.crm.service.ICustomerService;

public class CustomerServiceTest {

	@Test
	public void tt() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-service.xml");
		ICustomerService customerService = (ICustomerService) ac.getBean("customerService");
		System.out.println(customerService.findAll().size());
	}
	
}

千万不要忘了在applicationContext-service.xml配置文件中添加如下配置,即在该配置文件中引入crm-dao子模块中的applicationContext-dao.xml配置文件。
maven快速入门第十三讲——使用maven整合SSH
为什么要这样做呢?因为你不加以上配置,运行CustomerServiceTest单元测试类中的测试方法就会报错,错误提示信息如下图所示。
maven快速入门第十三讲——使用maven整合SSH
导致报错的原因就是没有加载所有与Spring有关的配置文件,也即是说还没有加载到crm-dao子模块中的applicationContext-dao.xml配置文件。

需要加载与Spring有关的所有配置文件,并把配置文件中的对象进行创建,对象创建之后,放到ServletContext域里面去,最终我们要使用创建的对象,可从ServletContext域里面获取出来。