Browse Source

一大波优化

zhouhao 8 years ago
parent
commit
85d55a818a
24 changed files with 443 additions and 911 deletions
  1. 25 2
      hsweb-web-controller/src/main/java/org/hsweb/web/controller/ControllerAutoConfiguration.java
  2. 5 6
      hsweb-web-core/src/main/java/org/hsweb/web/core/utils/ThreadLocalUtils.java
  3. 1 1
      hsweb-web-dao/hsweb-web-dao-mybatis/pom.xml
  4. 15 1
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/builder/EasyOrmSqlBuilder.java
  5. 0 80
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionHolder.java
  6. 0 372
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionTemplate.java
  7. 0 293
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionUtils.java
  8. 1 10
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/plgins/pager/PagerInterceptor.java
  9. 5 2
      hsweb-web-dao/hsweb-web-dao-mybatis/src/main/resources/org/hsweb/web/dao/impl/mybatis/mapper/basic/BasicMapper.xml
  10. 4 1
      hsweb-web-dao/hsweb-web-dao-mybatis/src/test/java/org/hsweb/web/mybatis/user/UserMapperTest.java
  11. 21 2
      hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceAutoConfiguration.java
  12. 10 0
      hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceProperties.java
  13. 107 0
      hsweb-web-datasource/src/main/resources/META-INF/spring-configuration-metadata.json
  14. 4 4
      hsweb-web-oauth2/hsweb-web-oauth2-service-simple/src/main/java/org/hsweb/web/oauth2/service/OAuth2ClientServiceImpl.java
  15. 93 30
      hsweb-web-service/hsweb-web-service-api/src/main/java/org/hsweb/web/service/GenericService.java
  16. 2 0
      hsweb-web-service/hsweb-web-service-api/src/main/java/org/hsweb/web/service/form/FormService.java
  17. 3 0
      hsweb-web-service/hsweb-web-service-api/src/main/java/org/hsweb/web/service/quartz/QuartzJobService.java
  18. 39 9
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/AbstractServiceImpl.java
  19. 1 26
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/FormDeployContextLoaderListener.java
  20. 0 1
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/form/DynamicFormServiceImpl.java
  21. 24 2
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/form/FormServiceImpl.java
  22. 76 11
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/quartz/QuartzJobServiceImpl.java
  23. 5 57
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/quartz/SimpleJob.java
  24. 2 1
      hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/user/UserServiceImpl.java

+ 25 - 2
hsweb-web-controller/src/main/java/org/hsweb/web/controller/ControllerAutoConfiguration.java

@@ -1,5 +1,8 @@
 package org.hsweb.web.controller;
 
