浏览代码

Merge branch 'master' of https://github.com/just-a-stone/hsweb-framework

stone 8 年之前
父节点
当前提交
77072ce2ad
共有 27 个文件被更改,包括 490 次插入177 次删除
  1. 0 3
      hsweb-web-bean/src/main/java/org/hsweb/web/bean/po/quartz/QuartzJob.java
  2. 5 1
      hsweb-web-controller/src/main/java/org/hsweb/web/controller/RestControllerExceptionTranslator.java
  3. 2 6
      hsweb-web-controller/src/main/java/org/hsweb/web/controller/system/DatabaseManagerController.java
  4. 3 2
      hsweb-web-core/src/main/java/org/hsweb/web/core/authorize/validator/SimpleAuthorizeValidator.java
  5. 1 0
      hsweb-web-core/src/main/java/org/hsweb/web/core/datasource/DynamicDataSource.java
  6. 39 0
      hsweb-web-core/src/main/java/org/hsweb/web/core/datasource/DynamicDataSourceHolder.java
  7. 2 4
      hsweb-web-core/src/main/java/org/hsweb/web/core/session/siample/SimpleHttpSessionManager.java
  8. 1 1
      hsweb-web-core/src/main/java/org/hsweb/web/core/session/siample/SimpleHttpSessionManagerAutoConfiguration.java
  9. 38 38
      hsweb-web-core/src/main/java/org/hsweb/web/core/session/siample/UserLoginOutListener.java
  10. 6 0
      hsweb-web-dao/hsweb-web-dao-mybatis/pom.xml
  11. 0 3
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/MybatisDaoAutoConfiguration.java
  12. 77 0
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicDataSourceMyBatisAutoConfiguration.java
  13. 28 0
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicDataSourceSqlSessionFactoryBuilder.java
  14. 145 0
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionFactory.java
  15. 4 31
      hsweb-web-datasource/pom.xml
  16. 6 26
      hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceAutoConfiguration.java
  17. 44 21
      hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceServiceImpl.java
  18. 27 2
      hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceSqlExecutorService.java
  19. 1 1
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/DataBaseAutoConfiguration.java
  20. 33 0
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/basic/SqlExecutorService.java
  21. 1 2
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/form/DynamicFormServiceImpl.java
  22. 20 1
      hsweb-web-service/hsweb-web-service-simple/src/test/java/org/hsweb/web/service/impl/datasource/DatasourceTests.java
  23. 2 1
      hsweb-web-service/hsweb-web-service-simple/src/test/java/org/hsweb/web/service/impl/datasource/TestService.java
  24. 1 0
      hsweb-web-service/hsweb-web-service-simple/src/test/resources/application.yml
  25. 2 1
      hsweb-web-service/hsweb-web-service-simple/src/test/resources/logback.xml
  26. 1 1
      hsweb-web-service/hsweb-web-service-simple/src/test/resources/transactions.properties
  27. 1 32
      pom.xml

+ 0 - 3
hsweb-web-bean/src/main/java/org/hsweb/web/bean/po/quartz/QuartzJob.java

@@ -2,9 +2,6 @@ package org.hsweb.web.bean.po.quartz;
 
 import org.hsweb.web.bean.po.GenericPo;
 
