スプリングMVC+Spring+Hibernate+PostgreSQLフレームの集積とマルチテナント(一)

72328 ワード

スプリングMVC+Spring+Hibernate+PostgreSQLフレームの集積とマルチテナント
本論では、Mavenでspring MVC+Spring+Hibernateのwebフレームを構築し、postgreSQLをデータベースとし、データソースはdbcpを採用する.建てられた考えは以下の通りです.
  • 1.Mavenプロジェクトを作成し、pom.xmlファイル
  • を作成する.
  • .Spring構成
  • を導入する.
  • 3.ヒベルナ構成
  • 4.マルチテナント実現
  • .データベース設計
  • .サービスentityエンティティ
  • を生成する.
  • .dao層
  • を作成する.
  • 9.service層
  • を作成する.
  • 10.テストspringとhibernate統合
  • 11.Spring MVC
  • を導入する.
  • .配置web.xml容器
  • .制御層controler
  • を作成する.
  • .視聴層
  • を作成する.
  • 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.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>
    
    2.Spring配置の導入
    設定ファイルを作成し、設定ファイルをsrc/main/resourceリソースディレクトリの下に置く(以下同じ).プロジェクトに必要な配置情報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
    2.1 Spring配置
    
    <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>
    2.2ログファイルのプロファイルLog 4 jを導入する
    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
    3.Hibernate配置
    Hbernateの構成は主にデータソースdbcpを配置し、Session Factoryを配置し、事務管理器を配置し、その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>
    4.マルチテナント実現
    第3ステップでは、マルチテナントを配置し、2つのタイプのTenantIdResolaverとSchemaBasedMulti TenantConnection Providerに関連する:
    TenantIdResolaverの種類は以下の通りです.
    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;
        }
    
    }
    
    SchemaBasedMulti TenantConnection Providerの種類は以下の通りです.
    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);
        }
    
    }
    5.データベース設計
    PostgreSQLでdatabaseを作成し、exampledbと呼ばれます.schemaを創建して、myschemaといいます.mychemaでテーブルを作成し、ステートメントを作成します.
    create database exampledb;
    create schema myschema;
    set schema 'myschema';
    create table user_info(id varchar(200),name varchar(50),signup_date
    date);
    6.業務entityエンティティを生成する
    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;
        }
    
    }
    
    8.ダオ層を作成する
    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 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")
    @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
    
        }
    
    
    
    }
    
    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 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 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.制御層controlller-14を作成します.视レイヤー-15を作成します.配置サーバテスト