一、数据库准备
 1.创建数据库maven
		create database maven character set utf8 collate utf8_general_ci; //use maven;
2.创建用户表
		create table t_users(
			id int primary key auto_increment,
			username varchar(30) not null,
			password varchar(50) not null,
			constraint unq_users_username unique(username)
		);
3.插入测试数据
		insert into t_users(username,password) values(‘admin‘, md5(‘admin‘));
		insert into t_users(username,password) values(‘user‘, md5(‘user‘));
		
二、项目框架构建
	1.创建简单父工程maven-parent,注意packaging类型为pom
	2.复制prom.xml内容以引入jar包
	3.创建子工程(Maven Module)maven-entity,注意packaging类型为jar,选择父类型为maven-parent
	4.创建子工程(Maven Module)maven-utils,注意packaging类型为jar,选择父类型为maven-parent
	5.创建子工程(Maven Module)maven-dao,注意packaging类型为jar,选择父类型为maven-parent
	6.创建子工程(Maven Module)maven-service,注意packaging类型为jar,选择父类型为maven-parent
	7.创建子工程(Maven Module)maven-web,,注意packaging类型为war,选择父类型为maven-parent
	8.将maven-parent发布到本地仓库,maven会自动将所有子工程发布到本地仓库
	9.按顺序为各个子项目添加依赖关系,具体依赖顺序如下 web--->service-->dao--->utils--->entity
	10.在子工程之间添加依赖的具体操作如下:
		10.1 发布工程后,最好先打开Maven Repository重建一下索引
		10.2 打开maven-utils子工程的porm.xml,选择dependencies标签添加对maven-entity的依赖(也可以直接编辑porm.xml源码添加)
		10.3 打开maven-dao子工程的porm.xml,选择dependencies标签添加对maven-utils的依赖(也可以直接编辑porm.xml源码添加)
		10.4 打开maven-service子工程的porm.xml,选择dependencies标签添加对maven-dao的依赖(也可以直接编辑porm.xml源码添加)
		10.5 打开maven-web子工程的porm.xml,选择dependencies标签添加对maven-web的依赖(也可以直接编辑porm.xml源码添加)
	11.子工程之间的依赖会以工程的形式出现在lib中,若关闭某一子工程,则会变为以jar方式引入
	12.在maven-web工程的webapp创建WEB-INF目录及web.xml文件
	
三、构建maven-entity子工程
	1.在src/main/java的com.hao.entity下编写User.java,并采用Hibernate注解映射实体
	
			package com.hao.entity;
// Generated 2017-8-6 12:57:28 by Hibernate Tools 4.0.0
			import javax.persistence.Column;
			import javax.persistence.Entity;
			import javax.persistence.GeneratedValue;
			import static javax.persistence.GenerationType.IDENTITY;
			import javax.persistence.Id;
			import javax.persistence.Table;
			import javax.persistence.UniqueConstraint;
			/**
			 * TUsers generated by hbm2java
			 */
			@Entity
			@Table(name = "t_users", catalog = "maven", uniqueConstraints = @UniqueConstraint(columnNames = "username"))
			public class User implements java.io.Serializable {
private static final long serialVersionUID = 1L;
				private Integer id;
				private String username;
				private String password;
				public User() {
				}
				public User(String username, String password) {
					this.username = username;
					this.password = password;
				}
				@Id
				@GeneratedValue(strategy = IDENTITY)
				@Column(name = "id", unique = true, nullable = false)
				public Integer getId() {
					return this.id;
				}
				public void setId(Integer id) {
					this.id = id;
				}
				@Column(name = "username", unique = true, nullable = false, length = 30)
				public String getUsername() {
					return this.username;
				}
				public void setUsername(String username) {
					this.username = username;
				}
				@Column(name = "password", nullable = false, length = 50)
				public String getPassword() {
					return this.password;
				}
				public void setPassword(String password) {
					this.password = password;
				}
			}
			