-/**
- * Created by zhouhao on 16-5-20.
- */
 public class QuartzJob extends GenericPo<String> {
     private String name;
 

+ 5 - 1
hsweb-web-controller/src/main/java/org/hsweb/web/controller/RestControllerExceptionTranslator.java

@@ -3,6 +3,8 @@ package org.hsweb.web.controller;
 import com.alibaba.fastjson.JSON;
 import org.hsweb.web.core.exception.*;
 import org.hsweb.web.core.message.ResponseMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.core.annotation.Order;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.*;
@@ -14,6 +16,8 @@ import javax.servlet.http.HttpServletResponse;
 @Order(1)
 public class RestControllerExceptionTranslator {
 
+    private Logger logger = LoggerFactory.getLogger(this.getClass());
+
     @ExceptionHandler(ValidationException.class)
     @ResponseStatus(HttpStatus.BAD_REQUEST)
     @ResponseBody
@@ -36,7 +40,6 @@ public class RestControllerExceptionTranslator {
         return ResponseMessage.error(exception.getMessage(), exception.getStatus());
     }
 
-
     @ExceptionHandler(AuthorizeException.class)
     @ResponseStatus(HttpStatus.UNAUTHORIZED)
     @ResponseBody
@@ -63,6 +66,7 @@ public class RestControllerExceptionTranslator {
     @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     @ResponseBody
     ResponseMessage handleException(Throwable exception) {
+        logger.error("未知错误", exception);
         return ResponseMessage.error(exception.getMessage(), 500);
     }
 

+ 2 - 6
hsweb-web-controller/src/main/java/org/hsweb/web/controller/system/DatabaseManagerController.java

@@ -2,20 +2,16 @@ package org.hsweb.web.controller.system;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import org.hsweb.ezorm.meta.DatabaseMetaData;
 import org.hsweb.ezorm.meta.FieldMetaData;
 import org.hsweb.ezorm.meta.TableMetaData;
 import org.hsweb.ezorm.render.SqlAppender;
-import org.hsweb.ezorm.render.SqlRender;
 import org.hsweb.web.bean.po.user.User;
 import org.hsweb.web.core.authorize.annotation.Authorize;
 import org.hsweb.web.core.datasource.DynamicDataSource;
-import org.hsweb.web.core.exception.AuthorizeException;
 import org.hsweb.web.core.exception.AuthorizeForbiddenException;
 import org.hsweb.web.core.logger.annotation.AccessLogger;
 import org.hsweb.web.core.message.ResponseMessage;
 import org.hsweb.web.core.utils.WebUtil;
-import org.hsweb.web.service.form.DynamicFormService;
 import org.hsweb.web.service.system.DataBaseManagerService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -106,11 +102,11 @@ public class DatabaseManagerController {
                 .forEach(s1 -> {
                     if (s1.trim().endsWith(";")) {
                         s1 = s1.trim();
-                        tmp[0].add(s1.substring(0, s1.length() - 1));
+                        tmp[0].add(s1.substring(0, s1.length() - 1), "\n");
                         sqlList.add(tmp[0]);
                         tmp[0] = new SqlAppender();
                     } else {
-                        tmp[0].add(s1);
+                        tmp[0].add(s1, "\n");
                     }
                 });
         if (!tmp[0].isEmpty()) sqlList.add(tmp[0]);

+ 3 - 2
hsweb-web-core/src/main/java/org/hsweb/web/core/authorize/validator/SimpleAuthorizeValidator.java

@@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * 权限验证器
@@ -43,9 +44,9 @@ public class SimpleAuthorizeValidator implements AuthorizeValidator {
         //验证角色
         if (!roles.isEmpty()) {
             if (mod == Authorize.MOD.AND)
-                access = roles.stream().allMatch(role -> user.hasAccessRole(role));
+                access = roles.stream().allMatch(user::hasAccessRole);
             else
-                access = roles.stream().anyMatch(role -> user.hasAccessRole(role));
+                access = roles.stream().anyMatch(user::hasAccessRole);
         }
         //验证表达式
         if (!expressions.isEmpty()) {

+ 1 - 0
hsweb-web-core/src/main/java/org/hsweb/web/core/datasource/DynamicDataSource.java

@@ -31,6 +31,7 @@ public interface DynamicDataSource extends DataSource {
 
     String DATA_SOURCE_FLAG_LAST = "data-source-id-last";
 
+
     static void useLast() {
         use(ThreadLocalUtils.get(DATA_SOURCE_FLAG_LAST));
     }

+ 39 - 0
hsweb-web-core/src/main/java/org/hsweb/web/core/datasource/DynamicDataSourceHolder.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.web.core.datasource;
+
+
+import javax.sql.DataSource;
+
+public class DynamicDataSourceHolder {
+
+    private static DynamicDataSource dynamicDataSource;
+
+    public static DataSource getActiveSource() {
+        if (dynamicDataSource != null) {
+            return dynamicDataSource.getActiveDataSource();
+        }
+        return null;
+    }
+
+    public static void install(DynamicDataSource dynamicDataSource) {
+        if (DynamicDataSourceHolder.dynamicDataSource != null) {
+            throw new UnsupportedOperationException();
+        }
+        DynamicDataSourceHolder.dynamicDataSource = dynamicDataSource;
+    }
+}

+ 2 - 4
hsweb-web-core/src/main/java/org/hsweb/web/core/session/siample/SimpleHttpSessionManager.java

@@ -1,13 +1,11 @@
-package org.hsweb.web.core.session.siample;
+package org.hsweb.web.core.session.simple;
 
 import org.hsweb.web.bean.po.user.User;
 import org.hsweb.web.core.session.AbstractHttpSessionManager;
-import org.hsweb.web.core.session.HttpSessionManager;
 import org.hsweb.web.core.utils.WebUtil;
 
 import javax.servlet.http.HttpSession;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -55,7 +53,7 @@ public class SimpleHttpSessionManager extends AbstractHttpSessionManager {
                 userSessionStorage.remove(userId);
                 return null;
             }
-            return user.getId();
+            return session.getId();
         }
         return null;
     }

+ 1 - 1
hsweb-web-core/src/main/java/org/hsweb/web/core/session/siample/SimpleHttpSessionManagerAutoConfiguration.java

@@ -1,4 +1,4 @@
-package org.hsweb.web.core.session.siample;
+package org.hsweb.web.core.session.simple;
 
 import org.hsweb.web.core.session.HttpSessionManager;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

+ 38 - 38
hsweb-web-core/src/main/java/org/hsweb/web/core/session/siample/UserLoginOutListener.java

@@ -1,39 +1,39 @@
-package org.hsweb.web.core.session.siample;
-
-import org.hsweb.web.bean.po.user.User;
-import org.hsweb.web.core.session.HttpSessionManager;
-import org.hsweb.web.core.utils.WebUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.servlet.http.HttpSession;
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionListener;
-
-public class UserLoginOutListener implements HttpSessionListener {
-    private Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    private HttpSessionManager httpSessionManager;
-
-    /* Session创建事件 */
-    public void sessionCreated(HttpSessionEvent se) {
-        logger.info("session created:" + se.getSession().getId());
-    }
-
-    /* Session失效事件 */
-    public void sessionDestroyed(HttpSessionEvent se) {
-        HttpSession session = se.getSession();
-        try {
-            User user = WebUtil.getLoginUser(session);
-            if (user != null) {
-                httpSessionManager.removeUser(user.getId());
-            }
-        } catch (Exception e) {
-            logger.error("remove session or user error!", e);
-        }
-    }
-
-    public void setHttpSessionManager(HttpSessionManager httpSessionManager) {
-        this.httpSessionManager = httpSessionManager;
-    }
+package org.hsweb.web.core.session.simple;
+
+import org.hsweb.web.bean.po.user.User;
+import org.hsweb.web.core.session.HttpSessionManager;
+import org.hsweb.web.core.utils.WebUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+public class UserLoginOutListener implements HttpSessionListener {
+    private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    private HttpSessionManager httpSessionManager;
+
+    /* Session创建事件 */
+    public void sessionCreated(HttpSessionEvent se) {
+        logger.info("session created:" + se.getSession().getId());
+    }
+
+    /* Session失效事件 */
+    public void sessionDestroyed(HttpSessionEvent se) {
+        HttpSession session = se.getSession();
+        try {
+            User user = WebUtil.getLoginUser(session);
+            if (user != null) {
+                httpSessionManager.removeUser(user.getId());
+            }
+        } catch (Exception e) {
+            logger.error("remove session or user error!", e);
+        }
+    }
+
+    public void setHttpSessionManager(HttpSessionManager httpSessionManager) {
+        this.httpSessionManager = httpSessionManager;
+    }
 }

+ 6 - 0
hsweb-web-dao/hsweb-web-dao-mybatis/pom.xml

@@ -32,6 +32,12 @@
             <artifactId>spring-boot-starter-jdbc</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.hsweb</groupId>
+            <artifactId>hsweb-web-datasource</artifactId>
+            <optional>true</optional>
+        </dependency>
+
         <!-- mybatis start-->
         <dependency>
             <groupId>org.mybatis.spring.boot</groupId>

+ 0 - 3
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/MybatisDaoAutoConfiguration.java

@@ -9,9 +9,6 @@ import org.springframework.context.annotation.Configuration;
 
 import javax.annotation.PostConstruct;
 
-/**
- * Created by zhouhao on 16-5-6.
- */
 @Configuration
 @ComponentScan(basePackages = {"org.hsweb.web.mybatis"})
 @MapperScan(basePackages = {"org.hsweb.web.dao"})

+ 77 - 0
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicDataSourceMyBatisAutoConfiguration.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.web.mybatis.dynamic;
+
+import org.apache.ibatis.mapping.DatabaseIdProvider;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.hsweb.web.datasource.dynamic.DynamicDataSourceAutoConfiguration;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
+import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.StringUtils;
+
+import javax.sql.DataSource;
+
+@Configuration
+@AutoConfigureAfter(DynamicDataSourceAutoConfiguration.class)
+@EnableConfigurationProperties(MybatisProperties.class)
+@ConditionalOnProperty(prefix = "mybatis", value = "dynamic-datasource")
+public class DynamicDataSourceMyBatisAutoConfiguration {
+
+    @Autowired
+    private MybatisProperties properties;
+
+    @Autowired(required = false)
+    private Interceptor[] interceptors;
+
+    @Autowired
+    private ResourceLoader resourceLoader = new DefaultResourceLoader();
+
+    @Autowired(required = false)
+    private DatabaseIdProvider databaseIdProvider;
+
+    @Bean(name = "sqlSessionFactory")
+    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
+        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
+        factory.setSqlSessionFactoryBuilder(new DynamicDataSourceSqlSessionFactoryBuilder());
+        factory.setDataSource(dataSource);
+        factory.setVfs(SpringBootVFS.class);
+        if (StringUtils.hasText(this.properties.getConfig())) {
+            factory.setConfigLocation(this.resourceLoader.getResource(this.properties
+                    .getConfig()));
+        }
+        if (this.interceptors != null && this.interceptors.length > 0) {
+            factory.setPlugins(this.interceptors);
+        }
+        if (this.databaseIdProvider != null) {
+            factory.setDatabaseIdProvider(this.databaseIdProvider);
+        }
+        factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
+        factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
+        factory.setMapperLocations(this.properties.resolveMapperLocations());
+        return factory.getObject();
+    }
+}

+ 28 - 0
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicDataSourceSqlSessionFactoryBuilder.java

@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.web.mybatis.dynamic;
+
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+
+public class DynamicDataSourceSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
+    @Override
+    public SqlSessionFactory build(Configuration config) {
+            return new DynamicSqlSessionFactory(config);
+    }
+}

+ 145 - 0
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionFactory.java

@@ -0,0 +1,145 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.web.mybatis.dynamic;
+
+import org.apache.ibatis.exceptions.ExceptionFactory;
+import org.apache.ibatis.executor.ErrorContext;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.Environment;
+import org.apache.ibatis.session.*;
+import org.apache.ibatis.session.defaults.DefaultSqlSession;
+import org.apache.ibatis.transaction.Transaction;
+import org.apache.ibatis.transaction.TransactionFactory;
+import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
+import org.hsweb.web.core.datasource.DynamicDataSourceHolder;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * @author zhouhao
+ */
+public class DynamicSqlSessionFactory implements SqlSessionFactory {
+    private final Configuration configuration;
+
+    public DynamicSqlSessionFactory(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public SqlSession openSession() {
+        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
+    }
+
+    @Override
+    public SqlSession openSession(boolean autoCommit) {
+        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
+    }
+
+    @Override
+    public SqlSession openSession(ExecutorType execType) {
+        return openSessionFromDataSource(execType, null, false);
+    }
+
+    @Override
+    public SqlSession openSession(TransactionIsolationLevel level) {
+        return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
+    }
+
+    @Override
+    public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
+        return openSessionFromDataSource(execType, level, false);
+    }
+
+    @Override
+    public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
+        return openSessionFromDataSource(execType, null, autoCommit);
+    }
+
+    @Override
+    public SqlSession openSession(Connection connection) {
+        return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
+    }
+
+    @Override
+    public SqlSession openSession(ExecutorType execType, Connection connection) {
+        return openSessionFromConnection(execType, connection);
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
+        Transaction tx = null;
+        try {
+            final Environment environment = getConfiguration().getEnvironment();
+            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
+            DataSource ds = DynamicDataSourceHolder.getActiveSource();
+            if (ds == null) ds = environment.getDataSource();
+            tx = transactionFactory.newTransaction(ds, level, autoCommit);
+            final Executor executor = getConfiguration().newExecutor(tx, execType);
+            return new DefaultSqlSession(getConfiguration(), executor, autoCommit);
+        } catch (Exception e) {
+            closeTransaction(tx); // may have fetched a connection so lets call close()
+            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
+        } finally {
+            ErrorContext.instance().reset();
+        }
+    }
+
+    private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
+        try {
+            boolean autoCommit;
+            try {
+                autoCommit = connection.getAutoCommit();
+            } catch (SQLException e) {
+                // Failover to true, as most poor drivers
+                // or databases won't support transactions
+                autoCommit = true;
+            }
+            final Environment environment = configuration.getEnvironment();
+            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
+            final Transaction tx = transactionFactory.newTransaction(connection);
+            final Executor executor = configuration.newExecutor(tx, execType);
+            return new DefaultSqlSession(configuration, executor, autoCommit);
+        } catch (Exception e) {
+            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
+        } finally {
+            ErrorContext.instance().reset();
+        }
+    }
+
+    private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
+        if (environment == null || environment.getTransactionFactory() == null) {
+            return new ManagedTransactionFactory();
+        }
+        return environment.getTransactionFactory();
+    }
+
+    private void closeTransaction(Transaction tx) {
+        if (tx != null) {
+            try {
+                tx.close();
+            } catch (SQLException ignore) {
+                // Intentionally ignore. Prefer previous error.
+            }
+        }
+    }
+}

+ 4 - 31
hsweb-web-datasource/pom.xml

@@ -33,11 +33,10 @@
             <artifactId>h2</artifactId>
             <scope>test</scope>
         </dependency>
-
-        <!--<dependency>-->
-            <!--<groupId>org.springframework.boot</groupId>-->
-            <!--<artifactId>spring-boot-starter-web</artifactId>-->
-        <!--</dependency>-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -66,32 +65,6 @@
             <scope>test</scope>
         </dependency>
 
-        <!--atomikos-->
-        <dependency>
-            <groupId>com.atomikos</groupId>
-            <artifactId>transactions-jdbc</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.atomikos</groupId>
-            <artifactId>transactions-jta</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.atomikos</groupId>
-            <artifactId>transactions</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.atomikos</groupId>
-            <artifactId>transactions-api</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.atomikos</groupId>
-            <artifactId>atomikos-util</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>javax.transaction</groupId>
             <artifactId>jta</artifactId>

+ 6 - 26
hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceAutoConfiguration.java

@@ -19,13 +19,11 @@ package org.hsweb.web.datasource.dynamic;
 import com.atomikos.icatch.jta.UserTransactionImp;
 import com.atomikos.icatch.jta.UserTransactionManager;
 import com.atomikos.jdbc.AtomikosDataSourceBean;
-import org.hsweb.commons.StringUtils;
 import org.hsweb.web.core.datasource.DynamicDataSource;
-import org.hsweb.web.service.datasource.DynamicDataSourceService;
+import org.hsweb.web.core.datasource.DynamicDataSourceHolder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
@@ -44,11 +42,6 @@ public class DynamicDataSourceAutoConfiguration {
     @Autowired
     private DataSourceProperties properties;
 
-    static {
-        //  com.atomikos.icatch.config.Configuration.init();
-        //  com.atomikos.icatch.config.Configuration.installCompositeTransactionManager(new CompositeTransactionManagerImp());
-    }
-
     /**
      * 默认数据库链接
      */
@@ -59,29 +52,16 @@ public class DynamicDataSourceAutoConfiguration {
         dataSourceBean.getXaProperties().putAll(properties.getXa().getProperties());
         dataSourceBean.setXaDataSourceClassName(properties.getXa().getDataSourceClassName());
         dataSourceBean.setUniqueResourceName("core");
-        dataSourceBean.setMinPoolSize(StringUtils.toInt(properties.getXa().getProperties().get("minPoolSize"), 5));
-        dataSourceBean.setMaxPoolSize(StringUtils.toInt(properties.getXa().getProperties().get("maxPoolSize"), 200));
-        dataSourceBean.setTestQuery(properties.getXa().getProperties().get("validationQuery"));
-        dataSourceBean.setBorrowConnectionTimeout(60);
+        dataSourceBean.setMinPoolSize(5);
+        dataSourceBean.setMaxPoolSize(200);
         return dataSourceBean;
     }
 
     @Bean(name = "dynamicDataSource")
     public DynamicXaDataSourceImpl dynamicXaDataSource(@Qualifier("dataSource") DataSource dataSource) {
-        return new DynamicXaDataSourceImpl(dataSource);
-    }
-
-    /**
-     * 动态数据源
-     */
-    @Bean(initMethod = "init", destroyMethod = "close")
-    public AtomikosDataSourceBean atomikosDataSourceBean(DynamicXaDataSourceImpl dynamicDataSource) {
-        AtomikosDataSourceBean dataSourceBean = new AtomikosDataSourceBean();
-        dataSourceBean.setXaDataSource(dynamicDataSource);
-        dataSourceBean.setUniqueResourceName("dynamic");
-        dataSourceBean.setMaxPoolSize(StringUtils.toInt(properties.getXa().getProperties().get("maxPoolSize"), 200));
-        dataSourceBean.setBorrowConnectionTimeout(30);
-        return dataSourceBean;
+        DynamicXaDataSourceImpl dynamicXaDataSource = new DynamicXaDataSourceImpl(dataSource);
+        DynamicDataSourceHolder.install(dynamicXaDataSource);
+        return dynamicXaDataSource;
     }
 
     @Bean

+ 44 - 21
hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceServiceImpl.java

@@ -27,7 +27,6 @@ import org.hsweb.web.service.datasource.DynamicDataSourceService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.stereotype.Service;
 
@@ -67,8 +66,9 @@ public class DynamicDataSourceServiceImpl implements DynamicDataSourceService {
         cache.values().stream().map(CacheInfo::getDataSource).forEach(this::closeDataSource);
     }
 
-    protected void closeDataSource(javax.sql.DataSource ds) {
+    protected void closeDataSource(javax.sql.CommonDataSource ds) {
         if (ds instanceof AtomikosDataSourceBean) {
+            closeDataSource(((AtomikosDataSourceBean) ds).getXaDataSource());
             ((AtomikosDataSourceBean) ds).close();
         } else if (ds instanceof Closeable) {
             try {
@@ -84,31 +84,39 @@ public class DynamicDataSourceServiceImpl implements DynamicDataSourceService {
         try {
             DataSource old = dataSourceService.selectByPk(id);
             if (old == null || old.getEnabled() != 1) throw new NotFoundException("数据源不存在或已禁用");
+
             //创建锁
-            ReadWriteLock readWriteLock = lockFactory.createReadWriteLock("datasource.lock." + id);
+            ReadWriteLock readWriteLock = lockFactory.createReadWriteLock("dynamic.ds." + id);
+
             readWriteLock.readLock().tryLock();
+            CacheInfo cacheInfo = null;
             try {
-                CacheInfo cacheInfo = cache.get(id);
+                cacheInfo = cache.get(id);
                 // 缓存存在,并且hash一致
                 if (cacheInfo != null && cacheInfo.getHash() == old.getHash())
                     return cacheInfo;
             } finally {
-                readWriteLock.readLock().unlock();
+                try {
+                    readWriteLock.readLock().unlock();
+                } catch (Exception e) {
+                }
             }
-            //加载datasource到缓存
             readWriteLock.writeLock().tryLock();
             try {
-                javax.sql.DataSource dataSource = createDataSource(old);
-
-                CacheInfo cacheInfo = new CacheInfo(old.getHash(), dataSource);
-                CacheInfo oldCache = cache.put(id, cacheInfo);
-                if (oldCache != null) {
-                    closeDataSource(oldCache.getDataSource());
+                if (cacheInfo != null) {
+                    closeDataSource(cacheInfo.getDataSource());
                 }
-                return cacheInfo;
+                //加载datasource到缓存
+                javax.sql.DataSource dataSource = createDataSource(old);
+                cacheInfo = new CacheInfo(old.getHash(), dataSource);
+                cache.put(id, cacheInfo);
             } finally {
-                readWriteLock.writeLock().unlock();
+                try {
+                    readWriteLock.writeLock().unlock();
+                } catch (Exception e) {
+                }
             }
+            return cacheInfo;
         } finally {
             DynamicDataSource.useLast();
         }
@@ -139,14 +147,29 @@ public class DynamicDataSourceServiceImpl implements DynamicDataSourceService {
         dataSourceBean.setUniqueResourceName("ds_" + dataSource.getId());
         dataSourceBean.setMaxPoolSize(200);
         dataSourceBean.setMinPoolSize(5);
-        dataSourceBean.setTestQuery(dataSource.getTestSql());
         dataSourceBean.setBorrowConnectionTimeout(60);
-        try {
-            dataSourceBean.init();
-        } catch (AtomikosSQLException e) {
-            dataSourceBean.close();
-            throw new RuntimeException(e);
-        }
+        boolean[] success = new boolean[1];
+        //异步初始化
+        new Thread(() -> {
+            try {
+                dataSourceBean.init();
+                success[0] = true;
+            } catch (AtomikosSQLException e) {
+                closeDataSource(dataSourceBean);
+            }
+        }).start();
+        //初始化检测
+        new Thread(() -> {
+            try {
+                Thread.sleep(10000);
+                if (!success[0]) {
+                    logger.error("初始化jdbc超时:{}", dataSourceBean);
+                    closeDataSource(dataSourceBean);
+                }
+            } catch (Exception e) {
+
+            }
+        }).start();
         return dataSourceBean;
     }
 

+ 27 - 2
hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceSqlExecutorService.java

@@ -21,6 +21,7 @@ import org.hsweb.ezorm.executor.SQL;
 import org.hsweb.ezorm.meta.expand.ObjectWrapper;
 import org.hsweb.ezorm.meta.expand.SimpleMapWrapper;
 import org.hsweb.ezorm.render.support.simple.SimpleSQL;
+import org.hsweb.web.core.authorize.ExpressionScopeBean;
 import org.hsweb.web.core.datasource.DynamicDataSource;
 import org.springframework.jdbc.datasource.DataSourceUtils;
 import org.springframework.transaction.annotation.Propagation;
@@ -35,7 +36,7 @@ import java.util.Map;
 /**
  * 动态数据源sql执行器
  */
-public class DynamicDataSourceSqlExecutorService extends AbstractJdbcSqlExecutor {
+public class DynamicDataSourceSqlExecutorService extends AbstractJdbcSqlExecutor implements ExpressionScopeBean {
 
     @Resource
     protected DynamicDataSource dynamicDataSource;
@@ -98,6 +99,31 @@ public class DynamicDataSourceSqlExecutorService extends AbstractJdbcSqlExecutor
         return data;
     }
 
+    @Transactional
+    public int update(String sql, Map<String, Object> param) throws SQLException {
+        return super.update(new SimpleSQL(sql, param));
+    }
+
+    @Transactional
+    public int update(String sql) throws SQLException {
+        return super.update(new SimpleSQL(sql));
+    }
+
+    @Transactional
+    public int delete(String sql, Map<String, Object> param) throws SQLException {
+        return super.delete(new SimpleSQL(sql, param));
+    }
+
+    @Transactional
+    public int delete(String sql) throws SQLException {
+        return super.delete(new SimpleSQL(sql));
+    }
+
+    @Transactional(propagation = Propagation.NOT_SUPPORTED)
+    public void exec(String sql) throws SQLException {
+        super.exec(new SimpleSQL(sql));
+    }
+
     @Override
     @Transactional(propagation = Propagation.NOT_SUPPORTED)
     public void exec(SQL sql) throws SQLException {
@@ -112,5 +138,4 @@ public class DynamicDataSourceSqlExecutorService extends AbstractJdbcSqlExecutor
         SimpleSQL sql1 = new SimpleSQL(sql, param);
         return sql1;
     }
-
 }

+ 1 - 1
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/DataBaseAutoConfiguration.java

@@ -86,7 +86,7 @@ public class DataBaseAutoConfiguration {
         SimpleDatabase dataBase = new SimpleDatabase(dataBaseMetaData, sqlExecutor) {
             @Override
             public Map<String, Object> getTriggerContextRoot() {
-                if (null != null)
+                if (expressionScopeBeanMap != null)
                     return new HashMap<>(expressionScopeBeanMap);
                 return super.getTriggerContextRoot();
             }

+ 33 - 0
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/basic/SqlExecutorService.java

@@ -8,6 +8,7 @@ import org.hsweb.ezorm.render.support.simple.SimpleSQL;
 import org.hsweb.web.core.authorize.ExpressionScopeBean;
 import org.springframework.jdbc.datasource.DataSourceUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
@@ -34,6 +35,7 @@ public class SqlExecutorService extends AbstractJdbcSqlExecutor implements Expre
         DataSourceUtils.releaseConnection(connection, dataSource);
     }
 
+
     @Override
     @Transactional(readOnly = true)
     public <T> List<T> list(SQL sql, ObjectWrapper<T> wrapper) throws SQLException {
@@ -82,6 +84,37 @@ public class SqlExecutorService extends AbstractJdbcSqlExecutor implements Expre
         return data;
     }
 
+    @Transactional
+    public int update(String sql, Map<String, Object> param) throws SQLException {
+        return super.update(new SimpleSQL(sql, param));
+    }
+
+    @Transactional
+    public int update(String sql) throws SQLException {
+        return super.update(new SimpleSQL(sql));
+    }
+
+    @Transactional
+    public int delete(String sql, Map<String, Object> param) throws SQLException {
+        return super.delete(new SimpleSQL(sql, param));
+    }
+
+    @Transactional
+    public int delete(String sql) throws SQLException {
+        return super.delete(new SimpleSQL(sql));
+    }
+
+    @Transactional(propagation = Propagation.NOT_SUPPORTED)
+    public void exec(String sql) throws SQLException {
+        super.exec(new SimpleSQL(sql));
+    }
+
+    @Override
+    @Transactional(propagation = Propagation.NOT_SUPPORTED)
+    public void exec(SQL sql) throws SQLException {
+        super.exec(sql);
+    }
+
     public SQL create(String sql) {
         return new SimpleSQL(sql);
     }

+ 1 - 2
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/form/DynamicFormServiceImpl.java

@@ -33,7 +33,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
@@ -457,6 +456,6 @@ public class DynamicFormServiceImpl implements DynamicFormService, ExpressionSco
 
 
     public static void main(String[] args) {
-        Arrays.asList(1,2,3).forEach(System.out::println);
+        Arrays.asList(1, 2, 3).forEach(System.out::println);
     }
 }

+ 20 - 1
hsweb-web-service/hsweb-web-service-simple/src/test/java/org/hsweb/web/service/impl/datasource/DatasourceTests.java

@@ -17,9 +17,13 @@
 package org.hsweb.web.service.impl.datasource;
 
 import org.hsweb.ezorm.executor.SqlExecutor;
+import org.hsweb.web.bean.common.QueryParam;
 import org.hsweb.web.bean.po.datasource.DataSource;
+import org.hsweb.web.core.Install;
+import org.hsweb.web.core.datasource.DynamicDataSource;
 import org.hsweb.web.service.datasource.DataSourceService;
 import org.hsweb.web.service.impl.AbstractTestCase;
+import org.hsweb.web.service.user.UserService;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -38,13 +42,18 @@ public class DatasourceTests extends AbstractTestCase {
     @Resource
     private TestService testService;
 
+    @Resource
+    private UserService userService;
+    @Resource
+    Install install;
     @PostConstruct
     public void init() {
         testService.setSqlExecutor(sqlExecutor);
     }
 
     @Before
-    public void setup() throws SQLException {
+    public void setup() throws Exception {
+        dataSourceService.delete("test");
         DataSource dataSource = new DataSource();
         dataSource.setId("test");
         dataSource.setName("test");
@@ -53,7 +62,17 @@ public class DatasourceTests extends AbstractTestCase {
         dataSource.setPassword("");
         dataSource.setCreateDate(new Date());
         dataSource.setUrl("jdbc:h2:file:./data/h2db2;DB_CLOSE_ON_EXIT=FALSE");
+
         dataSourceService.insert(dataSource);
+
+        DynamicDataSource.use("test");
+        install.install();//安装新的数据库
+
+        DynamicDataSource.useDefault();
+        userService.select(QueryParam.build());
+        DynamicDataSource.use("test");
+        userService.select(QueryParam.build());
+
     }
 
     @Test

+ 2 - 1
hsweb-web-service/hsweb-web-service-simple/src/test/java/org/hsweb/web/service/impl/datasource/TestService.java

@@ -35,12 +35,13 @@ public class TestService {
     }
 
     @Transactional
-    public void test() throws SQLException {
+    public void test() throws Exception {
         sqlExecutor.exec(new SimpleSQL("drop table if exists s_test"));
         sqlExecutor.exec(new SimpleSQL("create table s_test(name varchar(32))"));
         System.out.println(sqlExecutor.list(new SimpleSQL("select * from s_test"), new SimpleMapWrapper()));
         System.out.println(sqlExecutor.insert(new SimpleSQL("insert into s_test values ('默认数据源')")));
         DynamicDataSource.use("test");
+        Thread.sleep(30000);
         sqlExecutor.exec(new SimpleSQL("drop table if exists s_test"));
         sqlExecutor.exec(new SimpleSQL("create table s_test(name varchar(32))"));
         System.out.println(sqlExecutor.list(new SimpleSQL("select * from s_test"), new SimpleMapWrapper()));

+ 1 - 0
hsweb-web-service/hsweb-web-service-simple/src/test/resources/application.yml

@@ -51,3 +51,4 @@ mybatis:
     mapper-locations: classpath*:org/hsweb/web/dao/impl/mybatis/mapper/oracle/**/*.xml
     config: classpath:mybatis-config.xml
     typeHandlers-package: org.hsweb.web.mybatis.handler
+    dynamic-datasource: on

+ 2 - 1
hsweb-web-service/hsweb-web-service-simple/src/test/resources/logback.xml

@@ -9,9 +9,10 @@
     <logger name="org.springframework" level="ERROR" />
     <logger name="org.apache.tomcat" level="ERROR" />
     <logger name="org.hsweb" level="DEBUG" />
-    <logger name="com.atomikos" level="ON" />
+    <logger name="com.atomikos" level="ERROR" />
     <logger name="org.h2" level="ON" />
     <logger name="org.mybatis.spring.SqlSessionUtils" level="DEBUG" />
+    <logger name="org.hsweb.web.datasource" level="INFO" />
     <root level="ERROR">
         <appender-ref ref="Console"/>
     </root>

+ 1 - 1
hsweb-web-service/hsweb-web-service-simple/src/test/resources/transactions.properties

@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
+com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
 com.atomikos.icatch.serial_jta_transactions=false
 com.atomikos.icatch.output_dir=./data/atomikos
 com.atomikos.icatch.log_base_dir=./data/atomikos

+ 1 - 32
pom.xml

@@ -29,7 +29,7 @@
         <javassist.version>3.20.0-GA</javassist.version>
         <project.build.jdk>${java.version}</project.build.jdk>
 
-        <spring.boot.version>1.3.3.RELEASE</spring.boot.version>
+        <spring.boot.version>1.3.7.RELEASE</spring.boot.version>
         <activiti.version>5.19.0.2</activiti.version>
 
         <fastjson.version>1.2.6</fastjson.version>
@@ -42,7 +42,6 @@
         <hsweb.ezorm.version>1.0-SNAPSHOT</hsweb.ezorm.version>
         <hsweb.commons.version>1.0-SNAPSHOT</hsweb.commons.version>
         <hsweb.expands.version>1.0-SNAPSHOT</hsweb.expands.version>
-        <atomikos.version>4.0.4</atomikos.version>
     </properties>
 
     <build>
@@ -112,36 +111,6 @@
 
     <dependencyManagement>
         <dependencies>
-            <!--atomikos-->
-            <dependency>
-                <groupId>com.atomikos</groupId>
-                <artifactId>transactions-jdbc</artifactId>
-                <version>${atomikos.version}</version>
-            </dependency>
-
-            <dependency>
-                <groupId>com.atomikos</groupId>
-                <artifactId>transactions-jta</artifactId>
-                <version>${atomikos.version}</version>
-            </dependency>
-
-            <dependency>
-                <groupId>com.atomikos</groupId>
-                <artifactId>transactions</artifactId>
-                <version>${atomikos.version}</version>
-            </dependency>
-
-            <dependency>
-                <groupId>com.atomikos</groupId>
-                <artifactId>transactions-api</artifactId>
-                <version>${atomikos.version}</version>
-            </dependency>
-
-            <dependency>
-                <groupId>com.atomikos</groupId>
-                <artifactId>atomikos-util</artifactId>
-                <version>${atomikos.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>javax.transaction</groupId>