本文采用maven搭建spring MVC + Spring + Hibernate的web框架,采用postgreSQL作为数据库,数据源采用dbcp。搭建的思路如下:
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/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>cn.ac.bccgroupId>
<artifactId>maqueartifactId>
<packaging>warpackaging>
<version>0.0.1-SNAPSHOTversion>
<name>maque Maven Webappname>
<url>http://maven.apache.orgurl>
<repositories>
<repository>
<id>mavenid>
<name>Maven Repository Switchboardname>
<layout>defaultlayout>
<url>http://repo1.maven.org/maven2url>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
<repository>
<id>alibaba-opensourceid>
<name>alibaba-opensourcename>
<url>http://code.alibabatech.com/mvn/releases/url>
<layout>defaultlayout>
repository>
<repository>
<id>alibaba-opensource-snapshotid>
<name>alibaba-opensource-snapshotname>
<url>http://code.alibabatech.com/mvn/snapshots/url>
<layout>defaultlayout>
repository>
repositories>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<spring.version>4.2.1.RELEASEspring.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>3.0-alpha-1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2.1-b03version>
<scope>providedscope>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.2.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.1.26version>
dependency>
<dependency>
<groupId>org.codehaus.jacksongroupId>
<artifactId>jackson-mapper-aslartifactId>
<version>1.9.11version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.7.4version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.7.4version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.7.1version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-coreartifactId>
<version>4.2.5.Finalversion>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>4.2.5.Finalversion>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-ehcacheartifactId>
<version>4.2.5.Finalversion>
dependency>
<dependency>
<groupId>org.hibernate.javax.persistencegroupId>
<artifactId>hibernate-jpa-2.0-apiartifactId>
<version>1.0.1.Finalversion>
dependency>
<dependency>
<groupId>postgresqlgroupId>
<artifactId>postgresqlartifactId>
<version>9.1-901-1.jdbc4version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>commons-dbcpgroupId>
<artifactId>commons-dbcpartifactId>
<version>1.4version>
dependency>
dependencies>
<build>
<finalName>maquefinalName>
<plugins>
<plugin>
<artifactId>maven-war-pluginartifactId>
plugin>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
plugins>
build>
project>
编写配置文件,配置文件放在src/main/resources资源目录下(下同)。
项目所需的配置信息config.properties
#PostgreSQL
jdbc.driver=org.postgresql.Driver
jdbc.url=jdbc:postgresql://localhost:5432/exampledb
jdbc.username=postgres
jdbc.password=123abc
validationQuery=SELECT 1
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.format_sql=true
sessionInfoName=sessionInfo
<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" xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
">
<context:property-placeholder location="classpath:config.properties" />
<context:component-scan base-package="cn.ac.bcc.maque.dao,cn.ac.bcc.maque.service" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor">bean>
beans>
log4j.rootLogger=INFO,A1,R
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.Target=System.out
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%c]%m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=sshf.log
log4j.appender.R.MaxFileSize=10MB
log4j.appender.R.Threshold=ALL
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n
Hibernate的配置主要包括:配置数据源dbcp,配置SessionFactory,配置事务管理器,配置事务管理,其spring-hibernate.xml文件如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
<property name="url" value="${jdbc.url}">property>
<property name="driverClassName" value="${jdbc.driver}" >property>
bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<map>
<entry key="hibernate.dialect" value="${hibernate.dialect}">entry>
<entry key="hibernate.show_sql" value="${hibernate.show_sql}">entry>
<entry key="hibernate.format_sql" value="${hibernate.format_sql}">entry>
<entry key="hibernate.current_session_context_class" value="org.springframework.orm.hibernate4.SpringSessionContext">entry>
<entry key="hibernate.multiTenancy" value="SCHEMA">entry>
<entry key="hibernate.tenant_identifier_resolver" value="cn.ac.bcc.maque.dao.impl.TenantIdResolver">entry>
<entry key="hibernate.multi_tenant_connection_provider" value="cn.ac.bcc.maque.dao.impl.SchemaBasedMultiTenantConnectionProvider">entry>
map>
property>
<property name="packagesToScan">
<list>
<value>cn.ac.bcc.maque.modelvalue>
list>
property>
bean>
<bean name="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager" />
beans>
在第3步中,配置了多租户,涉及到了两个类TenantIdResolver和SchemaBasedMultiTenantConnectionProvider:
TenantIdResolver的类内容如下:
package cn.ac.bcc.maque.dao.impl;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import cn.ac.bcc.maque.model.Login;
public class TenantIdResolver implements CurrentTenantIdentifierResolver {
@Override
public String resolveCurrentTenantIdentifier() {
return Login.getTenantId();
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
SchemaBasedMultiTenantConnectionProvider的类内容如下:
package cn.ac.bcc.maque.dao.impl;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl;
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.Stoppable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository("schemaBasedMultiTenantConnectionProvider")
public class SchemaBasedMultiTenantConnectionProvider implements MultiTenantConnectionProvider,Stoppable,Configurable {
/**
*
*/
private static final long serialVersionUID = -5379376698684861045L;
private final DatasourceConnectionProviderImpl connectionProvider = new DatasourceConnectionProviderImpl();
public void configure(Map configurationValues) {
this.connectionProvider.configure(configurationValues);
}
public Connection getAnyConnection() throws SQLException {
return connectionProvider.getConnection();
}
public void releaseAnyConnection(Connection connection) throws SQLException {
connectionProvider.closeConnection(connection);
}
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
// connection.createStatement().execute("USE " + tenantIdentifier);
connection.createStatement().execute("set schema '" + tenantIdentifier + "'");
} catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]", e);
}
return connection;
}
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
try {
connection.createStatement().execute("USE test");
} catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]", e);
}
connectionProvider.closeConnection(connection);
}
public boolean supportsAggressiveRelease() {
return this.connectionProvider.supportsAggressiveRelease();
}
public void stop() {
this.connectionProvider.stop();
}
public boolean isUnwrappableAs(Class unwrapType) {
return this.connectionProvider.isUnwrappableAs(unwrapType);
}
public T unwrap(Class unwrapType) {
return this.connectionProvider.unwrap(unwrapType);
}
}
在PostgreSQL中,创建database,名为exampledb;创建schema,名为myschema;在mychema中创建table,创建语句如下:
create database exampledb;
create schema myschema;
set schema 'myschema';
create table user_info(id varchar(200),name varchar(50),signup_date
date);
package cn.ac.bcc.maque.model;
// Generated 2016-5-11 17:35:53 by Hibernate Tools 4.3.1.Final
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* User generated by hbm2java
*/
@Entity
@Table(name="user_info")
public class User implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = -5656136547913487597L;
@Id
@Column(name="id")
private String id;
@Column(name="name")
private String name;
@Column(name="signup_date")
private Date signupDate;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Date getSignupDate() {
return this.signupDate;
}
public void setSignupDate(Date signupDate) {
this.signupDate = signupDate;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof User))
return false;
User castOther = (User) other;
return ((this.getName() == castOther.getName()) || (this.getName() != null && castOther.getName() != null
&& this.getName().equals(castOther.getName())))
&& ((this.getSignupDate() == castOther.getSignupDate())
|| (this.getSignupDate() != null && castOther.getSignupDate() != null
&& this.getSignupDate().equals(castOther.getSignupDate())));
}
public int hashCode() {
int result = 17;
result = 37 * result + (getName() == null ? 0 : this.getName().hashCode());
result = 37 * result + (getSignupDate() == null ? 0 : this.getSignupDate().hashCode());
return result;
}
}
Dao层和Service层我们肯定采用的是面相接口编程的思想,所以,我们先定义一个通用的Dao接口,GenericDao.java
package cn.ac.bcc.maque.dao;
import java.io.Serializable;
import java.util.List;
public interface GenericDao <T, PK extends Serializable>{
T load(PK id);
T get(PK id);
List findAll();
void persist(T entity);
PK save(T entity);
void saveOrUpdate(T entity);
void delete(PK id);
void flush();
}
再定义具体的UserDao.java接口:
package cn.ac.bcc.maque.dao;
import cn.ac.bcc.maque.model.User;
public interface UserDao extends GenericDao<User,String>{
}
package cn.ac.bcc.maque.dao.impl;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import cn.ac.bcc.maque.dao.UserDao;
import cn.ac.bcc.maque.model.User;
@Repository("userDao")
@Transactional
public class UserDaoImpl implements UserDao {
@Autowired
private SessionFactory sessionFactory;
private Session currentSession(){
Session session = sessionFactory.getCurrentSession();
return session;
}
@Override
public User load(String id) {
// TODO Auto-generated method stub
return null;
}
@Override
public User get(String id) {
return (User) currentSession().get(User.class,id);
}
@SuppressWarnings("unchecked")
@Override
public List findAll() {
List users = currentSession().createQuery("from User user").list();
return users;
}
@Override
public void persist(User entity) {
// TODO Auto-generated method stub
}
@Override
public String save(User entity) {
return (String) currentSession().save(entity);
}
@Override
public void saveOrUpdate(User entity) {
// TODO Auto-generated method stub
}
@Override
public void delete(String id) {
currentSession().delete(currentSession().get(User.class, id));
}
@Override
public void flush() {
// TODO Auto-generated method stub
}
}
package cn.ac.bcc.maque.service;
import java.util.List;
import cn.ac.bcc.maque.model.User;
public interface UserService {
User load(String id);
User get(String id);
List<User> findAll();
void persist(User entity);
String save(User entity);
void saveOrUpdate(User entity);
void delete(String id);
void flush();
}
package cn.ac.bcc.maque.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.ac.bcc.maque.dao.UserDao;
import cn.ac.bcc.maque.model.User;
import cn.ac.bcc.maque.service.UserService;
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User load(String id) {
// TODO Auto-generated method stub
return null;
}
@Override
public User get(String id) {
return userDao.get(id);
}
@Override
public List findAll() {
return userDao.findAll();
}
@Override
public void persist(User entity) {
// TODO Auto-generated method stub
}
@Override
public String save(User entity) {
return userDao.save(entity);
}
@Override
public void saveOrUpdate(User entity) {
// TODO Auto-generated method stub
}
@Override
public void delete(String id) {
userDao.delete(id);
}
@Override
public void flush() {
// TODO Auto-generated method stub
}
}
我们可以在src/test/java编写测试类,测试上面的配置,如果测试成功已经基本大功告成。
package cn.ac.bcc.maque.service;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.log4j.Logger;
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 com.alibaba.fastjson.JSON;
import cn.ac.bcc.maque.model.Login;
import cn.ac.bcc.maque.model.User;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring.xml",
"classpath:spring-hibernate.xml"})
public class TestUserService {
private static final Logger LOGGER = Logger
.getLogger(TestUserService.class);
@Autowired
private UserService userService;
// @Test
// public void save(){
// User user = new User();
// user.setId(UUID.randomUUID().toString());
// user.setName("ada");
// user.setSignupDate(new Date());
// String id = userService.save(user);
// LOGGER.info(JSON.toJSON(id));
// }
//
// @Test
// public void findAll(){
// List users = userService.findAll();
// for(User u:users){
// LOGGER.info(u.getId()+"\t"+u.getName()+"\t"+u.getSignupDate());
// }
// }
@Test
public void saveByTenantId(){
Login.setTenantId("myschema");
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setName("ada");
user.setSignupDate(new Date());
String id = userService.save(user);
LOGGER.info(JSON.toJSON(id));
}
}
未完待续…
- 11. 引入Spring MVC
- 12. 配置web.xml容器
- 13. 创建控制层controller
- 14. 创建视图层
- 15. 部署服务器测试