四、构建maven-utils子工程
1.在src/main/java下编写MD5工具类,用于密码加密
package com.hao.utils;
			import java.math.BigInteger;
			import java.security.MessageDigest;
			import java.security.NoSuchAlgorithmException;
			public class MD5Utils {
				/**
				 * 使用md5的算法进行加密
				 */
				public static String md5(String plainText) {
					byte[] secretBytes = null;
					try {
						secretBytes = MessageDigest.getInstance("md5").digest(
								plainText.getBytes());
					} catch (NoSuchAlgorithmException e) {
						throw new RuntimeException("没有md5这个算法!");
					}
					String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
					// 如果生成数字未满32位,需要前面补0
					for (int i = 0; i < 32 - md5code.length(); i++) {
						md5code = "0" + md5code;
					}
					return md5code;
				}
				public static void main(String[] args) {
					System.out.println(md5("123"));
				}
			}
			
五、构建maven-dao子工程
	1.在src/main/java下进行BaseDao的抽取以及UserDao代码的编写
	
		1.1 BaseDao接口
		
			package com.hao.dao.base;
			import java.io.Serializable;
			import java.util.List;
public interface BaseDao<T> {
void save(T entity);
void delete(T entity);
void deleteById(Serializable id);
void update(T entity);
T findById(Serializable id);
				List<T> findAll();
			}
			
		1.2 BaseDaoImpl实现类
		
			package com.hao.dao.base.impl;
			import java.io.Serializable;
			import java.lang.reflect.ParameterizedType;
			import java.lang.reflect.Type;
			import java.util.List;
			import org.hibernate.SessionFactory;
			import org.springframework.beans.factory.annotation.Autowired;
			import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.hao.dao.base.BaseDao;
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
private Class<T> entityClass;
				@SuppressWarnings("unchecked")
				public BaseDaoImpl() {
					// 获取子类对象的父类类型
					ParameterizedType superClass = (ParameterizedType) this.getClass()
							.getGenericSuperclass();
					// 获得在父类类型上声明的反省数组
					Type[] genericTypes = superClass.getActualTypeArguments();
					// 第一个泛型即为实体类型
					entityClass = (Class<T>) genericTypes[0];
				}
				@Override
				public void save(T entity) {
					getHibernateTemplate().save(entity);
				}
				@Override
				public void delete(T entity) {
					getHibernateTemplate().delete(entity);
				}
				@Override
				public void deleteById(Serializable id) {
					T entity = getHibernateTemplate().load(entityClass, id);
					getHibernateTemplate().delete(entity);
				}
				@Override
				public void update(T entity) {
					getHibernateTemplate().update(entity);
				}
				@Override
				public T findById(Serializable id) {
					return getHibernateTemplate().get(entityClass, id);
				}
				@Override
				public List<T> findAll() {
					return getHibernateTemplate().loadAll(entityClass);
				}
				/**
				 * HibernateDao接口在使用前必须注入SessionFactory
				 * 
				 * @param sessionFactory
				 */
				@Autowired
				public void setSF(SessionFactory sessionFactory) {
					super.setSessionFactory(sessionFactory);
				}
			}
		
		1.3 UserDao接口
		
			package com.hao.dao;
			import com.hao.dao.base.BaseDao;
			import com.hao.entity.User;
public interface UserDao extends BaseDao<User> {
				User login(String username, String password);
			}
			
		1.4 UserDaoImpl实现类
		
			package com.hao.dao.impl;
