Maven - 構建基於Maven的ssh分模塊項目
一、數據庫準備
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文件時,[email protected]
[email protected]碼,[email protected]
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進行單元測試時,[email protected],否則會使用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測試即可
Maven - 構建基於Maven的ssh分模塊項目