+import org.hsweb.web.core.datasource.DynamicDataSource;
+import org.hsweb.web.core.utils.ThreadLocalUtils;
+import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
@@ -7,7 +10,9 @@ import org.springframework.context.support.ReloadableResourceBundleMessageSource
 import org.springframework.ui.context.support.ResourceBundleThemeSource;
 import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
 import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.ThemeResolver;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@@ -41,6 +46,24 @@ public class ControllerAutoConfiguration extends WebMvcConfigurerAdapter {
 
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new HandlerInterceptor() {
+            @Override
+            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
+                return true;
+            }
+
+            @Override
+            public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
+                //ThreadLocalUtils.clear();
+            }
+
+            @Override
+            public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
+                ThreadLocalUtils.clear();
+                DynamicDataSource.useDefault();
+            }
+        });
+
         ThemeChangeInterceptor themeChangeInterceptor = new ThemeChangeInterceptor() {
             @Override
             public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
@@ -96,7 +119,7 @@ public class ControllerAutoConfiguration extends WebMvcConfigurerAdapter {
         registry.addInterceptor(themeChangeInterceptor);
     }
 
-    @Bean(name="localeResolver")
+    @Bean(name = "localeResolver")
     public CookieLocaleResolver cookieLocaleResolver() {
         CookieLocaleResolver resolver = new CookieLocaleResolver();
         resolver.setDefaultLocale(Locale.CHINA);
@@ -110,7 +133,7 @@ public class ControllerAutoConfiguration extends WebMvcConfigurerAdapter {
         return resourceBundleThemeSource;
     }
 
-    @Bean(name="themeResolver")
+    @Bean(name = "themeResolver")
     public CookieThemeResolver cookieThemeResolver() {
         CookieThemeResolver cookieThemeResolver = new CookieThemeResolver();
         cookieThemeResolver.setDefaultThemeName("default");

+ 5 - 6
hsweb-web-core/src/main/java/org/hsweb/web/core/utils/ThreadLocalUtils.java

@@ -7,12 +7,7 @@ import java.util.Map;
  * Created by zhouhao on 16-5-26.
  */
 public class ThreadLocalUtils {
-    private static final ThreadLocal<Map<String, Object>> local = new ThreadLocal<Map<String, Object>>() {
-        @Override
-        protected Map<String, Object> initialValue() {
-            return new HashMap<>();
-        }
-    };
+    private static final ThreadLocal<Map<String, Object>> local = ThreadLocal.withInitial(() -> new HashMap<>());
 
     public static <T> T put(String key, T value) {
         local.get().put(key, value);
@@ -23,6 +18,10 @@ public class ThreadLocalUtils {
         local.get().remove(key);
     }
 
+    public static void clear() {
+        local.remove();
+    }
+
     public static <T> T get(String key) {
         return ((T) local.get().get(key));
     }

+ 1 - 1
hsweb-web-dao/hsweb-web-dao-mybatis/pom.xml

@@ -58,7 +58,7 @@
         <dependency>
             <groupId>org.mybatis.spring.boot</groupId>
             <artifactId>mybatis-spring-boot-starter</artifactId>
-            <version>1.1.1</version>
+            <version>1.0.1</version>
         </dependency>
 
         <!--mybatis end-->

+ 15 - 1
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/builder/EasyOrmSqlBuilder.java

@@ -22,6 +22,7 @@ import org.hsweb.web.bean.common.InsertParam;
 import org.hsweb.web.bean.common.UpdateParam;
 import org.hsweb.web.core.datasource.DataSourceHolder;
 import org.hsweb.web.core.datasource.DatabaseType;
+import org.hsweb.web.core.exception.BusinessException;
 import org.hsweb.web.mybatis.plgins.pager.Pager;
 import org.hsweb.web.mybatis.utils.ResultMapsUtils;
 
@@ -135,6 +136,7 @@ public class EasyOrmSqlBuilder {
     }
 
     public String buildUpdateFields(String resultMapId, String tableName, UpdateParam param) {
+        Pager.reset();
         param.excludes("id");
         RDBTableMetaData tableMetaData = createMeta(tableName, resultMapId);
         RDBDatabaseMetaData databaseMetaDate = getActiveDatabase();
@@ -172,12 +174,14 @@ public class EasyOrmSqlBuilder {
     }
 
     public String buildInsertSql(String resultMapId, String tableName, InsertParam param) {
+        Pager.reset();
         RDBTableMetaData tableMetaData = createMeta(tableName, resultMapId);
         SqlRender<InsertParam> render = tableMetaData.getDatabaseMetaData().getRenderer(SqlRender.TYPE.INSERT);
         return render.render(tableMetaData, param).getSql();
     }
 
     public String buildUpdateSql(String resultMapId, String tableName, UpdateParam param) {
+        Pager.reset();
         RDBTableMetaData tableMetaData = createMeta(tableName, resultMapId);
         SqlRender<UpdateParam> render = tableMetaData.getDatabaseMetaData().getRenderer(SqlRender.TYPE.UPDATE);
         return render.render(tableMetaData, param).getSql();
@@ -219,13 +223,23 @@ public class EasyOrmSqlBuilder {
                     if (column == null)
                         column = tableMetaData.findColumn(sort.getName());
                     if (column == null) return;
-                    appender.add(column.getName(), " ", sort.getOrder(), ",");
+                    String cname = column.getName();
+                    if (!cname.contains(".")) cname = tableName.concat(".").concat(cname);
+                    appender.add(encodeColumn(tableMetaData.getDatabaseMetaData().getDialect(), cname), " ", sort.getOrder(), ",");
                 });
         if (appender.isEmpty()) return "";
         appender.removeLast();
         return appender.toString();
     }
 
+    public String buildWhereForUpdate(String resultMapId, String tableName, List<Term> terms) {
+        String where = buildWhere(resultMapId, tableName, terms);
+        if (where.trim().isEmpty()) {
+            throw new BusinessException("禁止执行无条件的更新操作");
+        }
+        return where;
+    }
+
     public String buildWhere(String resultMapId, String tableName, List<Term> terms) {
         RDBTableMetaData tableMetaData = createMeta(tableName, resultMapId);
         RDBDatabaseMetaData databaseMetaDate = getActiveDatabase();

+ 0 - 80
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionHolder.java

@@ -1,80 +0,0 @@
-/**
- * Copyright 2010-2015 the original author or authors.
- * <p>
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.SqlSession;
-import org.hsweb.web.core.datasource.DynamicDataSource;
-import org.springframework.transaction.support.ResourceHolderSupport;
-
-import java.util.*;
-
-public final class DynamicSqlSessionHolder extends ResourceHolderSupport {
-
-    private Map<String, SqlSession> sqlSessionMap;
-
-    public DynamicSqlSessionHolder() {
-        sqlSessionMap = new HashMap<>();
-    }
-
-    public SqlSession getSqlSession() {
-        return sqlSessionMap.get(getDataSourceId());
-    }
-
-    public void remove() {
-        sqlSessionMap.remove(getDataSourceId());
-    }
-
-    public void remove(String dataSourceId) {
-        sqlSessionMap.remove(dataSourceId);
-    }
-
-    public Collection<SqlSession> getAllSqlSession() {
-        return sqlSessionMap.values();
-    }
-
-    public void close() {
-        List<Exception> exceptions = new ArrayList<>();
-        sqlSessionMap.forEach((id, sqlSession) -> {
-            try {
-                sqlSession.close();
-            } catch (Exception e) {
-                exceptions.add(e);
-            }
-        });
-        sqlSessionMap.clear();
-        //todo 异常未处理
-        //   if (exceptions.size() > 0) throw new RuntimeException(exceptions.get(0));
-    }
-
-    public void commit() {
-        sqlSessionMap.values().forEach(SqlSession::commit);
-    }
-
-    public void setSqlSession(SqlSession sqlSession) {
-        sqlSessionMap.put(getDataSourceId(), sqlSession);
-    }
-
-
-    public void setSqlSession(String dataSourceId, SqlSession sqlSession) {
-        sqlSessionMap.put(dataSourceId, sqlSession);
-    }
-
-    public String getDataSourceId() {
-        String id = DynamicDataSource.getActiveDataSourceId();
-        if (null == id) return "default";
-        return id;
-    }
-}

+ 0 - 372
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionTemplate.java

@@ -1,372 +0,0 @@
-/**
- * Copyright 2010-2015 the original author or authors.
- * <p>
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.PersistenceException;
-import org.apache.ibatis.executor.BatchResult;
-import org.apache.ibatis.session.*;
-import org.mybatis.spring.MyBatisExceptionTranslator;
-import org.mybatis.spring.SqlSessionTemplate;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.dao.support.PersistenceExceptionTranslator;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.sql.Connection;
-import java.util.List;
-import java.util.Map;
-
-import static java.lang.reflect.Proxy.newProxyInstance;
-import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;
-import static org.hsweb.web.mybatis.dynamic.DynamicSqlSessionUtils.*;
-import static org.springframework.util.Assert.notNull;
-
-public class DynamicSqlSessionTemplate extends SqlSessionTemplate implements SqlSession, DisposableBean {
-
-    private final SqlSessionFactory sqlSessionFactory;
-
-    private final ExecutorType executorType;
-
-    private final SqlSession sqlSessionProxy;
-
-    private final PersistenceExceptionTranslator exceptionTranslator;
-
-    /**
-     * Constructs a Spring managed SqlSession with the {@code SqlSessionFactory}
-     * provided as an argument.
-     *
-     * @param sqlSessionFactory
-     */
-    public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
-        this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
-    }
-
-    /**
-     * Constructs a Spring managed SqlSession with the {@code SqlSessionFactory}
-     * provided as an argument and the given {@code ExecutorType}
-     * {@code ExecutorType} cannot be changed once the {@code SqlSessionTemplate}
-     * is constructed.
-     *
-     * @param sqlSessionFactory
-     * @param executorType
-     */
-    public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
-        this(sqlSessionFactory, executorType,
-                new MyBatisExceptionTranslator(
-                        sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
-    }
-
-    /**
-     * Constructs a Spring managed {@code SqlSession} with the given
-     * {@code SqlSessionFactory} and {@code ExecutorType}.
-     * A custom {@code SQLExceptionTranslator} can be provided as an
-     * argument so any {@code PersistenceException} thrown by MyBatis
-     * can be custom translated to a {@code RuntimeException}
-     * The {@code SQLExceptionTranslator} can also be null and thus no
-     * exception translation will be done and MyBatis exceptions will be
-     * thrown
-     *
-     * @param sqlSessionFactory
-     * @param executorType
-     * @param exceptionTranslator
-     */
-    public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
-                                     PersistenceExceptionTranslator exceptionTranslator) {
-        super(sqlSessionFactory, executorType);
-
-        notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
-        notNull(executorType, "Property 'executorType' is required");
-
-        this.sqlSessionFactory = sqlSessionFactory;
-        this.executorType = executorType;
-        this.exceptionTranslator = exceptionTranslator;
-        this.sqlSessionProxy = (SqlSession) newProxyInstance(
-                SqlSessionFactory.class.getClassLoader(),
-                new Class[]{SqlSession.class},
-                new SqlSessionInterceptor());
-    }
-
-    public SqlSessionFactory getSqlSessionFactory() {
-        return this.sqlSessionFactory;
-    }
-
-    public ExecutorType getExecutorType() {
-        return this.executorType;
-    }
-
-    public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
-        return this.exceptionTranslator;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <T> T selectOne(String statement) {
-        return this.sqlSessionProxy.<T>selectOne(statement);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <T> T selectOne(String statement, Object parameter) {
-        return this.sqlSessionProxy.<T>selectOne(statement, parameter);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
-        return this.sqlSessionProxy.<K, V>selectMap(statement, mapKey);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
-        return this.sqlSessionProxy.<K, V>selectMap(statement, parameter, mapKey);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
-        return this.sqlSessionProxy.<K, V>selectMap(statement, parameter, mapKey, rowBounds);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <E> List<E> selectList(String statement) {
-        return this.sqlSessionProxy.<E>selectList(statement);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <E> List<E> selectList(String statement, Object parameter) {
-        return this.sqlSessionProxy.<E>selectList(statement, parameter);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
-        return this.sqlSessionProxy.<E>selectList(statement, parameter, rowBounds);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void select(String statement, ResultHandler handler) {
-        this.sqlSessionProxy.select(statement, handler);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void select(String statement, Object parameter, ResultHandler handler) {
-        this.sqlSessionProxy.select(statement, parameter, handler);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
-        this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int insert(String statement) {
-        return this.sqlSessionProxy.insert(statement);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int insert(String statement, Object parameter) {
-        return this.sqlSessionProxy.insert(statement, parameter);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int update(String statement) {
-        return this.sqlSessionProxy.update(statement);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int update(String statement, Object parameter) {
-        return this.sqlSessionProxy.update(statement, parameter);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int delete(String statement) {
-        return this.sqlSessionProxy.delete(statement);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int delete(String statement, Object parameter) {
-        return this.sqlSessionProxy.delete(statement, parameter);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public <T> T getMapper(Class<T> type) {
-        return getConfiguration().getMapper(type, this);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void commit() {
-        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void commit(boolean force) {
-        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void rollback() {
-        throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void rollback(boolean force) {
-        throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void close() {
-        throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void clearCache() {
-        this.sqlSessionProxy.clearCache();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Configuration getConfiguration() {
-        return this.sqlSessionFactory.getConfiguration();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Connection getConnection() {
-        return this.sqlSessionProxy.getConnection();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @since 1.0.2
-     */
-    @Override
-    public List<BatchResult> flushStatements() {
-        return this.sqlSessionProxy.flushStatements();
-    }
-
-    @Override
-    public void destroy() throws Exception {
-    }
-
-    private class SqlSessionInterceptor implements InvocationHandler {
-        @Override
-        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-            SqlSession sqlSession = getSqlSession(
-                    DynamicSqlSessionTemplate.this.sqlSessionFactory,
-                    DynamicSqlSessionTemplate.this.executorType,
-                    DynamicSqlSessionTemplate.this.exceptionTranslator);
-
-            try {
-                Object result = method.invoke(sqlSession, args);
-                if (!isSqlSessionTransactional(sqlSession, DynamicSqlSessionTemplate.this.sqlSessionFactory)) {
-                    // force commit even on non-dirty sessions because some databases require
-                    // a commit/rollback before calling close()
-                    sqlSession.commit(true);
-                }
-                return result;
-            } catch (Throwable t) {
-                Throwable unwrapped = unwrapThrowable(t);
-                if (DynamicSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
-                    // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
-                    closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.sqlSessionFactory);
-                    sqlSession = null;
-                    Throwable translated = DynamicSqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
-                    if (translated != null) {
-                        unwrapped = translated;
-                    }
-                }
-                throw unwrapped;
-            } finally {
-                if (sqlSession != null) {
-                    closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.sqlSessionFactory);
-                }
-            }
-        }
-    }
-
-}

+ 0 - 293
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/dynamic/DynamicSqlSessionUtils.java

@@ -1,293 +0,0 @@
-/**
- * Copyright 2010-2015 the original author or authors.
- * <p>
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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 static org.springframework.util.Assert.notNull;
-
-import org.apache.ibatis.exceptions.PersistenceException;
-import org.apache.ibatis.logging.Log;
-import org.apache.ibatis.logging.LogFactory;
-import org.apache.ibatis.mapping.Environment;
-import org.apache.ibatis.session.ExecutorType;
-import org.apache.ibatis.session.SqlSession;
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.hsweb.web.core.datasource.DataSourceHolder;
-import org.mybatis.spring.SqlSessionHolder;
-import org.mybatis.spring.SqlSessionUtils;
-import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
-import org.springframework.dao.DataAccessException;
-import org.springframework.dao.TransientDataAccessResourceException;
-import org.springframework.dao.support.PersistenceExceptionTranslator;
-import org.springframework.jdbc.datasource.DataSourceUtils;
-import org.springframework.transaction.support.TransactionSynchronizationAdapter;
-import org.springframework.transaction.support.TransactionSynchronizationManager;
-
-import javax.sql.DataSource;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Handles MyBatis SqlSession life cycle. It can register and get SqlSessions from
- * Spring {@code TransactionSynchronizationManager}. Also works if no transaction is active.
- *
- * @author Hunter Presnall
- * @author Eduardo Macarron
- * @version $Id$
- */
-public final class DynamicSqlSessionUtils {
-
-    private static final Log LOGGER = LogFactory.getLog(DynamicSqlSessionUtils.class);
-
-    private static final String NO_EXECUTOR_TYPE_SPECIFIED       = "No ExecutorType specified";
-    private static final String NO_SQL_SESSION_FACTORY_SPECIFIED = "No SqlSessionFactory specified";
-    private static final String NO_SQL_SESSION_SPECIFIED         = "No SqlSession specified";
-
-    /**
-     * This class can't be instantiated, exposes static utility methods only.
-     */
-    private DynamicSqlSessionUtils() {
-        // do nothing
-    }
-
-    /**
-     * Creates a new MyBatis {@code SqlSession} from the {@code SqlSessionFactory}
-     * provided as a parameter and using its {@code DataSource} and {@code ExecutorType}
-     *
-     * @param sessionFactory a MyBatis {@code SqlSessionFactory} to create new sessions
-     * @return a MyBatis {@code SqlSession}
-     * @throws TransientDataAccessResourceException if a transaction is active and the
-     *                                              {@code SqlSessionFactory} is not using a {@code SpringManagedTransactionFactory}
-     */
-    public static SqlSession getSqlSession(SqlSessionFactory sessionFactory) {
-        ExecutorType executorType = sessionFactory.getConfiguration().getDefaultExecutorType();
-        return getSqlSession(sessionFactory, executorType, null);
-    }
-
-    static final String SQL_SESSION_RESOURCE_KEY = "dynamic-sqlSession";
-
-    /**
-     * Gets an SqlSession from Spring Transaction Manager or creates a new one if needed.
-     * Tries to get a SqlSession out of current transaction. If there is not any, it creates a new one.
-     * Then, it synchronizes the SqlSession with the transaction if Spring TX is active and
-     * <code>SpringManagedTransactionFactory</code> is configured as a transaction manager.
-     *
-     * @param sessionFactory      a MyBatis {@code SqlSessionFactory} to create new sessions
-     * @param executorType        The executor type of the SqlSession to create
-     * @param exceptionTranslator Optional. Translates SqlSession.commit() exceptions to Spring exceptions.
-     * @throws TransientDataAccessResourceException if a transaction is active and the
-     *                                              {@code SqlSessionFactory} is not using a {@code SpringManagedTransactionFactory}
-     * @see SpringManagedTransactionFactory
-     */
-    public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
-
-        notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
-        notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
-        DynamicSqlSessionHolder holder = (DynamicSqlSessionHolder) TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY);
-        if (holder == null) {
-            TransactionSynchronizationManager.bindResource(SQL_SESSION_RESOURCE_KEY, holder = new DynamicSqlSessionHolder());
-        }
-        SqlSession session = holder.getSqlSession();
-        if (session != null) {
-            return session;
-        }
-
-        if (LOGGER.isDebugEnabled()) {
-            LOGGER.debug("Creating a new SqlSession for datasource " + holder.getDataSourceId());
-        }
-
-        session = sessionFactory.openSession(executorType);
-        if (TransactionSynchronizationManager.isSynchronizationActive()) {
-            TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(session, holder));
-            if (!holder.isSynchronizedWithTransaction()) {
-                holder.setSynchronizedWithTransaction(true);
-                holder.requested();
-            }
-
-        }
-        holder.setSqlSession(session);
-        return session;
-    }
-
-    /**
-     * Checks if {@code SqlSession} passed as an argument is managed by Spring {@code TransactionSynchronizationManager}
-     * If it is not, it closes it, otherwise it just updates the reference counter and
-     * lets Spring call the close callback when the managed transaction ends
-     *
-     * @param session
-     * @param sessionFactory
-     */
-    public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
-        notNull(session, NO_SQL_SESSION_SPECIFIED);
-        notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
-        DynamicSqlSessionHolder holder = (DynamicSqlSessionHolder) TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY);
-        if ((holder != null) && (holder.getAllSqlSession().contains(session))) {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug("Releasing transactional SqlSession [" + session + "]");
-            }
-            holder.released();
-        } else {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug("Closing non transactional SqlSession [" + session + "]");
-            }
-            session.close();
-        }
-    }
-
-    /**
-     * Returns if the {@code SqlSession} passed as an argument is being managed by Spring
-     *
-     * @param session        a MyBatis SqlSession to check
-     * @param sessionFactory the SqlSessionFactory which the SqlSession was built with
-     * @return true if session is transactional, otherwise false
-     */
-    public static boolean isSqlSessionTransactional(SqlSession session, SqlSessionFactory sessionFactory) {
-        notNull(session, NO_SQL_SESSION_SPECIFIED);
-        notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
-        DynamicSqlSessionHolder holder = (DynamicSqlSessionHolder) TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY);
-
-        return (holder != null) && (holder.getAllSqlSession().contains(session));
-    }
-
-    /**
-     * Callback for cleaning up resources. It cleans TransactionSynchronizationManager and
-     * also commits and closes the {@code SqlSession}.
-     * It assumes that {@code Connection} life cycle will be managed by
-     * {@code DataSourceTransactionManager} or {@code JtaTransactionManager}
-     */
-    private static final class SqlSessionSynchronization extends TransactionSynchronizationAdapter {
-
-        private final DynamicSqlSessionHolder holder;
-
-        private boolean holderActive = true;
-
-        private SqlSession sqlSession;
-
-        private String dataSourceId;
-
-        public SqlSessionSynchronization(SqlSession sqlSession, DynamicSqlSessionHolder holder) {
-            notNull(holder, "Parameter 'holder' must be not null");
-            this.holder = holder;
-            this.sqlSession = sqlSession;
-            this.dataSourceId = holder.getDataSourceId();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getOrder() {
-            // order right before any Connection synchronization
-            return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 1;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void suspend() {
-            if (this.holderActive) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Transaction synchronization suspending SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                }
-                holder.remove(dataSourceId);
-                if (holder.getAllSqlSession().isEmpty() && TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY) != null)
-                    TransactionSynchronizationManager.unbindResource(SQL_SESSION_RESOURCE_KEY);
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void resume() {
-            if (this.holderActive) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Transaction synchronization resuming SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                }
-                holder.setSqlSession(dataSourceId, sqlSession);
-                if (TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY) == null)
-                    TransactionSynchronizationManager.bindResource(SQL_SESSION_RESOURCE_KEY, this.holder);
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void beforeCommit(boolean readOnly) {
-            // Connection commit or rollback will be handled by ConnectionSynchronization or
-            // DataSourceTransactionManager.
-            // But, do cleanup the SqlSession / Executor, including flushing BATCH statements so
-            // they are actually executed.
-            // SpringManagedTransaction will no-op the commit over the jdbc connection
-            // TODO This updates 2nd level caches but the tx may be rolledback later on!
-            if (TransactionSynchronizationManager.isActualTransactionActive()) {
-                try {
-                    if (LOGGER.isDebugEnabled()) {
-                        LOGGER.debug("Transaction synchronization committing SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                    }
-                    sqlSession.commit();
-                } catch (PersistenceException p) {
-                    throw p;
-                }
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void beforeCompletion() {
-            // Issue #18 Close SqlSession and deregister it now
-            // because afterCompletion may be called from a different thread
-            if (!this.holder.isOpen()) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Transaction synchronization deregistering SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                }
-                holder.remove(dataSourceId);
-                if (holder.getAllSqlSession().isEmpty() && TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY) != null)
-                    TransactionSynchronizationManager.unbindResource(SQL_SESSION_RESOURCE_KEY);
-                this.holderActive = false;
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Transaction synchronization closing SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                }
-                sqlSession.close();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void afterCompletion(int status) {
-            if (this.holderActive) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Transaction synchronization deregistering SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                }
-                holder.remove(dataSourceId);
-                if (holder.getAllSqlSession().isEmpty() && TransactionSynchronizationManager.getResource(SQL_SESSION_RESOURCE_KEY) != null)
-                    TransactionSynchronizationManager.unbindResource(SQL_SESSION_RESOURCE_KEY);
-                this.holderActive = false;
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Transaction synchronization closing SqlSession [" + sqlSession + "] for dataSource :" + dataSourceId);
-                }
-                sqlSession.close();
-            }
-            //this.holder.reset();
-        }
-    }
-
-}

+ 1 - 10
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/java/org/hsweb/web/mybatis/plgins/pager/PagerInterceptor.java

@@ -39,21 +39,12 @@ public class PagerInterceptor implements Interceptor {
             MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
             String sql = statementHandler.getBoundSql().getSql();
             Pager pager = Pager.getAndReset();
-            if (pager != null) {
+            if (pager != null && sql.trim().toLowerCase().startsWith("select")) {
                 String newSql = EasyOrmSqlBuilder.getInstance()
                         .getActiveDatabase().getDialect()
                         .doPaging(sql, pager.pageIndex(), pager.pageSize());
                 metaStatementHandler.setValue("delegate.boundSql.sql", newSql);
             }
-//            else if (obj instanceof QueryParam) {
-//                QueryParam param = (QueryParam) obj;
-//                if (param.isPaging()) {
-//                    String newSql = EasyOrmSqlBuilder.getInstance()
-//                            .getActiveDatabase().getDialect()
-//                            .doPaging(sql, param.getPageIndex(), param.getPageSize());
-//                    metaStatementHandler.setValue("delegate.boundSql.sql", newSql);
-//                }
-//            }
         }
         return Plugin.wrap(target, this);
     }

+ 5 - 2
hsweb-web-dao/hsweb-web-dao-mybatis/src/main/resources/org/hsweb/web/dao/impl/mybatis/mapper/basic/BasicMapper.xml

@@ -7,6 +7,9 @@
     <sql id="buildWhere">
         ${@org.hsweb.web.mybatis.builder.SqlBuilder@current().buildWhere(resultMapId,tableName,#this['_parameter'].terms)}
     </sql>
+    <sql id="buildWhereForUpdate">
+        ${@org.hsweb.web.mybatis.builder.SqlBuilder@current().buildWhereForUpdate(resultMapId,tableName,#this['_parameter'].terms)}
+    </sql>
 
     <!--生成查询字段-->
     <sql id="buildSelectField">
@@ -43,7 +46,7 @@
         <trim>
             delete from ${tableName}
             <where>
-                <include refid="BasicMapper.buildWhere"/>
+                <include refid="BasicMapper.buildWhereForUpdate"/>
                 <if test="terms.size()==0">
                     1=2
                 </if>
@@ -62,7 +65,7 @@
             update ${tableName}
             <include refid="BasicMapper.buildUpdateField"/>
             <where>
-                <include refid="BasicMapper.buildWhere"/>
+                <include refid="BasicMapper.buildWhereForUpdate"/>
                 <if test="terms.size()==0">
                     u_id=#{data.id}
                 </if>

+ 4 - 1
hsweb-web-dao/hsweb-web-dao-mybatis/src/test/java/org/hsweb/web/mybatis/user/UserMapperTest.java

@@ -31,6 +31,8 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 
 import static org.hsweb.ezorm.rdb.render.dialect.Dialect.TermTypeMapper.sql;
@@ -67,7 +69,8 @@ public class UserMapperTest extends AbstractTestCase {
         user.setName("test");
         Pager.doPaging(0, 20);
         Query.forList(userMapper::select, new QueryParam())
-                .where("username", sql("username is not null"))
+                .sql("username is not null")
+                .or().sql("username=#{username}", Collections.singletonMap("username", "root"))
                 .fromBean(user)
                 .$like$("username").list();
     }

+ 21 - 2
hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceAutoConfiguration.java

@@ -16,15 +16,20 @@
 
 package org.hsweb.web.datasource.dynamic;
 
+import com.atomikos.icatch.config.UserTransactionService;
+import com.atomikos.icatch.config.UserTransactionServiceImp;
 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.DataSourceHolder;
 import org.hsweb.web.core.datasource.DynamicDataSource;
 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.transaction.jta.JtaAutoConfiguration;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.jta.atomikos.AtomikosProperties;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
@@ -34,6 +39,7 @@ import org.springframework.transaction.jta.JtaTransactionManager;
 
 import javax.sql.DataSource;
 import javax.transaction.SystemException;
+import java.util.Properties;
 
 @Configuration
 @ConditionalOnMissingBean(DynamicDataSource.class)
@@ -44,6 +50,17 @@ public class DynamicDataSourceAutoConfiguration {
     @Autowired
     private DynamicDataSourceProperties properties;
 
+    @Bean(initMethod = "init", destroyMethod = "shutdownForce")
+    public UserTransactionServiceImp userTransactionService() {
+        AtomikosProperties atomikosProperties = properties.getIcatch();
+        Properties properties = new Properties();
+        properties.putAll(atomikosProperties.asProperties());
+        if (StringUtils.isNullOrEmpty(properties.get("com.atomikos.icatch.service"))) {
+            properties.put("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
+        }
+        return new UserTransactionServiceImp(properties);
+    }
+
     /**
      * 默认数据库链接
      */
@@ -64,10 +81,12 @@ public class DynamicDataSourceAutoConfiguration {
         return dynamicXaDataSource;
     }
 
-    @Bean
-    public UserTransactionManager userTransactionManager() {
+    @Bean(initMethod = "init", destroyMethod = "close")
+    public UserTransactionManager userTransactionManager(
+            UserTransactionService userTransactionService) {
         UserTransactionManager transactionManager = new UserTransactionManager();
         transactionManager.setForceShutdown(true);
+        transactionManager.setStartupTransactionService(false);
         return transactionManager;
     }
 

+ 10 - 0
hsweb-web-datasource/src/main/java/org/hsweb/web/datasource/dynamic/DynamicDataSourceProperties.java

@@ -21,6 +21,7 @@ import org.hsweb.web.core.datasource.DatabaseType;
 import org.springframework.beans.factory.BeanClassLoaderAware;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jta.atomikos.AtomikosProperties;
 import org.springframework.util.Assert;
 import org.springframework.util.ClassUtils;
 import org.springframework.util.StringUtils;
@@ -56,6 +57,7 @@ public class DynamicDataSourceProperties
     private Properties            properties              = null;
     private ClassLoader           classLoader             = null;
     private DatasourceTypeSupport datasourceTypeSupport   = null;
+    private AtomikosProperties    icatch      = new AtomikosProperties();
 
     public int getTransactionTimeout() {
         return transactionTimeout;
@@ -88,6 +90,14 @@ public class DynamicDataSourceProperties
         return type;
     }
 
+    public AtomikosProperties getIcatch() {
+        return icatch;
+    }
+
+    public void setIcatch(AtomikosProperties icatch) {
+        this.icatch = icatch;
+    }
+
     public void setType(DatabaseType type) {
         this.type = type;
     }

+ 107 - 0
hsweb-web-datasource/src/main/resources/META-INF/spring-configuration-metadata.json

@@ -96,6 +96,96 @@
       "name": "hsweb.dynamic-datasource.properties",
       "type": "java.util.Properties",
       "sourceType": "org.hsweb.web.datasource.dynamic.DynamicDataSourceProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch",
+      "type": "org.springframework.boot.jta.atomikos.AtomikosProperties",
+      "sourceType": "org.hsweb.web.datasource.dynamic.DynamicDataSourceProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.service",
+      "type": "String",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.max-timeout",
+      "type": "long",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.default-jta-timeout",
+      "type": "long",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.max-actives",
+      "type": "int",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.enable-logging",
+      "type": "boolean",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.transaction-manager-unique-name",
+      "type": "String",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.serial-jta-transactions",
+      "type": "boolean",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.force-shutdown-on-vm-exit",
+      "type": "boolean",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.log-base-name",
+      "type": "String",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.log-base-dir",
+      "type": "String",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.checkpoint-interval",
+      "type": "long",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.console-log-level",
+      "type": "org.springframework.boot.jta.atomikos.AtomikosLoggingLevel",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.output-dir",
+      "type": "String",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.console-file-name",
+      "type": "String",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.console-file-count",
+      "type": "int",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.console-file-limit",
+      "type": "int",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.threaded-2pc",
+      "type": "boolean",
+      "sourceType": "org.springframework.boot.jta.atomikos.AtomikosProperties"
     }
   ],
   "hints": [
@@ -115,6 +205,23 @@
           "description": "use oracle database."
         }
       ]
+    },
+    {
+      "name": "hsweb.dynamic-datasource.icatch.console-log-level",
+      "values": [
+        {
+          "value": "INFO",
+          "description": "INFO LEVEL."
+        },
+        {
+          "value": "DEBUG",
+          "description": "DEBUG LEVEL."
+        },
+        {
+          "value": "WARN",
+          "description": "ERROR LEVEL."
+        }
+      ]
     }
   ]
 }

+ 4 - 4
hsweb-web-oauth2/hsweb-web-oauth2-service-simple/src/main/java/org/hsweb/web/oauth2/service/OAuth2ClientServiceImpl.java

@@ -72,7 +72,7 @@ public class OAuth2ClientServiceImpl extends AbstractServiceImpl<OAuth2Client, S
     @Override
     public String refreshSecret(String clientId) {
         String secret = MD5.encode(UUID.randomUUID().toString() + Math.random());
-        int size = oAuth2ClientMapper.update((UpdateParam) UpdateMapParam.build().set("secret", secret).where("id", clientId));
+        int size = createUpdate().set("secret", secret).where("id", clientId).exec();
         if (size != 1) throw new NotFoundException("客户端不存在");
         return secret;
     }
@@ -81,18 +81,18 @@ public class OAuth2ClientServiceImpl extends AbstractServiceImpl<OAuth2Client, S
     public void enable(String id) {
         OAuth2Client old = selectByPk(id);
         assertNotNull(old, "客户端不存在");
-        oAuth2ClientMapper.update((UpdateParam) UpdateMapParam.build().set("status", 1).where("id", id));
+        createUpdate().set("status", 1).where("id", id).exec();
     }
 
     @Override
     public void disable(String id) {
         OAuth2Client old = selectByPk(id);
         assertNotNull(old, "客户端不存在");
-        oAuth2ClientMapper.update((UpdateParam) UpdateMapParam.build().set("status", -1).where("id", id));
+        createUpdate().set("status", -1).where("id", id).exec();
     }
 
     @Override
     public int update(OAuth2Client data) {
-        return getMapper().update(UpdateParam.build(data).excludes("secret","status").where("id", data.getId()));
+        return createUpdate(data).excludes("secret", "status").where("id", data.getId()).exec();
     }
 }

+ 93 - 30
hsweb-web-service/hsweb-web-service-api/src/main/java/org/hsweb/web/service/GenericService.java

@@ -12,8 +12,10 @@ import java.util.List;
 
 
 /**
- * 通用Service。继承了通用mapper的常用增删改查方法
- * <p>
+ * 通用Service,实现增删改查
+ *
+ * @author zhouhao
+ * @since 1.0
  */
 public interface GenericService<Po, Pk> {
 
@@ -34,17 +36,18 @@ public interface GenericService<Po, Pk> {
      */
     Pk insert(Po data);
 
+    /**
+     * 此方法即将删除
+     */
+    @Deprecated
     default List<Pk> batchInsert(List<Po> data) {
         return batchInsert(data, false);
     }
 
     /**
-     * 批量添加数据
-     *
-     * @param data     数据集合
-     * @param skipFail 是否跳过验证失败的的数据
-     * @return 添加后产生的主键集合
+     * 此方法即将删除
      */
+    @Deprecated
     List<Pk> batchInsert(List<Po> data, boolean skipFail);
 
     /**
@@ -71,24 +74,21 @@ public interface GenericService<Po, Pk> {
      */
     int update(List<Po> data);
 
+    /**
+     * 保存或修改
+     *
+     * @param po 要修改的数据
+     * @return
+     */
     int saveOrUpdate(Po po);
 
     /**
-     * 根据条件集合查询记录,支持分页,排序。
-     * <br/>查询条件支持 类似$LIKE,$IN 表达式查询,如传入 name$LIKE 则进行name字段模糊查询
-     * <br/>$LIKE -->模糊查询 (只支持字符)
-     * <br/>$START -->以?开始 (只支持字符 和数字)
-     * <br/>$END -->以?结尾 (只支持字符 和数字)
-     * <br/>$IN -->in查询,参数必须为List实现,传入类似 1,2,3 是非法的
-     * <br/>$GT -->大于 (只支持 数字和日期)
-     * <br/>$LT -->小于 (只支持 数字和日期)
-     * <br/>$NOT -->不等于
-     * <br/>$NOTNULL -->值不为空
-     * <br/>$ISNULL -->值为空
-     * <br/>所有操作支持取反
+     * 根据查询参数进行查询,参数可使用 {@link Query}进行构建
+     * 推荐使用 {@link this#createQuery()}进行查询
      *
      * @param param 查询参数
      * @return 查询结果
+     * @see Query
      */
     List<Po> select(QueryParam param);
 
@@ -113,7 +113,7 @@ public interface GenericService<Po, Pk> {
      *
      * @param param 查询条件
      * @return 单个结果
-     * @
+     * @see this#select(QueryParam)
      */
     default Po selectSingle(QueryParam param) {
         param.doPaging(0, 1);
@@ -122,41 +122,104 @@ public interface GenericService<Po, Pk> {
         else return list.get(0);
     }
 
-    default <Po, Pk> Update<Po, UpdateParam<Po>> createUpdate(GenericMapper<Po, Pk> mapper) {
-        Update<Po, UpdateParam<Po>> update = new Update(new UpdateParam(new HashMap<>()));
-        update.setExecutor(mapper::update);
-        return update;
+    /**
+     * 指定一个dao映射接口,接口需继承{@link GenericMapper}创建dsl数据更新操作对象<br>
+     * 可通过返回的Update对象进行dsl方式操作如:<br>
+     * <code>
+     * createUpdate(userMapper).where("id",1).exec();
+     * </code>
+     *
+     * @param mapper dao映射接口
+     * @param <PO>   PO泛型
+     * @param <PK>   主键泛型
+     * @return {@link Update}
+     * @see Update
+     * @see org.hsweb.ezorm.core.Conditional
+     * @see UpdateParam
+     * @since 2.2
+     */
+    static <PO, PK> Update<PO, UpdateParam<PO>> createUpdate(GenericMapper<PO, PK> mapper) {
+        return Update.build(mapper::update, new UpdateParam(new HashMap<>()));
     }
 
-    default Delete createDelete(GenericMapper<Po, Pk> mapper) {
+    /**
+     * 指定一个dao映射接口,接口需继承{@link GenericMapper}创建dsl数据删除操作对象<br>
+     * 可通过返回的Update对象进行dsl方式操作如:<br>
+     * <code>
+     * createDelete(userMapper).where("id",1).exec();
+     * </code>
+     *
+     * @param mapper dao映射结构
+     * @param <PO>   PO泛型
+     * @param <PK>   主键泛型
+     * @return {@link Delete}
+     * @see Delete
+     * @see org.hsweb.ezorm.core.Conditional
+     * @since 2.2
+     */
+    static <PO, PK> Delete createDelete(GenericMapper<PO, PK> mapper) {
         Delete update = new Delete();
         update.setParam(new DeleteParam());
         update.setExecutor(param -> mapper.delete(((DeleteParam) param)));
         return update;
     }
 
-    default Delete createDelete(Delete.Executor<DeleteParam> executor) {
+    /**
+     * 自定义一个删除执行器。创建dsl数据删除操作对象
+     *
+     * @param executor 执行器
+     * @return {@link Delete}
+     * @since 2.2
+     */
+    static Delete createDelete(Delete.Executor<DeleteParam> executor) {
         Delete update = new Delete();
         update.setParam(new DeleteParam());
         update.setExecutor(param -> executor.doExecute(((DeleteParam) param)));
         return update;
     }
 
+    /**
+     * 创建本服务的dsl查询操作对象
+     * 可通过返回的Query对象进行dsl方式操作如:<br>
+     * <code>
+     * createQuery().where("id",1).single();
+     * </code>
+     *
+     * @return {@link Query}
+     * @see Query
+     * @see org.hsweb.ezorm.core.Conditional
+     * @since 2.2
+     */
     default Query<Po, QueryParam> createQuery() {
-        Query<Po, QueryParam> query = new Query<>(new QueryParam());
+        Query<Po, QueryParam> query = Query.empty(new QueryParam());
         query.setListExecutor(this::select);
         query.setTotalExecutor(this::total);
         query.setSingleExecutor(this::selectSingle);
         return query;
     }
 
-    default <Po, Pk> Query<Po, QueryParam> createQuery(GenericMapper<Po, Pk> mapper) {
-        Query<Po, QueryParam> query = new Query<>(new QueryParam());
+    /**
+     * 指定一个dao映射接口,接口需继承{@link GenericMapper}创建dsl数据查询对象<br>
+     * 可通过返回的Query对象进行dsl方式操作如:<br>
+     * <code>
+     * createQuery(userMapper).where("id",1).single();
+     * </code>
+     *
+     * @param mapper dao映射结构
+     * @param <PO>   PO泛型
+     * @param <PK>   主键泛型
+     * @return {@link Query}
+     * @see Query
+     * @see org.hsweb.ezorm.core.Conditional
+     * @since 2.2
+     */
+    static <PO, PK> Query<PO, QueryParam> createQuery(GenericMapper<PO, PK> mapper) {
+        Query<PO, QueryParam> query = new Query<>(new QueryParam());
         query.setListExecutor(mapper::select);
         query.setTotalExecutor(mapper::total);
         query.setSingleExecutor((param) -> {
             param.doPaging(0, 1);
-            List<Po> list = mapper.select(param);
+            List<PO> list = mapper.select(param);
             if (null == list || list.size() == 0) return null;
             else return list.get(0);
         });

+ 2 - 0
hsweb-web-service/hsweb-web-service-api/src/main/java/org/hsweb/web/service/form/FormService.java

@@ -51,6 +51,8 @@ public interface FormService extends GenericService<Form, String> {
      */
     void deploy(String formId) throws SQLException;
 
+    void tryDeployAll();
+
     /**
      * 取消发布,取消发布后。表单失效。使用{@link DynamicFormService}后无法再进行调用
      *

+ 3 - 0
hsweb-web-service/hsweb-web-service-api/src/main/java/org/hsweb/web/service/quartz/QuartzJobService.java

@@ -21,6 +21,7 @@ import org.hsweb.web.service.GenericService;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 定时调度任务服务类
@@ -33,4 +34,6 @@ public interface QuartzJobService extends GenericService<QuartzJob, String> {
     void disable(String id);
 
     List<Date> getExecTimes(String cron, int number);
+
+    Object execute(String id, Map<String,Object> var);
 }

+ 39 - 9
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/AbstractServiceImpl.java

@@ -22,7 +22,13 @@ import java.util.List;
 import java.util.Set;
 
 /**
- * Created by 浩 on 2016-01-22 0022.
+ * 抽象通用服务实现类,通过指定{@link GenericMapper} 实现通用的增删改查方法
+ *
+ * @param <Po> PO类型
+ * @param <PK> 主键类型
+ * @author zhouhao
+ * @see GenericService
+ * @since 1.0
  */
 @Transactional(rollbackFor = Throwable.class)
 public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po, PK> {
@@ -63,6 +69,7 @@ public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po,
         return primaryKey;
     }
 
+    @Deprecated
     public List<PK> batchInsert(List<Po> data, boolean skipFail) {
         List<PK> pkList = new ArrayList<>();
         List<Po> insertData = new ArrayList<>();
@@ -92,7 +99,7 @@ public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po,
 
     @Override
     public int delete(PK pk) {
-        return getMapper().delete(DeleteParam.build().where("id", pk));
+        return createDelete().where(GenericPo.Property.id, pk).exec();
     }
 
     @Override
@@ -104,7 +111,7 @@ public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po,
     public int update(List<Po> data) {
         int i = 0;
         for (Po po : data) {
-            i += getMapper().update(UpdateParam.build(po));
+            i += createUpdate(po).exec();
         }
         return i;
     }
@@ -117,7 +124,7 @@ public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po,
 
     @Transactional(readOnly = true)
     public List<Po> select() {
-        return this.getMapper().select(QueryParam.build().noPaging());
+        return createQuery().listNoPaging();
     }
 
     @Override
@@ -152,6 +159,10 @@ public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po,
         }
     }
 
+    protected void assertNotNull(Object po) {
+        assertNotNull(po, "数据不存在");
+    }
+
     protected void tryValidPo(Po data) {
         Set<ConstraintViolation<Object>> set = validator.validate(data);
         ValidateResults results = new ValidateResults();
@@ -164,18 +175,37 @@ public abstract class AbstractServiceImpl<Po, PK> implements GenericService<Po,
             throw new ValidationException(results);
     }
 
+    /**
+     * 创建dsl更新操作对象,默认使用map进行数据填充,调用此方法,需要通过{@link Update#set(String, Object)}进行属性赋值
+     *
+     * @return {@link Update}
+     * @see Update
+     * @see GenericService#createUpdate(GenericMapper)
+     */
     public Update<Po, UpdateParam<Po>> createUpdate() {
-        return createUpdate(getMapper());
+        return GenericService.createUpdate(getMapper());
     }
 
+    /**
+     * 创建dsl更新操作对象,并指定要操作的数据
+     *
+     * @return {@link Update}
+     * @see Update
+     * @see GenericService#createUpdate(GenericMapper)
+     */
     public Update<Po, UpdateParam<Po>> createUpdate(Po data) {
-        Update<Po, UpdateParam<Po>> update = createUpdate();
-        update.getParam().setData(data);
-        return update;
+        return Update.build(getMapper()::update, new UpdateParam<>(data));
     }
 
+    /**
+     * 创建dsl删除操作对象
+     *
+     * @return {@link Delete}
+     * @see Delete
+     * @see GenericService#createDelete(Delete.Executor)
+     */
     public Delete createDelete() {
-        return createDelete(getMapper());
+        return GenericService.createDelete(getMapper());
     }
 
 }

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

@@ -1,11 +1,6 @@
 package org.hsweb.web.service.impl;
 
-import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
-import org.hsweb.web.bean.po.form.Form;
-import org.hsweb.web.service.form.DynamicFormService;
 import org.hsweb.web.service.form.FormService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.stereotype.Component;
@@ -16,30 +11,10 @@ import javax.annotation.Resource;
 public class FormDeployContextLoaderListener implements ApplicationListener<ContextRefreshedEvent> {
     @Resource
     private FormService        formService;
-    @Resource
-    private DynamicFormService dynamicFormService;
-
-    private Logger logger = LoggerFactory.getLogger(this.getClass());
 
     @Override
     public void onApplicationEvent(ContextRefreshedEvent event) {
         if (event.getApplicationContext().getParent() != null) return;
-        try {
-            formService.createQuery().where(Form.Property.using, 1).listNoPaging().forEach(form -> {
-                try {
-                    Form deployed = formService.selectDeployed(form.getName());
-                    if (null != deployed) {
-                        RDBTableMetaData metaData = dynamicFormService.parseMeta(deployed);
-                        dynamicFormService.getDefaultDatabase().reloadTable(metaData);
-                    } else {
-                        dynamicFormService.deploy(form);
-                    }
-                } catch (Exception e) {
-                    logger.error("部署{}:({})失败", form.getName(), form.getRemark(), e);
-                }
-            });
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        formService.tryDeployAll();
     }
 }

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

@@ -78,7 +78,6 @@ public class DynamicFormServiceImpl implements DynamicFormService, ExpressionSco
         metaData.setDatabaseMetaData(database.getMeta());
         TableBuilder builder = new SimpleTableBuilder(metaData, database, null);
         builder.addColumn().name("u_id").varchar(32).primaryKey().comment("主键").commit();
-        metaData.setPrimaryKeys(new HashSet<>(Arrays.asList("u_id")));
         metaData.setProperty("primaryKey", "u_id");
     }
 

+ 24 - 2
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/form/FormServiceImpl.java

@@ -1,19 +1,21 @@
 package org.hsweb.web.service.impl.form;
 
 import com.alibaba.fastjson.JSON;
+import org.hsweb.commons.StringUtils;
+import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
 import org.hsweb.web.bean.common.InsertParam;
 import org.hsweb.web.bean.common.QueryParam;
 import org.hsweb.web.bean.common.UpdateParam;
 import org.hsweb.web.bean.po.form.Form;
 import org.hsweb.web.bean.po.form.Form.Property;
 import org.hsweb.web.bean.po.history.History;
+import org.hsweb.web.core.utils.RandomUtil;
 import org.hsweb.web.dao.form.FormMapper;
 import org.hsweb.web.service.form.DynamicFormService;
 import org.hsweb.web.service.form.FormParser;
 import org.hsweb.web.service.form.FormService;
 import org.hsweb.web.service.history.HistoryService;
 import org.hsweb.web.service.impl.AbstractServiceImpl;
-import org.hsweb.web.core.utils.RandomUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
@@ -21,7 +23,6 @@ import org.springframework.cache.annotation.Caching;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
-import org.hsweb.commons.StringUtils;
 
 import javax.annotation.Resource;
 import java.sql.SQLException;
@@ -143,6 +144,27 @@ public class FormServiceImpl extends AbstractServiceImpl<Form, String> implement
         return formList.size() > 0 ? formList.get(0) : null;
     }
 
+    @Override
+    @Caching(evict = {
+            @CacheEvict(value = {CACHE_KEY + ".deploy"}, allEntries = true),
+            @CacheEvict(value = {CACHE_KEY}, allEntries = true)
+    })
+    public void tryDeployAll() {
+        createQuery().where(Form.Property.using, 1).listNoPaging().forEach(form -> {
+            try {
+                Form deployed = selectDeployed(form.getName());
+                if (null != deployed) {
+                    RDBTableMetaData metaData = dynamicFormService.parseMeta(deployed);
+                    dynamicFormService.getDefaultDatabase().reloadTable(metaData);
+                } else {
+                    dynamicFormService.deploy(form);
+                }
+            } catch (Exception e) {
+                logger.error("部署{}:({})失败", form.getName(), form.getRemark(), e);
+            }
+        });
+    }
+
     @Override
     @Transactional(rollbackFor = Throwable.class)
     @Caching(evict = {

+ 76 - 11
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/quartz/QuartzJobServiceImpl.java

@@ -19,23 +19,23 @@ package org.hsweb.web.service.impl.quartz;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.hsweb.commons.MD5;
 import org.hsweb.commons.StringUtils;
-import org.hsweb.web.bean.common.DeleteParam;
-import org.hsweb.web.bean.common.UpdateMapParam;
-import org.hsweb.web.bean.common.UpdateParam;
+import org.hsweb.expands.script.engine.DynamicScriptEngine;
+import org.hsweb.expands.script.engine.DynamicScriptEngineFactory;
+import org.hsweb.expands.script.engine.ExecuteResult;
+import org.hsweb.expands.script.engine.ScriptContext;
 import org.hsweb.web.bean.po.quartz.QuartzJob;
 import org.hsweb.web.bean.po.quartz.QuartzJobHistory;
 import org.hsweb.web.core.exception.BusinessException;
 import org.hsweb.web.dao.quartz.QuartzJobHistoryMapper;
 import org.hsweb.web.dao.quartz.QuartzJobMapper;
+import org.hsweb.web.service.GenericService;
 import org.hsweb.web.service.impl.AbstractServiceImpl;
 import org.hsweb.web.service.quartz.QuartzJobHistoryService;
 import org.hsweb.web.service.quartz.QuartzJobService;
 import org.joda.time.DateTime;
 import org.quartz.*;
-import org.quartz.Calendar;
-import org.quartz.impl.calendar.CronCalendar;
 import org.quartz.impl.triggers.CronTriggerImpl;
 import org.quartz.spi.MutableTrigger;
 import org.quartz.spi.OperableTrigger;
@@ -43,13 +43,19 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
 
 import javax.annotation.Resource;
-import java.text.ParseException;
-import java.util.*;
-import java.util.stream.Collectors;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
 
-import static org.hsweb.web.bean.po.quartz.QuartzJob.Property.*;
+import static org.hsweb.web.bean.po.quartz.QuartzJob.Property.enabled;
+import static org.hsweb.web.bean.po.quartz.QuartzJob.Property.id;
+import static org.hsweb.web.bean.po.quartz.QuartzJobHistory.Status.FAIL;
+import static org.hsweb.web.bean.po.quartz.QuartzJobHistory.Status.SUCCESS;
 
 /**
  * 定时调度任务服务类
@@ -127,7 +133,7 @@ public class QuartzJobServiceImpl extends AbstractServiceImpl<QuartzJob, String>
     @CacheEvict(value = CACHE_KEY, key = "'id:'+#id")
     public int delete(String id) {
         deleteJob(id);
-        createDelete(quartzJobHistoryMapper::delete).where(QuartzJobHistory.Property.jobId, id).exec();
+        GenericService.createDelete(quartzJobHistoryMapper).where(QuartzJobHistory.Property.jobId, id).exec();
         return super.delete(id);
     }
 
@@ -154,6 +160,65 @@ public class QuartzJobServiceImpl extends AbstractServiceImpl<QuartzJob, String>
         }
     }
 
+    @Override
+    @Transactional
+    public Object execute(String id, Map<String, Object> var) {
+        Assert.notNull(id, "定时任务ID错误");
+        QuartzJob job = selectByPk(id);
+        Assert.notNull(job, "任务不存在");
+        String hisId = quartzJobHistoryService.createAndInsertHistory(id);
+        String strRes = null;
+        try {
+            if (logger.isDebugEnabled())
+                logger.debug("start job [{}]", job.getName());
+            DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(job.getLanguage());
+            String scriptId = "quartz.job.".concat(id);
+            try {
+                if (!engine.compiled(scriptId)) {
+                    engine.compile(scriptId, job.getScript());
+                } else {
+                    ScriptContext scriptContext = engine.getContext(scriptId);
+                    //脚本发生了变化,自动重新编译
+                    if (!MD5.defaultEncode(job.getScript()).equals(scriptContext.getMd5())) {
+                        if (logger.isDebugEnabled())
+                            logger.debug("script is changed,recompile....");
+                        engine.compile(scriptId, job.getScript());
+                    }
+                }
+            } catch (Exception e) {
+                throw new BusinessException("编译任务脚本失败");
+            }
+            if (logger.isDebugEnabled())
+                logger.debug("job running...");
+            ExecuteResult result = engine.execute(scriptId, var);
+            if (logger.isDebugEnabled())
+                logger.debug("job end...{} ", result.isSuccess() ? "success" : "fail");
+            if (result.isSuccess()) {
+                Object res = result.getResult();
+                if (res instanceof String)
+                    strRes = ((String) res);
+                else strRes = JSON.toJSONString(res);
+                quartzJobHistoryService.endHistory(hisId, strRes, SUCCESS);
+            } else {
+                if (result.getException() != null) {
+                    strRes = StringUtils.throwable2String(result.getException());
+                    logger.error("job failed", result.getException());
+                    if (result.getException() instanceof RuntimeException) {
+                        throw ((RuntimeException) result.getException());
+                    }
+                    throw new RuntimeException(result.getException());
+                } else {
+                    strRes = result.getMessage();
+                    logger.error("job failed {}", strRes);
+                    throw new RuntimeException(strRes);
+                }
+            }
+        } finally {
+            quartzJobHistoryService.endHistory(hisId, strRes, FAIL);
+        }
+        return strRes;
+    }
+
     public static List<Date> computeFireTimesBetween(OperableTrigger trigger,
                                                      org.quartz.Calendar cal, Date from, Date to, int num) {
         LinkedList<Date> lst = new LinkedList<>();

+ 5 - 57
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/quartz/SimpleJob.java

@@ -16,24 +16,13 @@
 
 package org.hsweb.web.service.impl.quartz;
 
-import com.alibaba.fastjson.JSON;
-import org.hsweb.commons.MD5;
-import org.hsweb.commons.StringUtils;
-import org.hsweb.expands.script.engine.DynamicScriptEngine;
-import org.hsweb.expands.script.engine.DynamicScriptEngineFactory;
-import org.hsweb.expands.script.engine.ExecuteResult;
-import org.hsweb.expands.script.engine.ScriptContext;
-import org.hsweb.web.bean.po.quartz.QuartzJob;
-import org.hsweb.web.bean.po.quartz.QuartzJobHistory;
 import org.hsweb.web.bean.po.user.User;
 import org.hsweb.web.core.utils.WebUtil;
 import org.hsweb.web.service.quartz.QuartzJobHistoryService;
 import org.hsweb.web.service.quartz.QuartzJobService;
-import org.hsweb.web.service.user.UserService;
 import org.quartz.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.Assert;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -59,58 +48,17 @@ public class SimpleJob implements Job {
 
     @Override
     public void execute(JobExecutionContext context) throws JobExecutionException {
-        //初始化用户信息
         try {
-            //解决定时任务获取当前用户
             WebUtil.setCurrentUser(defaultUser);
             JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
             String id = jobDataMap.getString(SimpleJobFactory.QUARTZ_ID_KEY);
-            Assert.notNull(id, "定时任务ID错误");
-            QuartzJob job = quartzJobService.selectByPk(id);
-            Assert.notNull(job, "任务不存在");
-            if (logger.isDebugEnabled())
-                logger.debug("start job [{}],data : {}", job.getName(), jobDataMap);
-            DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(job.getLanguage());
-            String scriptId = "quartz.job.".concat(id);
-            try {
-                if (!engine.compiled(scriptId)) {
-                    engine.compile(scriptId, job.getScript());
-                } else {
-                    ScriptContext scriptContext = engine.getContext(scriptId);
-                    //脚本发生了变化,自动重新编译
-                    if (!MD5.defaultEncode(job.getScript()).equals(scriptContext.getMd5())) {
-                        if (logger.isDebugEnabled())
-                            logger.debug("script is changed,recompile....");
-                        engine.compile(scriptId, job.getScript());
-                    }
-                }
-            } catch (Exception e) {
-                throw new JobExecutionException("编译任务脚本失败", e);
-            }
-            if (logger.isDebugEnabled())
-                logger.debug("job running...");
-            String hisId = quartzJobHistoryService.createAndInsertHistory(id);
             Map<String, Object> var = getVar();
             var.put("context", context);
-            ExecuteResult result = engine.execute(scriptId, var);
-            String strRes;
-            if (logger.isDebugEnabled())
-                logger.debug("job end...{} ", result.isSuccess() ? "success" : "fail");
-            if (result.isSuccess()) {
-                Object res = result.getResult();
-                if (res instanceof String)
-                    strRes = ((String) res);
-                else strRes = JSON.toJSONString(res);
-                quartzJobHistoryService.endHistory(hisId, strRes, QuartzJobHistory.Status.SUCCESS);
-            } else {
-                if (result.getException() != null) {
-                    strRes = StringUtils.throwable2String(result.getException());
-                    logger.error("job failed", result.getException());
-                } else {
-                    strRes = result.getMessage();
-                    logger.error("job failed {}", strRes);
-                }
-                quartzJobHistoryService.endHistory(hisId, strRes, QuartzJobHistory.Status.FAIL);
+            var.put("user", defaultUser);
+            try {
+                quartzJobService.execute(id, var);
+            } catch (Throwable e) {
+                throw new JobExecutionException(e);
             }
         } finally {
             WebUtil.removeCurrentUser();

+ 2 - 1
hsweb-web-service/hsweb-web-service-simple/src/main/java/org/hsweb/web/service/impl/user/UserServiceImpl.java

@@ -11,6 +11,7 @@ import org.hsweb.web.core.exception.NotFoundException;
 import org.hsweb.web.core.utils.RandomUtil;
 import org.hsweb.web.dao.role.UserRoleMapper;
 import org.hsweb.web.dao.user.UserMapper;
+import org.hsweb.web.service.GenericService;
 import org.hsweb.web.service.impl.AbstractServiceImpl;
 import org.hsweb.web.service.module.ModuleService;
 import org.hsweb.web.service.user.UserService;
@@ -110,7 +111,7 @@ public class UserServiceImpl extends AbstractServiceImpl<User, String> implement
 
     @Override
     public void initGuestUser(User user) {
-        List<UserRole> userRoles = createQuery(userRoleMapper).where(UserRole.Property.roleId, "guest").list();
+        List<UserRole> userRoles = GenericService.createQuery(userRoleMapper).where(UserRole.Property.roleId, "guest").list();
         user.setUserRoles(userRoles);
         user.initRoleInfo();
     }