import java.util.List;
import org.springframework.stereotype.Repository;
			import com.hao.dao.UserDao;
			import com.hao.dao.base.impl.BaseDaoImpl;
			import com.hao.entity.User;
			@Repository("userDao")
			public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao {
				@Override
				public User login(String username, String password) {
					@SuppressWarnings("unchecked")
					List<User> user = (List<User>) getHibernateTemplate().find(
							"from User u where u.username=? and u.password=?", username,
							password);
					if (user == null || user.size() < 1) {
						return null;
					} else {
						return user.get(0);
					}
				}
			}
	2.在src/main/resources下创建applicationContext-dao.xml文件,编写属于dao层的内容
	
		  <!-- 开启扫描注解Bean -->
		  <context:component-scan base-package="com.hao" />
		  <context:property-placeholder location="classpath:db.properties" />
		  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
			<property name="driverClass" value="${jdbc.driverClass}" />
			<property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
			<property name="user" value="${jdbc.user}" />
			<property name="password" value="${jdbc.password}" />
		  </bean>
		  <!-- 加载配置方案2:在spring配置中放置hibernate配置信息 -->
		  <bean name="sessionFactory"
			class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
			<!-- 将连接池注入到sessionFactory, hibernate会通过连接池获得连接 -->
			<property name="dataSource" ref="dataSource"></property>
			<!-- 配置hibernate基本信息 -->
			<property name="hibernateProperties">
			  <props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
				</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			  </props>
			</property>
			<!-- 引入orm元数据,指定orm元数据所在的包路径,spring会自动读取包中的所有配置 -->
			<property name="packagesToScan" value="com.hao.entity"></property>
		  </bean>
		  
	3.在src/main/resources下创建db.properties
	
			jdbc.jdbcUrl=jdbc:mysql://localhost:3306/maven
			jdbc.driverClass=com.mysql.jdbc.Driver
			jdbc.user=root
			jdbc.password=h66666
			
	4.在src/main/resources下创建log4j.properties
	
			log4j.appender.stdout=org.apache.log4j.ConsoleAppender
			log4j.appender.stdout.Target=System.out
			log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
			log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
			log4j.appender.file=org.apache.log4j.FileAppender
			log4j.appender.file.File=D:\\temp\\mylog.log
			log4j.appender.file.layout=org.apache.log4j.PatternLayout
			log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
			### fatal error warn info debug debug trace
			log4j.rootLogger=debug, stdout
			#log4j.logger.org.hibernate=INFO
			#log4j.logger.org.hibernate.type=INFO
			
	5.为了在Dao层能对save,update之类的方法进行测试,还需而外提供Service层中的Spring声明式事务配置
	6.故在src/test/resources下创建applicationContext-daotest.xml,提供和事务相关的配置(最好与applicationContext-service中的事务配置保持一致)
	
			  <bean name="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" >
				<property name="sessionFactory" ref="sessionFactory"/>
			  </bean>
			  
			  <tx:annotation-driven transaction-manager="transactionManager" /> 
	
	7.执行单元测试时,实际上需要使用到多个applicationContext文件,其中applicationContext-daotest.xml就是在src/test/resources中定义的
	
	8.单元测试依赖多个applicationContext文件时,要在@ContextConfiguration的locations中列举出来
	
	9.在src/test/java的com.hao.dao包下编写Dao层单元测试代码,注意要添加@Transaction注解
	
			package com.hao.dao;
import junit.framework.Assert;
			import org.junit.Test;
			import org.junit.runner.RunWith;
			import org.springframework.beans.factory.annotation.Autowired;
			import org.springframework.test.context.ContextConfiguration;
			import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
			import org.springframework.transaction.annotation.Transactional;
			import com.hao.entity.User;
			import com.hao.utils.MD5Utils;
			@RunWith(SpringJUnit4ClassRunner.class)
			@ContextConfiguration(locations = { "classpath:applicationContext-dao.xml",
					"classpath:applicationContext-daotest.xml" })
			@Transactional
			public class UserDaoTest {
				@Autowired
				UserDao userDao;
				@Test
				public void testLogin() {
					Assert.assertNotNull(userDao.login("admin", MD5Utils.md5("admin")));
					Assert.assertNull(userDao.login("admin", MD5Utils.md5("pass")));
					Assert.assertNotNull(userDao.login("user", MD5Utils.md5("user")));
					System.out.println(userDao.login("admin", MD5Utils.md5("admin")));
				}
				@Test
				public void testSave() {
					User u = new User();
					u.setUsername("dao");
					u.setPassword("dao");
					userDao.save(u);
				}
			}
			
六、构建maven-service子工程
	1.在src/main/java下编写UserService相关代码
	
		1.1 UserService接口
		
			package com.hao.service;
