spring MVC +Spring + Hibernate + PostgreSQL框架的集成和多租户( 一)
来源:互联网 发布:彩票app源码 编辑:程序博客网 时间:2024/05/22 15:28
spring MVC +Spring + Hibernate + PostgreSQL框架的集成和多租户
本文采用maven搭建spring MVC + Spring + Hibernate的web框架,采用postgreSQL作为数据库,数据源采用dbcp。搭建的思路如下:
- 1. 创建Maven项目,编写pom.xml文件
- 2. 引入Spring配置
- 3. hibernate配置
- 4. 多租户实现
- 5. 数据库设计
- 6. 生成业务entity实体
- 8. 创建dao层
- 9. 创建service层
- 10. 测试spring和hibernate整合
- 11. 引入Spring MVC
- 12. 配置web.xml容器
- 13. 创建控制层controller
- 14. 创建视图层
- 15. 部署服务器测试
1.创建Maven项目,编写pom.xml文件
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.0</modelVersion> <groupId>cn.ac.bcc</groupId> <artifactId>maque</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>maque Maven Webapp</name> <url>http://maven.apache.org</url> <!-- 指定maven仓库 --> <repositories><!-- 发现依赖和扩展的远程资源库 --> <!-- maven自己官方仓库 --> <repository> <id>maven</id> <name>Maven Repository Switchboard</name> <layout>default</layout> <url>http://repo1.maven.org/maven2</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <!-- 阿里巴巴发布版本仓库 --> <repository> <id>alibaba-opensource</id> <name>alibaba-opensource</name> <url>http://code.alibabatech.com/mvn/releases/</url> <layout>default</layout> </repository> <!-- 阿里巴巴快照版本仓库 --> <repository> <id>alibaba-opensource-snapshot</id> <name>alibaba-opensource-snapshot</name> <url>http://code.alibabatech.com/mvn/snapshots/</url> <layout>default</layout> </repository> </repositories> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.2.1.RELEASE</spring.version> </properties> <dependencies> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>3.0-alpha-1</version> <scope>provided</scope> </dependency> <!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2.1-b03</version> <scope>provided</scope> </dependency> <!-- 文件上传 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <!-- fastJson json数组有关的 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.26</version> </dependency> <!-- 使用 Jackson 把 Java 对象转换成 JSON 字串 --> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.11</version> </dependency> <!-- http://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.4</version> </dependency> <!-- http://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.4</version> </dependency> <!-- aspectjweaver.jar这是Spring AOP所要用到的包 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.1</version> </dependency> <!-- hibernate4 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.2.5.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.2.5.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>4.2.5.Final</version> </dependency> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.0-api</artifactId> <version>1.0.1.Final</version> </dependency> <!-- postgreSQL --> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.1-901-1.jdbc4</version> </dependency> <!-- spring mvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- spring4 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> </dependencies> <build> <finalName>maque</finalName> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build></project>
2.引入Spring配置
编写配置文件,配置文件放在src/main/resources资源目录下(下同)。
项目所需的配置信息config.properties
#PostgreSQLjdbc.driver=org.postgresql.Driverjdbc.url=jdbc:postgresql://localhost:5432/exampledbjdbc.username=postgresjdbc.password=123abcvalidationQuery=SELECT 1hibernate.dialect=org.hibernate.dialect.PostgreSQLDialecthibernate.hbm2ddl.auto=updatehibernate.show_sql=truehibernate.format_sql=truesessionInfoName=sessionInfo
2.1 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" 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" /> <!-- 自动扫描dao和service包(自动注入) --> <context:component-scan base-package="cn.ac.bcc.maque.dao,cn.ac.bcc.maque.service" /> <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"></bean></beans>
2.2 引入日志文件配置Log4j
log4j.rootLogger=INFO,A1,Rlog4j.appender.A1=org.apache.log4j.ConsoleAppenderlog4j.appender.A1.Target=System.outlog4j.appender.A1.layout=org.apache.log4j.PatternLayoutlog4j.appender.A1.layout.ConversionPattern=[%c]%m%nlog4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=sshf.loglog4j.appender.R.MaxFileSize=10MBlog4j.appender.R.Threshold=ALLlog4j.appender.R.layout=org.apache.log4j.PatternLayoutlog4j.appender.R.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n
3. Hibernate配置
Hibernate的配置主要包括:配置数据源dbcp,配置SessionFactory,配置事务管理器,配置事务管理,其spring-hibernate.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: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.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- JNDI(通过Tomcat)方式配置数据源 --> <!-- <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="${jndiName}"></property> </bean> --> <!-- 配置数据源 --> <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> <!-- 配置hibernate session工厂 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <map> <!-- <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> --> <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> <!-- hibernate多租户配置 --> <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> <!-- 自动扫描注解方式配置的hibernate类文件 --> <property name="packagesToScan"> <list> <value>cn.ac.bcc.maque.model</value> </list> </property> <!-- <property name="mappingDirectoryLocations"> <list> <value>classpath:/cn/ac/bcc/maque/model</value> </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" /> <!-- 拦截器方式配置事物 --> <!-- <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" /> <tx:method name="save*" /> <tx:method name="update*" /> <tx:method name="modify*" /> <tx:method name="edit*" /> <tx:method name="delete*" /> <tx:method name="remove*" /> <tx:method name="repair" /> <tx:method name="deleteAndRepair" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="transactionPointcut" expression="execution(* com.jesus.sshframework.service..*Impl.*(..))" /> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /> </aop:config> --></beans>
4. 多租户实现
在第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> T unwrap(Class<T> unwrapType) { return this.connectionProvider.unwrap(unwrapType); }}
5.数据库设计
在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_datedate);
6. 生成业务entity实体
package cn.ac.bcc.maque.model;// Generated 2016-5-11 17:35:53 by Hibernate Tools 4.3.1.Finalimport 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; }}
8. 创建dao层
8.1 Dao接口
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<T> 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>{}
8.2 Dao层实现
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")@Transactionalpublic 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<User> findAll() { List<User> 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 }}
9. 创建service层
9.1 创建service 接口
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(); }
9.2 service层实现类
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<User> 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 }}
10. 测试spring和hibernate整合
我们可以在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<User> 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. 部署服务器测试
- spring MVC +Spring + Hibernate + PostgreSQL框架的集成和多租户( 一)
- spring MVC +Spring + Hibernate + PostgreSQL框架的集成和多租户( 二)
- Spring Web MVC和Hibernate的集成
- cxf框架和spring mvc的集成
- spring mvc集成hibernate
- Spring MVC + Spring + Hibernate集成
- Spring 和 Hibernate的集成
- Spring 和 Hibernate的集成
- spring和hibernate的集成
- Hibernate、Spring和Spring MVC的整合
- Spring MVC集成Tiles框架
- spring和hibernate集成
- Spring和Hibernate集成
- Spring+Spring MVC+Shiro+Mybatis框架集成
- Myibatis和spring(mvc)的集成
- cxf和spring mvc的集成
- cxf和spring mvc的集成
- Spring和maven集成mvc,jpa,mongodb,Hibernate等
- 织梦dedecms文档静态页批量替换为动态浏览
- sort a
- 云时代的编程模式
- hive索引
- lintcode ----比较字符串
- spring MVC +Spring + Hibernate + PostgreSQL框架的集成和多租户( 一)
- linux 下 iozone随机读写测试报错: error reading block
- IOS开发—通过ChildViewController实现view的切换
- sort b
- UVA 11983-Weird Advertisement-k次以上覆盖矩形面积(线段树+扫描线)
- Autolayout之 关于+requiresConstraintBasedLayout方法作用
- 【leetcode】172. Factorial Trailing Zeroes
- LeetCode 40 Combination Sum II
- Robot Framework自动化测试框架(三):Android自动化