import com.hao.entity.User;
public interface UserService {
User login(User user);
void save(User user);
			}
			
		1.2 UserServiceImpl实现类
		
			package com.hao.service.impl;
			import org.springframework.beans.factory.annotation.Autowired;
			import org.springframework.stereotype.Service;
			import org.springframework.transaction.annotation.Isolation;
			import org.springframework.transaction.annotation.Propagation;
			import org.springframework.transaction.annotation.Transactional;
			import com.hao.dao.UserDao;
			import com.hao.entity.User;
			import com.hao.service.UserService;
			import com.hao.utils.MD5Utils;
			@Service("userService")
			@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = true)
			public class UserServiceImpl implements UserService {
private UserDao userDao;
				@Autowired
				public void setUserDao(UserDao userDao) {
					this.userDao = userDao;
				}
				@Override
				public User login(User user) {
					String pass = MD5Utils.md5(user.getPassword());
					return userDao.login(user.getUsername(), pass);
				}
				@Override
				@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = false)
				public void save(User user) {
					userDao.save(user);
				}
			}
			
	2.在src/main/resources下创建applicationContext-service.xml,编写service层相关的配置(主要是声明式事务的配置)
	
			  <!-- 定义核心事务管理器 -->
			  <bean name="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" >
				<property name="sessionFactory" ref="sessionFactory"/>
			  </bean>
			  
			  <!-- 开启注解事务 -->
			  <tx:annotation-driven transaction-manager="transactionManager" /> 
	
	3.多个applicationContext也可以采用通配符方式配置,如"classpath*:applicationContext-*.xml",但不建议
	
	4.因为使用通配符方式时,我在eclipse能成功执行单元测试,但使用maven的install命令发布到本地仓库时,单元测试代码会执行失败
	
	5.出错原因为为dao子工程的applicationContext找不到,因此建议使用列举文件方式而不要采用通配符的方式
	
	6.注意,第一个通配符表示读取包括类路径和jar包下的径的配置文件
	
	7.在对Service进行单元测试时,可添加@Transactional避免脏数据的产生,否则会使用service方法中配置的事务,会产生脏数据
	
	8.在src/test/java下编写Service层的单元测试代码
	
			package com.hao.service;
import junit.framework.Assert;
			import org.junit.Test;
			import org.junit.runner.RunWith;
			import org.springframework.beans.factory.annotation.Autowired;
			import org.springframework.test.context.ContextConfiguration;
			import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
			import org.springframework.transaction.annotation.Transactional;
import com.hao.entity.User;
			@RunWith(SpringJUnit4ClassRunner.class)
			@ContextConfiguration({"classpath*:applicationContext-dao.xml", "classpath:applicationContext-service.xml"})
			@Transactional
			public class UserServiceTest {
				@Autowired
				UserService userService;
				@Test
				public void testLogin() {
					User u1 = new User();
					u1.setUsername("admin");
					u1.setPassword("admin");
					User u2 = new User();
					u2.setUsername("admin");
					u2.setPassword("pass");
					User u3 = new User();
					u3.setUsername("user");
					u3.setPassword("user");
					Assert.assertNotNull(userService.login(u1));
					Assert.assertNull(userService.login(u2));
					Assert.assertNotNull(userService.login(u3));
				}
				@Test
				public void testSave() {
					User u = new User();
					u.setUsername("service");
					u.setPassword("service");
userService.save(u);
}
			}
			
七、构建maven-web子工程
	1.action的抽取以及UserAction的编写
	
		1.1 抽取BaseAction
		
			package com.hao.action.base;
			import java.lang.reflect.ParameterizedType;
			import java.lang.reflect.Type;
			import java.util.Map;
			import org.apache.struts2.interceptor.RequestAware;
			import org.apache.struts2.interceptor.SessionAware;
			import com.opensymphony.xwork2.ActionSupport;
			import com.opensymphony.xwork2.ModelDriven;
			public class BaseAction<T> extends ActionSupport implements ModelDriven<T>,
					RequestAware, SessionAware {
private static final long serialVersionUID = 1L;
				protected Map<String, Object> request;
				protected Map<String, Object> session;
				protected T model;
				@Override
				public void setRequest(Map<String, Object> request) {
					this.request = request;
				}
				@Override
				public void setSession(Map<String, Object> session) {
					this.session = session;
				}
				@Override
				public T getModel() {
					return model;
				}
public BaseAction() {
					// 获取父类
					ParameterizedType genericSuperclass = (ParameterizedType) this
							.getClass().getGenericSuperclass();
					// 获取父类的泛型数组
					Type[] types = genericSuperclass.getActualTypeArguments();
					// 取得第一个泛型,即Model的类型
					@SuppressWarnings("unchecked")
					Class<T> entityClass = (Class<T>) types[0];
					try {
						model = entityClass.newInstance();
					} catch (InstantiationException | IllegalAccessException e) {
						e.printStackTrace();
						throw new RuntimeException(e);
					}
				}
			}
			
		1.2 UserAction代码编写,注意scope要为prototype
		
			package com.hao.action;
			import org.springframework.beans.factory.annotation.Autowired;
			import org.springframework.context.annotation.Scope;
			import org.springframework.stereotype.Controller;
			import com.hao.action.base.BaseAction;
			import com.hao.entity.User;
			import com.hao.service.UserService;
			@Controller("userAction")
			@Scope("prototype")
			public class UserAction extends BaseAction<User> {
private static final long serialVersionUID = 1L;
				public String login() {
					System.out.println("-------------------------------------------------------"
							+ this + "-------------------------------------------------------");
					User user = userService.login(model);
					if (user == null) {
						request.put("errorInfo", "用户名或密码错误");
						return LOGIN;
					}
					session.put("loginUser", user);
					return SUCCESS;
				}
				@Autowired
				private UserService userService;
				public UserService getUserService() {
					return userService;
				}
				public void setUserService(UserService userService) {
					this.userService = userService;
				}
			}
			
	2.在struts.xml中配置struts,整合spring
		
			<?xml version="1.0" encoding="UTF-8" ?>
			<!DOCTYPE struts PUBLIC
			"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
			"http://struts.apache.org/dtds/struts-2.3.dtd">
			<struts>
			  <constant name="struts.enable.DynamicMethodInvocation" value="false" />
			  <constant name="struts.devMode" value="true" />
			  <constant name="struts.objectFactory" value="spring" />
			  <package name="hao" namespace="/" extends="struts-default">
				<action name="userAction_*" class="userAction" method="{1}">
				  <result>/success.jsp</result>
				  <result name="login">/index.jsp</result>
				</action>
			  </package>
			</struts>
			
	3.在web.xml中配置spring监听器,让spring容器随web项目启动而启动
	
		  <!-- 配置spring框架的监听器 -->
		  <listener>
			<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
		  </listener>
		  <context-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:applicationContext-*.xml</param-value>
		  </context-param>
		  
	4.配置过滤器,用于扩展Hibernate Session的作用域知道请求结束,注意一定要配置在struts2过滤器之前
	
		  <!-- 配置过滤器,解决hibernate延迟加载问题 -->
		  <filter>
			<filter-name>openSessionInView</filter-name>
			<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
		  </filter>
		  <filter-mapping>
			<filter-name>openSessionInView</filter-name>
			<url-pattern>/*</url-pattern>
		  </filter-mapping>
		  
	5.配置struts2过滤器
	
		  <!-- 配置struts2的过滤器 -->
		  <filter>
			<filter-name>struts2</filter-name>
			<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
		  </filter>
		  <filter-mapping>
			<filter-name>struts2</filter-name>
			<url-pattern>/*</url-pattern>
		  </filter-mapping>	
		  
八、编写页面,启动项目
1.index.jsp,注意引入jstl标签库
		  <form action="userAction_login.action" method="post">
			<span>用户名:</span><input type="text" name="username"/><br/>
			<span>密 码:</span><input type="password" name="password"/><br/>
			<input type="submit" value="提交"/>
		  </form>
		  <c:if test="${not empty requestScope.errorInfo }">
			<c:out value="${errorInfo }"/>
		  </c:if>
	
	2.success.jsp
	
		<h5>${sessionScope.loginUser.username }登陆成功</h5><hr/>
	
	3.使用tomcat7:run命令运行或者使用eclipse从执行服务器运行,访问index.jsp测试即可
		
	
原文:http://www.cnblogs.com/tommychok/p/7345319.html