1
0
Эх сурвалжийг харах

!43 v1.1.2-Alpha
Merge pull request !43 from AE86/V_1.0.0

AE86 3 жил өмнө
parent
commit
6fd3486552
46 өөрчлөгдсөн 401 нэмэгдсэн , 322 устгасан
  1. 28 61
      README.md
  2. 12 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConnectorService.java
  3. 6 6
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/BaseServiceImpl.java
  4. 39 6
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ConnectorServiceImpl.java
  5. 6 2
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/MappingServiceImpl.java
  6. 34 12
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/PluginServiceImpl.java
  7. 30 13
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/TableGroupServiceImpl.java
  8. 3 3
      dbsyncer-common/src/main/java/org/dbsyncer/common/util/SHA1Util.java
  9. 1 1
      dbsyncer-connector/src/main/java/org/dbsyncer/connector/ConnectorFactory.java
  10. 19 0
      dbsyncer-connector/src/main/java/org/dbsyncer/connector/database/setter/IntegerSetter.java
  11. 1 1
      dbsyncer-connector/src/main/java/org/dbsyncer/connector/es/ESConnector.java
  12. 1 1
      dbsyncer-connector/src/main/java/org/dbsyncer/connector/util/ESUtil.java
  13. 1 1
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/mysql/MysqlExtractor.java
  14. 17 6
      dbsyncer-manager/src/main/java/org/dbsyncer/manager/ManagerFactory.java
  15. 0 37
      dbsyncer-manager/src/main/java/org/dbsyncer/manager/template/impl/DataTemplate.java
  16. 0 2
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/Monitor.java
  17. 0 13
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/MonitorFactory.java
  18. 14 2
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/ParserFactory.java
  19. 4 2
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/logger/LogType.java
  20. 9 0
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/MonitorController.java
  21. 0 1
      dbsyncer-web/src/main/resources/application.properties
  22. 1 1
      dbsyncer-web/src/main/resources/public/connector/add.html
  23. 3 6
      dbsyncer-web/src/main/resources/public/connector/addDqlMysql.html
  24. 3 6
      dbsyncer-web/src/main/resources/public/connector/addElasticsearch.html
  25. 3 6
      dbsyncer-web/src/main/resources/public/connector/addMysql.html
  26. 2 2
      dbsyncer-web/src/main/resources/public/index.html
  27. 1 1
      dbsyncer-web/src/main/resources/public/mapping/editParameter.html
  28. 2 2
      dbsyncer-web/src/main/resources/public/mapping/editPlugin.html
  29. 2 2
      dbsyncer-web/src/main/resources/public/mapping/editTable.html
  30. 4 4
      dbsyncer-web/src/main/resources/public/mapping/editTableGroup.html
  31. 2 2
      dbsyncer-web/src/main/resources/public/monitor/monitor.html
  32. 4 4
      dbsyncer-web/src/main/resources/static/css/common.css
  33. 28 0
      dbsyncer-web/src/main/resources/static/js/common.js
  34. 25 27
      dbsyncer-web/src/main/resources/static/js/connector/add.js
  35. 3 5
      dbsyncer-web/src/main/resources/static/js/connector/edit.js
  36. 2 5
      dbsyncer-web/src/main/resources/static/js/mapping/add.js
  37. 42 25
      dbsyncer-web/src/main/resources/static/js/mapping/edit.js
  38. 8 6
      dbsyncer-web/src/main/resources/static/js/mapping/editFilterAndConvert.js
  39. 2 2
      dbsyncer-web/src/main/resources/static/js/mapping/editParam.js
  40. 16 29
      dbsyncer-web/src/main/resources/static/js/mapping/editTableGroup.js
  41. 6 9
      dbsyncer-web/src/main/resources/static/js/monitor/index.js
  42. 5 0
      dbsyncer-web/src/main/resources/static/plugins/css/bootstrap-select/bootstrap-select.min.css
  43. 0 0
      dbsyncer-web/src/main/resources/static/plugins/css/select2/select2.min.css
  44. 7 0
      dbsyncer-web/src/main/resources/static/plugins/js/bootstrap-select/bootstrap-select.min.js
  45. 5 5
      dbsyncer-web/src/main/resources/static/plugins/js/loading-plus/loading-plus.js
  46. 0 3
      dbsyncer-web/src/main/resources/static/plugins/js/select2/select2.min.js

+ 28 - 61
README.md

@@ -12,92 +12,56 @@ DBSyncer是一款开源的数据同步中间件,提供Mysql、Oracle、SqlServ
     <table>
         <tbody>
             <tr>
-                <td colspan="2" rowspan="2">Every point is a DataBase</td>
-                <td colspan="6" align="center">目标源</td>
+                <td>连接器</td>
+                <td>数据源</td>
+                <td>目标源</td>
+                <td>支持版本</td>
             </tr>
             <tr>
                 <td>Mysql</td>
-                <td>Oracle</td>
-                <td>SqlServer</td>
-                <td>ES</td>
-                <td>SQL</td>
-            </tr>
-            <tr>
-                <td rowspan="5">数据源</td>
-                <td>Mysql</td>
-                <td>√</td>
-                <td>√</td>
-                <td>√</td>
                 <td>√</td>
                 <td>√</td>
+                <td>5.7.19以上</td>
             </tr>
             <tr>
                 <td>Oracle</td>
                 <td>√</td>
                 <td>√</td>
-                <td>√</td>
-                <td>√</td>
-                <td>√</td>
+                <td>10g以上</td>
             </tr>
             <tr>
                 <td>SqlServer</td>
                 <td>√</td>
                 <td>√</td>
-                <td>√</td>
-                <td>√</td>
-                <td>√</td>
+                <td>2008以上</td>
             </tr>
             <tr>
                 <td>ES</td>
                 <td>√</td>
                 <td>√</td>
-                <td>√</td>
-                <td>√</td>
-                <td>√</td>
+                <td>6.X以上</td>
             </tr>
             <tr>
                 <td>SQL</td>
-                <td></td>
-                <td></td>
-                <td></td>
+                <td>√</td>
                 <td></td>
                 <td></td>
             </tr>
-            <tr>
-                <td rowspan="4">版本支持</td>
-                <td>Mysql</td>
-                <td colspan="7">5.7.19以上</td>
-            </tr>
-            <tr>
-                <td>Oracle</td>
-                <td colspan="7">10g以上(Oracle-9i未测试)</td>
-            </tr>
-            <tr>
-                <td>SqlServer</td>
-                <td colspan="7">2008以上</td>
-            </tr>
-            <tr>
-                <td>ES</td>
-                <td colspan="7">6.X以上</td>
-            </tr>
             <tr>
                 <td>最近计划</td>
-                <td colspan="7">kafka</td>
+                <td colspan="3">kafka</td>
             </tr>
         </tbody>
     </table>
 <div>
 
 ## 安装配置
-#### 准备
-* [DBSyncer-1.0.0-Alpha.zip](https://gitee.com/ghi/dbsyncer/releases)(安装包)
-* [JRE 1.8 +](https://www.oracle.com/java/technologies/jdk8-downloads.html)
 #### 步骤
-* 安装JRE1.8版本以上(省略详细)
-* 下载安装包DBSyncer-X.X.X-RELEASE.zip
-* 解压安装包,Window执行bin/startup.bat,Linux执行bin/startup.sh
-* 打开浏览器访问:http://127.0.0.1:18686
-* 账号和密码:admin/admin
+1. 安装[JRE 1.8](https://www.oracle.com/java/technologies/jdk8-downloads.html)(省略详细)
+2. 下载安装包[DBSyncer-1.0.0-Alpha.zip](https://gitee.com/ghi/dbsyncer/releases)(也可手动编译)
+3. 解压安装包,Window执行bin/startup.bat,Linux执行bin/startup.sh
+4. 打开浏览器访问:http://127.0.0.1:18686
+5. 账号和密码:admin/admin
 
 #### 增量同步配置(源库)
 
@@ -135,6 +99,17 @@ grant change notification to 你的账号
 * 配置
 > 账号具有访问权限。
 
+##### 日志
+> 建议Mysql和SqlServer都使用日志
+
+![日志](https://images.gitee.com/uploads/images/2021/0906/181036_1f9a9e78_376718.png "日志.png")
+
+##### 定时
+> 假设源表数据格式
+
+![表数据格式](https://images.gitee.com/uploads/images/2021/0903/004406_68ef9bb4_376718.png "表数据格式.png")
+![定时和过滤条件](https://images.gitee.com/uploads/images/2021/0903/004807_07cdf2b7_376718.png "定时和过滤条件.png")
+
 ## 预览
 ### 驱动管理
 ![连接器和驱动](https://images.gitee.com/uploads/images/2021/0903/003755_01016fc1_376718.png "驱动管理.png")
@@ -145,12 +120,6 @@ grant change notification to 你的账号
 ### 驱动表字段关系配置
 ![驱动表字段关系配置](https://images.gitee.com/uploads/images/2021/0903/004106_26399534_376718.png "驱动表字段关系配置.png")
 
-### 定时配置
-> 假设源表数据格式
-
-![表数据格式](https://images.gitee.com/uploads/images/2021/0903/004406_68ef9bb4_376718.png "表数据格式.png")
-![定时和过滤条件](https://images.gitee.com/uploads/images/2021/0903/004807_07cdf2b7_376718.png "定时和过滤条件.png")
-
 ### 监控
 ![监控](https://images.gitee.com/uploads/images/2021/0728/000645_35a544b3_376718.png "监控.png")
 
@@ -170,8 +139,6 @@ grant change notification to 你的账号
 ## 开发依赖
 * [JDK - 1.8.0_40](https://www.oracle.com/java/technologies/jdk8-downloads.html)(推荐版本以上)
 * [Maven - 3.3.9](https://dlcdn.apache.org/maven/maven-3/)(推荐版本以上)
-* [Spring Boot - 2.2.0.RELEASE](https://docs.spring.io/spring-boot/docs/2.2.0.RELEASE/reference/html)
-* [Bootstrap - 3.3.4](http://getbootstrap.com)
 
 ## 手动编译
 > 先确保环境已安装JDK和Maven
@@ -183,5 +150,5 @@ $ ./build.sh
 ```
 
 ## 了解更多
-* [访问博客地址](https://my.oschina.net/dbsyncer "https://my.oschina.net/dbsyncer")
-* QQ群: 875519623或点击右侧按钮<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=fce8d51b264130bac5890674e7db99f82f7f8af3f790d49fcf21eaafc8775f2a"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="数据同步dbsyncer" title="数据同步dbsyncer" /> 
+* ##### [访问博客地址](https://my.oschina.net/dbsyncer "https://my.oschina.net/dbsyncer")
+* ##### QQ群: 875519623或点击右侧按钮<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=fce8d51b264130bac5890674e7db99f82f7f8af3f790d49fcf21eaafc8775f2a"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="数据同步dbsyncer" title="数据同步dbsyncer" /> 

+ 12 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConnectorService.java

@@ -55,4 +55,16 @@ public interface ConnectorService {
      */
     List<String> getConnectorTypeAll();
 
+    /**
+     * 检查连接器状态
+     */
+    void refreshHealth();
+
+    /**
+     * 连接器是否可用
+     *
+     * @param id
+     * @return
+     */
+    boolean isAlive(String id);
 }

+ 6 - 6
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/BaseServiceImpl.java

@@ -35,16 +35,16 @@ public class BaseServiceImpl {
     }
 
     protected void assertRunning(String metaId) {
-        Assert.isTrue(!isRunning(metaId), "驱动正在运行, 请先停止.");
-    }
-
-    protected void assertRunning(TableGroup model) {
         synchronized (LOCK) {
-            Mapping mapping = manager.getMapping(model.getMappingId());
-            assertRunning(mapping.getMetaId());
+            Assert.isTrue(!isRunning(metaId), "驱动正在运行, 请先停止.");
         }
     }
 
+    protected void assertRunning(Mapping mapping) {
+        Assert.notNull(mapping, "mapping can not be null.");
+        assertRunning(mapping.getMetaId());
+    }
+
     protected void log(LogType log, ConfigModel model) {
         if (null != model) {
             // 新增连接器:知识库

+ 39 - 6
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ConnectorServiceImpl.java

@@ -15,10 +15,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -31,6 +28,8 @@ public class ConnectorServiceImpl extends BaseServiceImpl implements ConnectorSe
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
+    private Map<String, Boolean> health = new LinkedHashMap<>();
+
     @Autowired
     private Manager manager;
 
@@ -56,9 +55,9 @@ public class ConnectorServiceImpl extends BaseServiceImpl implements ConnectorSe
     @Override
     public String remove(String id) {
         List<Mapping> mappingAll = manager.getMappingAll();
-        if(!CollectionUtils.isEmpty(mappingAll)){
+        if (!CollectionUtils.isEmpty(mappingAll)) {
             mappingAll.forEach(mapping -> {
-                if(StringUtil.equals(mapping.getSourceConnectorId(), id) || StringUtil.equals(mapping.getTargetConnectorId(), id)){
+                if (StringUtil.equals(mapping.getSourceConnectorId(), id) || StringUtil.equals(mapping.getTargetConnectorId(), id)) {
                     String error = String.format("驱动“%s”正在使用,请先删除", mapping.getName());
                     logger.error(error);
                     throw new BizException(error);
@@ -94,4 +93,38 @@ public class ConnectorServiceImpl extends BaseServiceImpl implements ConnectorSe
         return list;
     }
 
+    @Override
+    public void refreshHealth() {
+        List<Connector> list = manager.getConnectorAll();
+        if (CollectionUtils.isEmpty(list)) {
+            if (!CollectionUtils.isEmpty(health)) {
+                health.clear();
+            }
+            return;
+        }
+
+        // 更新连接器状态
+        Set<String> exist = new HashSet<>();
+        list.forEach(c -> {
+            health.put(c.getId(), manager.isAliveConnectorConfig(c.getConfig()));
+            exist.add(c.getId());
+        });
+
+        // 移除删除的连接器
+        Set<String> remove = new HashSet<>();
+        health.keySet().forEach(k -> {
+            if (!exist.contains(k)) {
+                remove.add(k);
+            }
+        });
+
+        if (!CollectionUtils.isEmpty(remove)) {
+            remove.forEach(k -> health.remove(k));
+        }
+    }
+
+    @Override
+    public boolean isAlive(String id) {
+        return health.containsKey(id) && health.get(id);
+    }
 }

+ 6 - 2
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/MappingServiceImpl.java

@@ -1,6 +1,7 @@
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.biz.BizException;
+import org.dbsyncer.biz.ConnectorService;
 import org.dbsyncer.biz.MappingService;
 import org.dbsyncer.biz.TableGroupService;
 import org.dbsyncer.biz.checker.impl.mapping.MappingChecker;
@@ -43,6 +44,9 @@ public class MappingServiceImpl extends BaseServiceImpl implements MappingServic
     @Autowired
     private TableGroupService tableGroupService;
 
+    @Autowired
+    private ConnectorService connectorService;
+
     @Override
     public String add(Map<String, String> params) {
         ConfigModel model = mappingChecker.checkAddConfigModel(params);
@@ -155,9 +159,9 @@ public class MappingServiceImpl extends BaseServiceImpl implements MappingServic
         Assert.notNull(mapping, "Mapping can not be null.");
         Connector s = manager.getConnector(mapping.getSourceConnectorId());
         Connector t = manager.getConnector(mapping.getTargetConnectorId());
-        ConnectorVo sConn = new ConnectorVo(monitor.isAlive(s.getId()));
+        ConnectorVo sConn = new ConnectorVo(connectorService.isAlive(s.getId()));
         BeanUtils.copyProperties(s, sConn);
-        ConnectorVo tConn = new ConnectorVo(monitor.isAlive(t.getId()));
+        ConnectorVo tConn = new ConnectorVo(connectorService.isAlive(t.getId()));
         BeanUtils.copyProperties(t, tConn);
 
         // 元信息

+ 34 - 12
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/PluginServiceImpl.java

@@ -9,6 +9,7 @@ import org.dbsyncer.manager.Manager;
 import org.dbsyncer.parser.logger.LogService;
 import org.dbsyncer.parser.logger.LogType;
 import org.dbsyncer.parser.model.Mapping;
+import org.dbsyncer.parser.model.TableGroup;
 import org.dbsyncer.plugin.config.Plugin;
 import org.dbsyncer.plugin.enums.FileSuffixEnum;
 import org.springframework.beans.BeanUtils;
@@ -40,18 +41,7 @@ public class PluginServiceImpl implements PluginService {
         List<Plugin> pluginAll = manager.getPluginAll();
         List<PluginVo> vos = new ArrayList<>();
         if (!CollectionUtils.isEmpty(pluginAll)) {
-            Map<String, List<String>> pluginClassNameMap = new HashMap<>();
-            List<Mapping> mappingAll = manager.getMappingAll();
-            if (!CollectionUtils.isEmpty(mappingAll)) {
-                mappingAll.forEach(mapping -> {
-                    Plugin plugin = mapping.getPlugin();
-                    if (null != plugin) {
-                        pluginClassNameMap.putIfAbsent(plugin.getClassName(), new ArrayList<>());
-                        pluginClassNameMap.get(plugin.getClassName()).add(mapping.getName());
-                    }
-                });
-            }
-
+            Map<String, List<String>> pluginClassNameMap = getPluginClassNameMap();
             vos.addAll(pluginAll.stream().map(plugin -> {
                 PluginVo vo = new PluginVo();
                 BeanUtils.copyProperties(plugin, vo);
@@ -90,4 +80,36 @@ public class PluginServiceImpl implements PluginService {
             }
         }
     }
+
+    private Map<String, List<String>> getPluginClassNameMap() {
+        Map<String, List<String>> map = new HashMap<>();
+        List<Mapping> mappingAll = manager.getMappingAll();
+        if (CollectionUtils.isEmpty(mappingAll)) {
+            return map;
+        }
+
+        for (Mapping m : mappingAll) {
+            Plugin plugin = m.getPlugin();
+            if (null != plugin) {
+                map.putIfAbsent(plugin.getClassName(), new ArrayList<>());
+                map.get(plugin.getClassName()).add(m.getName());
+                continue;
+            }
+
+            List<TableGroup> tableGroupAll = manager.getTableGroupAll(m.getId());
+            if (CollectionUtils.isEmpty(tableGroupAll)) {
+                continue;
+            }
+            for (TableGroup t : tableGroupAll) {
+                Plugin p = t.getPlugin();
+                if (null != p) {
+                    map.putIfAbsent(p.getClassName(), new ArrayList<>());
+                    map.get(p.getClassName()).add(m.getName());
+                    break;
+                }
+            }
+        }
+
+        return map;
+    }
 }

+ 30 - 13
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/TableGroupServiceImpl.java

@@ -3,10 +3,12 @@ package org.dbsyncer.biz.impl;
 import org.dbsyncer.biz.TableGroupService;
 import org.dbsyncer.biz.checker.Checker;
 import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.common.util.StringUtil;
 import org.dbsyncer.connector.config.Field;
 import org.dbsyncer.parser.logger.LogType;
 import org.dbsyncer.parser.model.Mapping;
 import org.dbsyncer.parser.model.TableGroup;
+import org.dbsyncer.storage.constant.ConfigConstant;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,22 +33,39 @@ public class TableGroupServiceImpl extends BaseServiceImpl implements TableGroup
 
     @Override
     public String add(Map<String, String> params) {
-        TableGroup model = (TableGroup) tableGroupChecker.checkAddConfigModel(params);
-        assertRunning(model);
-        log(LogType.TableGroupLog.INSERT, model);
-
-        String id = manager.addTableGroup(model);
+        String mappingId = params.get("mappingId");
+        assertRunning(manager.getMapping(mappingId));
+
+        // table1, table2
+        String[] sourceTableArray = StringUtil.split(params.get("sourceTable"), ",");
+        String[] targetTableArray = StringUtil.split(params.get("targetTable"), ",");
+        int tableSize = sourceTableArray.length;
+        Assert.isTrue(tableSize == targetTableArray.length, "数据源表和目标源表关系必须为一组");
+
+        String id = null;
+        for (int i = 0; i < tableSize; i++) {
+            params.put("sourceTable", sourceTableArray[i]);
+            params.put("targetTable", targetTableArray[i]);
+            TableGroup model = (TableGroup) tableGroupChecker.checkAddConfigModel(params);
+            log(LogType.TableGroupLog.INSERT, model);
+
+            id = manager.addTableGroup(model);
+        }
 
         // 合并驱动公共字段
-        mergeMappingColumn(model.getMappingId());
+        mergeMappingColumn(mappingId);
 
-        return id;
+        return 1 < tableSize ? String.valueOf(tableSize) : id;
     }
 
     @Override
     public String edit(Map<String, String> params) {
+        String id = params.get(ConfigConstant.CONFIG_MODEL_ID);
+        TableGroup tableGroup = manager.getTableGroup(id);
+        Assert.notNull(tableGroup, "Can not find tableGroup.");
+        assertRunning(manager.getMapping(tableGroup.getMappingId()));
+
         TableGroup model = (TableGroup) tableGroupChecker.checkEditConfigModel(params);
-        assertRunning(model);
         log(LogType.TableGroupLog.UPDATE, model);
 
         return manager.editTableGroup(model);
@@ -56,19 +75,17 @@ public class TableGroupServiceImpl extends BaseServiceImpl implements TableGroup
     public boolean remove(String mappingId, String ids) {
         Assert.hasText(mappingId, "Mapping id can not be null");
         Assert.hasText(ids, "TableGroup ids can not be null");
-        Mapping mapping = manager.getMapping(mappingId);
-        Assert.notNull(mapping, "Mapping can not be null");
-        assertRunning(mapping.getMetaId());
+        assertRunning(manager.getMapping(mappingId));
 
         // 批量删除表
-        Stream.of(ids.split(",")).parallel().forEach(id -> {
+        Stream.of(StringUtil.split(ids, ",")).parallel().forEach(id -> {
             TableGroup model = manager.getTableGroup(id);
             log(LogType.TableGroupLog.DELETE, model);
             manager.removeTableGroup(id);
         });
 
         // 合并驱动公共字段
-        mergeMappingColumn(mapping.getId());
+        mergeMappingColumn(mappingId);
         return true;
     }
 

+ 3 - 3
dbsyncer-common/src/main/java/org/dbsyncer/common/util/SHA1Util.java

@@ -4,6 +4,7 @@ import org.dbsyncer.common.CommonException;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
 
 public abstract class SHA1Util {
 
@@ -16,8 +17,7 @@ public abstract class SHA1Util {
             throw new CommonException(e);
 		}
 	}
-	
-    @SuppressWarnings("restriction")
+
     public static String b64_sha1(String s) {
         if (null == s || "" == s.trim()) {
             return null;
@@ -30,7 +30,7 @@ public abstract class SHA1Util {
         	return null;
         }
         // base64加密
-        return new sun.misc.BASE64Encoder().encode(sha1);
+        return Base64.getEncoder().encodeToString(sha1);
     }
 
 //    public static void main(String[] args) throws Exception {

+ 1 - 1
dbsyncer-connector/src/main/java/org/dbsyncer/connector/ConnectorFactory.java

@@ -59,7 +59,7 @@ public class ConnectorFactory implements DisposableBean {
             connectorCache.remove(cacheKey);
         }
         connect(config);
-        return isAlive(config);
+        return connector.isAlive(connectorCache.get(cacheKey));
     }
 
     /**

+ 19 - 0
dbsyncer-connector/src/main/java/org/dbsyncer/connector/database/setter/IntegerSetter.java

@@ -1,7 +1,9 @@
 package org.dbsyncer.connector.database.setter;
 
+import org.dbsyncer.connector.ConnectorException;
 import org.dbsyncer.connector.database.AbstractSetter;
 
+import java.math.BigInteger;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 
@@ -12,4 +14,21 @@ public class IntegerSetter extends AbstractSetter<Integer> {
         ps.setInt(i, val);
     }
 
+    @Override
+    protected void setIfValueTypeNotMatch(PreparedFieldMapper mapper, PreparedStatement ps, int i, int type, Object val)
+            throws SQLException {
+        if (val instanceof BigInteger) {
+            BigInteger bigInteger = (BigInteger) val;
+            ps.setInt(i, bigInteger.intValue());
+            return;
+        }
+
+        if (val instanceof Long) {
+            Long l = (Long) val;
+            ps.setInt(i, l.intValue());
+            return;
+        }
+
+        throw new ConnectorException(String.format("IntegerSetter can not find type [%s], val [%s]", type, val));
+    }
 }

+ 1 - 1
dbsyncer-connector/src/main/java/org/dbsyncer/connector/es/ESConnector.java

@@ -78,7 +78,7 @@ public final class ESConnector extends AbstractConnector implements Connector<ES
             return client.ping(RequestOptions.DEFAULT);
         } catch (IOException e) {
             logger.error(e.getMessage());
-            return false;
+            throw new ConnectorException(e.getMessage());
         }
     }
 

+ 1 - 1
dbsyncer-connector/src/main/java/org/dbsyncer/connector/util/ESUtil.java

@@ -55,7 +55,7 @@ public abstract class ESUtil {
      * @return
      */
     private static HttpHost makeHttpHost(String address, String scheme) {
-        String[] arr = address.split(":");
+        String[] arr = StringUtil.split(address, ":");
         if (arr.length == ADDRESS_LENGTH) {
             String ip = arr[0];
             int port = Integer.parseInt(arr[1]);

+ 1 - 1
dbsyncer-listener/src/main/java/org/dbsyncer/listener/mysql/MysqlExtractor.java

@@ -34,7 +34,7 @@ public class MysqlExtractor extends AbstractExtractor {
 
     private static final String          BINLOG_FILENAME = "fileName";
     private static final String          BINLOG_POSITION = "position";
-    private static final int             RETRY_TIMES     = 3;
+    private static final int             RETRY_TIMES     = 10;
     private static final int             MASTER          = 0;
     private Map<Long, TableMapEventData> tables          = new HashMap<>();
     private BinaryLogClient              client;

+ 17 - 6
dbsyncer-manager/src/main/java/org/dbsyncer/manager/ManagerFactory.java

@@ -14,14 +14,17 @@ import org.dbsyncer.manager.config.QueryConfig;
 import org.dbsyncer.manager.enums.GroupStrategyEnum;
 import org.dbsyncer.manager.enums.HandlerEnum;
 import org.dbsyncer.manager.puller.Puller;
-import org.dbsyncer.manager.template.impl.DataTemplate;
 import org.dbsyncer.manager.template.impl.OperationTemplate;
 import org.dbsyncer.parser.Parser;
 import org.dbsyncer.parser.enums.ConvertEnum;
 import org.dbsyncer.parser.enums.MetaEnum;
+import org.dbsyncer.parser.enums.ModelEnum;
+import org.dbsyncer.parser.logger.LogService;
+import org.dbsyncer.parser.logger.LogType;
 import org.dbsyncer.parser.model.*;
 import org.dbsyncer.plugin.PluginFactory;
 import org.dbsyncer.plugin.config.Plugin;
+import org.dbsyncer.storage.StorageService;
 import org.dbsyncer.storage.constant.ConfigConstant;
 import org.dbsyncer.storage.enums.StorageDataStatusEnum;
 import org.dbsyncer.storage.enums.StorageEnum;
@@ -53,7 +56,10 @@ public class ManagerFactory implements Manager, ApplicationListener<ClosedEvent>
     private OperationTemplate operationTemplate;
 
     @Autowired
-    private DataTemplate dataTemplate;
+    private StorageService storageService;
+
+    @Autowired
+    private LogService logService;
 
     @Autowired
     private Map<String, Puller> map;
@@ -241,23 +247,28 @@ public class ManagerFactory implements Manager, ApplicationListener<ClosedEvent>
     public Paging queryData(Query query, String collectionId) {
         query.setType(StorageEnum.DATA);
         query.setCollection(collectionId);
-        return dataTemplate.query(query);
+        return storageService.query(query);
     }
 
     @Override
     public void clearData(String collectionId) {
-        dataTemplate.clear(StorageEnum.DATA, collectionId);
+        Meta meta = getMeta(collectionId);
+        Mapping mapping = getMapping(meta.getMappingId());
+        String model = ModelEnum.getModelEnum(mapping.getModel()).getName();
+        LogType.MappingLog log = LogType.MappingLog.CLEAR_DATA;
+        logService.log(log, "%s:%s(%s)", log.getMessage(), mapping.getName(), model);
+        storageService.clear(StorageEnum.DATA, collectionId);
     }
 
     @Override
     public Paging queryLog(Query query) {
         query.setType(StorageEnum.LOG);
-        return dataTemplate.query(query);
+        return storageService.query(query);
     }
 
     @Override
     public void clearLog() {
-        dataTemplate.clear(StorageEnum.LOG, null);
+        storageService.clear(StorageEnum.LOG, null);
     }
 
     @Override

+ 0 - 37
dbsyncer-manager/src/main/java/org/dbsyncer/manager/template/impl/DataTemplate.java

@@ -1,37 +0,0 @@
-package org.dbsyncer.manager.template.impl;
-
-import org.dbsyncer.common.model.Paging;
-import org.dbsyncer.storage.StorageService;
-import org.dbsyncer.storage.enums.StorageEnum;
-import org.dbsyncer.storage.query.Query;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * 同步数据和日志模板
- *
- * @author AE86
- * @version 1.0.0
- * @date 2020/5/20 18:59
- */
-@Component
-public final class DataTemplate {
-
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
-    @Autowired
-    private StorageService storageService;
-
-    public Paging query(Query query) {
-        return storageService.query(query);
-    }
-
-    public void clear(StorageEnum type, String collectionId) {
-        storageService.clear(type, collectionId);
-    }
-}

+ 0 - 2
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/Monitor.java

@@ -17,8 +17,6 @@ import java.util.List;
  */
 public interface Monitor {
 
-    boolean isAlive(String id);
-
     Mapping getMapping(String mappingId);
 
     List<Meta> getMetaAll();

+ 0 - 13
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/MonitorFactory.java

@@ -11,17 +11,13 @@ import org.dbsyncer.monitor.enums.ThreadPoolMetricEnum;
 import org.dbsyncer.monitor.model.AppReportMetric;
 import org.dbsyncer.monitor.model.MetricResponse;
 import org.dbsyncer.monitor.model.Sample;
-import org.dbsyncer.parser.model.Connector;
 import org.dbsyncer.parser.model.Mapping;
 import org.dbsyncer.parser.model.Meta;
 import org.dbsyncer.storage.constant.ConfigConstant;
 import org.dbsyncer.storage.enums.StorageDataStatusEnum;
 import org.dbsyncer.storage.query.Query;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.cache.annotation.Cacheable;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 
@@ -41,8 +37,6 @@ import java.util.concurrent.atomic.AtomicLong;
 @Component
 public class MonitorFactory implements Monitor {
 
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
     @Autowired
     private Manager manager;
 
@@ -55,13 +49,6 @@ public class MonitorFactory implements Monitor {
     @Value(value = "${dbsyncer.web.thread.pool.queue.capacity}")
     private int queueCapacity;
 
-    @Override
-    @Cacheable(value = "connector", keyGenerator = "cacheKeyGenerator")
-    public boolean isAlive(String id) {
-        Connector connector = manager.getConnector(id);
-        return null != connector ? manager.isAliveConnectorConfig(connector.getConfig()) : false;
-    }
-
     @Override
     public Mapping getMapping(String mappingId) {
         return manager.getMapping(mappingId);

+ 14 - 2
dbsyncer-parser/src/main/java/org/dbsyncer/parser/ParserFactory.java

@@ -83,13 +83,25 @@ public class ParserFactory implements Parser {
 
     @Override
     public boolean isAliveConnectorConfig(ConnectorConfig config) {
+        boolean alive = false;
         try {
-            return connectorFactory.isAlive(config);
+            alive = connectorFactory.isAlive(config);
         } catch (Exception e) {
             LogType.ConnectorLog logType = LogType.ConnectorLog.FAILED;
             flushService.asyncWrite(logType.getType(), String.format("%s%s", logType.getName(), e.getMessage()));
         }
-        return false;
+        // 断线重连
+        if(!alive){
+            try {
+                alive = connectorFactory.refresh(config);
+            } catch (Exception e) {
+                // nothing to do
+            }
+            if(alive){
+                logger.info(LogType.ConnectorLog.RECONNECT_SUCCESS.getMessage());
+            }
+        }
+        return alive;
     }
 
     @Override

+ 4 - 2
dbsyncer-parser/src/main/java/org/dbsyncer/parser/logger/LogType.java

@@ -78,7 +78,8 @@ public interface LogType {
         INSERT("20", "新增"),
         UPDATE("21", "修改"),
         DELETE("22", "删除"),
-        FAILED("23", "连接失败");
+        FAILED("23", "连接失败"),
+        RECONNECT_SUCCESS("24", "重连成功");
 
         private String type;
         private String message;
@@ -112,7 +113,8 @@ public interface LogType {
         UPDATE("31", "修改"),
         DELETE("32", "删除"),
         RUNNING("33", "启动"),
-        STOP("34", "停止");
+        STOP("34", "停止"),
+        CLEAR_DATA("35", "清空同步数据");
 
         private String type;
         private String message;

+ 9 - 0
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/MonitorController.java

@@ -1,6 +1,7 @@
 package org.dbsyncer.web.controller.monitor;
 
 import org.dbsyncer.biz.ConfigService;
+import org.dbsyncer.biz.ConnectorService;
 import org.dbsyncer.biz.MonitorService;
 import org.dbsyncer.biz.vo.AppReportMetricVo;
 import org.dbsyncer.biz.vo.ConfigVo;
@@ -46,6 +47,9 @@ public class MonitorController extends BaseController {
     @Autowired
     private MonitorService monitorService;
 
+    @Autowired
+    private ConnectorService connectorService;
+
     @Autowired
     private ConfigService configService;
 
@@ -78,6 +82,11 @@ public class MonitorController extends BaseController {
         recordHistoryStackMetric(MetricEnum.MEMORY_USED, memory, memoryHistoryStackValueFormatterImpl);
     }
 
+    @Scheduled(fixedRate = 10000)
+    public void refreshConnectorHealth() {
+        connectorService.refreshHealth();
+    }
+
     @GetMapping("/queryData")
     @ResponseBody
     public RestResult queryData(HttpServletRequest request) {

+ 0 - 1
dbsyncer-web/src/main/resources/application.properties

@@ -4,7 +4,6 @@ server.port=18686
 #web
 dbsyncer.web.login.username=admin
 dbsyncer.web.login.password=0DPiKuNIrrVmD8IUCuw1hQxNqZc=
-dbsyncer.web.cache.connector.timeout=5
 dbsyncer.web.thread.pool.core.size=10
 dbsyncer.web.thread.pool.queue.capacity=1000
 server.servlet.session.timeout=1800

+ 1 - 1
dbsyncer-web/src/main/resources/public/connector/add.html

@@ -54,7 +54,7 @@
                             </div>
 
                             <!-- 连接配置 -->
-                            <div class="connectorConfig"></div>
+                            <div id="connectorConfig"></div>
 
                         </div>
                     </div>

+ 3 - 6
dbsyncer-web/src/main/resources/public/connector/addDqlMysql.html

@@ -37,7 +37,7 @@
     <div class="form-group">
         <label class="col-sm-2 control-label">驱动 </label>
         <div class="col-sm-10">
-            <select class="form-control select-control" name="driverClassName">
+            <select id="driverClassName" class="form-control select-control" name="driverClassName">
                 <option value="com.mysql.jdbc.Driver" th:selected="${connector?.config?.driverClassName eq 'com.mysql.jdbc.Driver'}">com.mysql.jdbc.Driver</option>
                 <option value="com.mysql.cj.jdbc.Driver" th:selected="${connector?.config?.driverClassName eq 'com.mysql.cj.jdbc.Driver'}">com.mysql.cj.jdbc.Driver</option>
             </select>
@@ -47,11 +47,8 @@
 
 <script type="text/javascript">
 $(function () {
-    // 初始化select2插件
-    $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelectIndex($("#driverClassName"), 1);
 })
 </script>
 </html>

+ 3 - 6
dbsyncer-web/src/main/resources/public/connector/addElasticsearch.html

@@ -30,7 +30,7 @@
         </div>
         <label class="col-sm-2 control-label">协议 </label>
         <div class="col-sm-4">
-            <select class="form-control select-control" name="schema">
+            <select id="schema" class="form-control select-control" name="schema">
                 <option value="http" th:selected="${connector?.config?.schema eq 'http'}">http</option>
                 <option value="tcp" th:selected="${connector?.config?.schema eq 'tcp'}">tcp</option>
             </select>
@@ -47,11 +47,8 @@
 
 <script type="text/javascript">
 $(function () {
-    // 初始化select2插件
-    $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelectIndex($("#schema"), 1);
 })
 </script>
 </html>

+ 3 - 6
dbsyncer-web/src/main/resources/public/connector/addMysql.html

@@ -22,7 +22,7 @@
     <div class="form-group">
         <label class="col-sm-2 control-label">驱动 </label>
         <div class="col-sm-10">
-            <select class="form-control select-control" name="driverClassName">
+            <select id="driverClassName" class="form-control select-control" name="driverClassName">
                 <option value="com.mysql.jdbc.Driver" th:selected="${connector?.config?.driverClassName eq 'com.mysql.jdbc.Driver'}">com.mysql.jdbc.Driver</option>
                 <option value="com.mysql.cj.jdbc.Driver" th:selected="${connector?.config?.driverClassName eq 'com.mysql.cj.jdbc.Driver'}">com.mysql.cj.jdbc.Driver</option>
             </select>
@@ -32,11 +32,8 @@
 
 <script type="text/javascript">
 $(function () {
-    // 初始化select2插件
-    $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelectIndex($("#driverClassName"), 1);
 })
 </script>
 </html>

+ 2 - 2
dbsyncer-web/src/main/resources/public/index.html

@@ -17,9 +17,9 @@
     <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/bootstrap/bootstrap.min.css}"/>
     <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/bootstrap-dialog/bootstrap-dialog.min.css}"/>
     <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/bootstrap-fileinput/fileinput.min.css}"/>
+    <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/bootstrap-select/bootstrap-select.min.css}"/>
     <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/icheck/all.css}"/>
     <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/loading-plus/loading-plus.css}"/>
-    <link type="text/css" rel="stylesheet" th:href="@{/plugins/css/select2/select2.min.css}"/>
     <link type="text/css" rel="stylesheet" th:href="@{/css/common.css}">
     <link type="text/css" rel="stylesheet" th:href="@{/css/index/index.css}">
 </head>
@@ -45,10 +45,10 @@
 <script th:src="@{/plugins/js/bootstrap-fileinput/fileinput.min.js}"></script>
 <script th:src="@{/plugins/js/bootstrap-fileinput/theme.min.js}"></script>
 <script th:src="@{/plugins/js/bootstrap-fileinput/zh.js}"></script>
+<script th:src="@{/plugins/js/bootstrap-select/bootstrap-select.min.js}"></script>
 <script th:src="@{/plugins/js/icheck/icheck.min.js}"></script>
 <script th:src="@{/plugins/js/loading-plus/loading-plus.js}"></script>
 <script th:src="@{/plugins/js/placeholder/jquery.placeholder.js}"></script>
-<script th:src="@{/plugins/js/select2/select2.min.js}"></script>
 <script th:src="@{/plugins/js/formValidate/formValidate.js}"></script>
 <script th:src="@{/plugins/js/sql-formatter/sql-formatter.min.js}"></script>
 <script th:src="@{/plugins/js/echarts/echarts.min.js}"></script>

+ 1 - 1
dbsyncer-web/src/main/resources/public/mapping/editParameter.html

@@ -10,7 +10,7 @@
             <div class="col-md-4">
                 <label class="col-sm-3 control-label text-right"><span title="区分Oracle增量同步数据字段,会将该字段设置为目标源唯一主键">ROWID</span></label>
                 <div class="col-sm-9">
-                    <select name="ORACLE_ROW_ID" class="form-control select-control">
+                    <select id="oracleRowId" name="ORACLE_ROW_ID" class="form-control select-control-default">
                         <option value="" selected="selected">无</option>
                         <!-- Mapping params -->
                         <option th:if="${tableGroup} == null" th:each="c,s:${mapping?.targetColumn}" th:value="${c?.name}" th:text="${c?.name} +' (' + ${c?.typeName} +')'" th:selected="${c?.name eq mapping?.params?.get('ORACLE_ROW_ID')}"/>

+ 2 - 2
dbsyncer-web/src/main/resources/public/mapping/editPlugin.html

@@ -10,8 +10,8 @@
             <div class="col-md-4">
                 <label class="col-sm-3 control-label text-right">名称</label>
                 <div class="col-sm-9">
-                    <select id="sourceStrategyConvertRule" name="pluginClassName" class="form-control select-control">
-                        <option value="">无</option>
+                    <select id="pluginClassName" name="pluginClassName" class="form-control select-control-default">
+                        <option value="" selected="selected">无</option>
                         <option th:value="${p?.className}" th:text="${p?.name +'_'+ p?.version}" th:each="p,state : ${plugin}" th:selected="${tableGroup eq null and p.className eq mapping?.plugin?.className or p.className eq tableGroup?.plugin?.className}">
                     </select>
                 </div>

+ 2 - 2
dbsyncer-web/src/main/resources/public/mapping/editTable.html

@@ -10,7 +10,7 @@
         <div class="col-md-5">
             <label class="col-sm-3 control-label text-right">数据源表</label>
             <div class="col-sm-9">
-                <select id="sourceTable" class="form-control select-control">
+                <select id="sourceTable" class="form-control select-control-table" multiple="multiple">
                     <option th:each="t,s:${mapping?.sourceConnector?.table}" th:value="${t}" th:text="${t}" />
                 </select>
             </div>
@@ -24,7 +24,7 @@
             <div class="form-group">
                 <label class="col-sm-3 control-label text-right">目标源表</label>
                 <div class="col-sm-9">
-                    <select id="targetTable" class="form-control select-control">
+                    <select id="targetTable" class="form-control select-control-table" multiple="multiple">
                         <option th:each="t,s:${mapping?.targetConnector?.table}" th:value="${t}" th:text="${t}" />
                     </select>
                 </div>

+ 4 - 4
dbsyncer-web/src/main/resources/public/mapping/editTableGroup.html

@@ -83,8 +83,8 @@
                                 <div class="col-md-5">
                                     <label class="col-sm-3 control-label text-right">数据源表字段</label>
                                     <div class="col-sm-9">
-                                        <select id="sourceFieldMapping" class="form-control select-control">
-                                            <option value="">无</option>
+                                        <select id="sourceTableField" class="form-control select-control-default">
+                                            <option value="" selected="selected">无</option>
                                             <option th:each="c,s:${tableGroup?.sourceTable?.column}" th:value="${c?.name}" th:text="${c?.name} +' (' + ${c?.typeName} +')'" />
                                         </select>
                                     </div>
@@ -98,8 +98,8 @@
                                     <div class="form-group">
                                         <label class="col-sm-3 control-label text-right">目标源表字段</label>
                                         <div class="col-sm-9">
-                                            <select id="targetFieldMapping" class="form-control select-control">
-                                                <option value="">无</option>
+                                            <select id="targetTableField" class="form-control select-control-default">
+                                                <option value="" selected="selected">无</option>
                                                 <option th:each="c,s:${tableGroup?.targetTable?.column}" th:value="${c?.name}" th:text="${c?.name} +' (' + ${c?.typeName} +')'" />
                                             </select>
                                         </div>

+ 2 - 2
dbsyncer-web/src/main/resources/public/monitor/monitor.html

@@ -103,7 +103,7 @@
                                 <div class="col-md-1">
                                     <!-- 是否包含成功 -->
                                     <select id="searchDataSuccess" class="form-control select-control">
-                                        <option th:value="${c?.value}" th:text="${c?.message}" th:each="c,state : ${storageDataStatus}"/>
+                                        <option th:value="${c?.value}" th:text="${c?.message}" th:each="c,state : ${storageDataStatus}" th:selected="${c?.value eq 0}"/>
                                     </select>
                                 </div>
                                 <div class="col-sm-4">
@@ -164,7 +164,7 @@
                                 <u data-toggle="collapse" class="dbsyncer_pointer" href="#queryLogPanel">查询日志</u>
                             </h4>
                         </div>
-                        <div id="queryLogPanel" class="panel-body panel-collapse collapse">
+                        <div id="queryLogPanel" class="panel-body panel-collapse collapse in">
                             <div class="form-group">
                                 <div class="col-sm-4">
                                     <input id="searchLogKeyword" class="form-control" type="text" maxlength="32" placeholder="请输入内容关键字(最多32个字)." />

+ 4 - 4
dbsyncer-web/src/main/resources/static/css/common.css

@@ -7,12 +7,12 @@
 .dbsyncer_block:hover { cursor:pointer; background-color: #EBEBEB; -moz-box-shadow:2px 2px 5px; -webkit-box-shadow:2px 2px 5px; box-shadow:2px 2px 5px; -webkit-transform:translateY(-3px); transform: translateY(-3px); transition: all 0.3s ease-in-out;}
 .driverVerifcateRequired{color:#d9534f;}
 .dbsyncerVerifcateError{border-color: #b94a48;}
-.driver_add_vertical_center {padding-top: 100%;}
-.footerContainer{width:100%;position:fixed;bottom:0;background-color:white;}
-#initContainer{min-height: 600px;}
+.footerContainer{width:100%;position:relative;bottom:0;background-color:white;}
 /**
  * 强制单词换行
  */
 .driver_break_word { word-break: break-all;word-wrap:break-word;white-space:normal}
 .fa_gray {color: gray}
-.fa_blueviolet {color: blueviolet}
+.fa_blueviolet {color: blueviolet}
+.dbsyncer_btn-info { background-color: #E7EDF8;}
+.dbsyncer_btn-info.active, .dbsyncer_btn-info.focus, .dbsyncer_btn-info:active, .dbsyncer_btn-info:focus, .dbsyncer_btn-info:hover, .open>.dropdown-toggle.dbsyncer_btn-info {background-color: #D4DDED;}

+ 28 - 0
dbsyncer-web/src/main/resources/static/js/common.js

@@ -4,6 +4,7 @@ var $path = document.location.pathname;
 var $basePath = $location[0] + '//' + $location[2] + $path.substr(0, $path.substr(1).indexOf("/")+1);
 // 全局内容区域
 var $initContainer = $("#initContainer");
+    $initContainer.css("min-height", $(window).height() - 125);
 // 监控定时器
 var timer;
 
@@ -36,6 +37,33 @@ function beautifySql(){
     $sql.removeAttr('tmp');
 }
 
+// 初始化select组件,默认选中
+function initSelectIndex($select, $selectedIndex){
+    initSelect($select);
+
+    $.each($select, function () {
+        var v = $(this).selectpicker('val');
+        if (undefined == v || '' == v) {
+            var $option = $(this).find("option")[$selectedIndex];
+            if(undefined != $option){
+                $(this).selectpicker('val', $option.value);
+            }
+        }
+    });
+}
+function initSelect($select){
+    $select.selectpicker({
+        "style":'dbsyncer_btn-info',
+        "title":"请选择",
+        "actionsBox":true,
+        "liveSearch":true,
+        "selectAllText":"全选",
+        "deselectAllText":"取消全选",
+        "noneResultsText":"没有找到 {0}",
+        "selectedTextFormat":"count > 10"
+    });
+}
+
 // ******************* 扩展JS表单方法 ***************************
 $.fn.serializeJson = function () {
     var o = {};

+ 25 - 27
dbsyncer-web/src/main/resources/static/js/connector/add.js

@@ -9,47 +9,45 @@ function submit(data) {
     });
 }
 
-var check = function () {
-    var $form = $("#connectorAddForm");
-    if ($form.formValidate() == true) {
-        var data = $form.serializeJson();
-        submit(data);
-    }
-};
-
-//切换连接
-function changeConnectorType($this) {
+// 绑定连接器类型切换事件
+function bindConnectorChangeEvent($select) {
+    // 默认渲染连接页面
+    $select.on('changed.bs.select',function(e){
+        changeConnectorType($(this));
+    });
+
+    changeConnectorType($select);
+}
+
+function changeConnectorType($select){
     //连接类型
-    var connType = $this.val();
+    var connType = $select.selectpicker('val');
     //获取连接配置元素
-    var connectorConfig = $this.parent().parent().parent().find(".connectorConfig");
+    var $connectorConfig = $("#connectorConfig");
     //清空配置
-    connectorConfig.html("");
+    $connectorConfig.html("");
 
     //加载页面
-    connectorConfig.load($basePath + "/connector/page/add" + connType);
+    $connectorConfig.load($basePath + "/connector/page/add" + connType);
 }
 
 $(function () {
     // 兼容IE PlaceHolder
     $('input[type="text"],input[type="password"],textarea').PlaceHolder();
 
-    // 初始化select2插件
-    var $connectorTypeSelect = $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
-    // 默认渲染连接页面
-    changeConnectorType($connectorTypeSelect);
-
-    //连接类型切换事件
-    $("select[name='connectorType']").change(function () {
-        changeConnectorType($(this));
-    });
+    // 初始化select插件
+    var $select = $("#connectorType");
+    initSelectIndex($select, 1);
+    // 绑定连接器类型切换事件
+    bindConnectorChangeEvent($select);
 
     //保存
     $("#connectorSubmitBtn").click(function () {
-        check();
+        var $form = $("#connectorAddForm");
+        if ($form.formValidate() == true) {
+            var data = $form.serializeJson();
+            submit(data);
+        }
     });
 
     //返回

+ 3 - 5
dbsyncer-web/src/main/resources/static/js/connector/edit.js

@@ -13,11 +13,9 @@ $(function () {
     // 兼容IE PlaceHolder
     $('input[type="text"],input[type="password"],textarea').PlaceHolder();
 
-    // 初始化select2插件
-    var $connectorTypeSelect = $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelect($(".select-control"));
+
     //保存
     $("#connectorSubmitBtn").click(function () {
         var $form = $("#connectorModifyForm");

+ 2 - 5
dbsyncer-web/src/main/resources/static/js/mapping/add.js

@@ -22,11 +22,8 @@ $(function () {
     // 兼容IE PlaceHolder
     $('input[type="text"],input[type="password"],textarea').PlaceHolder();
 
-    // 初始化select2插件
-    $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelectIndex($(".select-control"), 1);
 
     // 绑定匹配相似表复选框事件
     bindAutoMatchTableCheckBoxClick();

+ 42 - 25
dbsyncer-web/src/main/resources/static/js/mapping/edit.js

@@ -98,15 +98,50 @@ function bindMappingTableGroupListClick() {
     });
 }
 
+// 绑定下拉选择事件自动匹配相似表事件
+function bindTableSelect(){
+    var $sourceSelect = $("#sourceTable");
+    var $targetSelect = $("#targetTable");
+    $sourceSelect.on('changed.bs.select',function(e){
+        $targetSelect.selectpicker('val', $(this).selectpicker('val'));
+    });
+    bindMappingTableGroupAddClick($sourceSelect, $targetSelect);
+}
+
 // 绑定新增表关系点击事件
-function bindMappingTableGroupAddClick() {
+function bindMappingTableGroupAddClick($sourceSelect, $targetSelect) {
     var $addBtn = $("#tableGroupAddBtn");
     $addBtn.unbind("click");
     $addBtn.bind('click', function () {
         var m = {};
         m.mappingId = $(this).attr("mappingId");
-        m.sourceTable = $("#sourceTable option:checked").val();
-        m.targetTable = $("#targetTable option:checked").val();
+        m.sourceTable = $sourceSelect.selectpicker('val');
+        m.targetTable = $targetSelect.selectpicker('val');
+        if(undefined == m.sourceTable){
+            bootGrowl("请选择数据源表", "danger");
+            return;
+        }
+        if(undefined == m.targetTable){
+            bootGrowl("请选择目标源表", "danger");
+            return;
+        }
+
+        // 如果存在多个选择,只筛选相似表
+        var sLen = m.sourceTable.length;
+        var tLen = m.targetTable.length;
+        if(1 < sLen || 1 < tLen){
+            var mark = [];
+            for(j = 0; j < sLen; j++) {
+                if(-1 != m.targetTable.indexOf(m.sourceTable[j])){
+                    mark.push(m.sourceTable[j]);
+                }
+            }
+            m.sourceTable = mark;
+            m.targetTable = mark;
+        }
+        m.sourceTable = m.sourceTable.join();
+        m.targetTable = m.targetTable.join();
+
         doPoster("/tableGroup/add", m, function (data) {
             if (data.success == true) {
                 bootGrowl("新增映射关系成功!", "success");
@@ -136,18 +171,6 @@ function bindMappingTableGroupDelClick() {
     });
 }
 
-// 绑定下拉自动匹配字段
-function bindAutoSelect(){
-    var $sourceSelect = $("#sourceTable");
-    var $targetSelect = $("#targetTable");
-
-    // 绑定数据源下拉切换事件
-    $sourceSelect.change(function () {
-        var v = $(this).select2("val");
-        $targetSelect.val(v).trigger("change");
-    });
-}
-
 // 修改驱动名称
 function mappingModifyName(){
     var $name = $("#mappingModifyName");
@@ -171,19 +194,13 @@ $(function () {
 
     // 绑定表关系点击事件
     bindMappingTableGroupListClick();
-    // 绑定新增表关系点击事件
-    bindMappingTableGroupAddClick();
+    // 绑定下拉选择事件自动匹配相似表事件
+    bindTableSelect();
     // 绑定删除表关系点击事件
     bindMappingTableGroupDelClick();
 
-    // 绑定下拉自动匹配字段
-    bindAutoSelect();
-
-    // 初始化select2插件
-    $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelectIndex($(".select-control-table"), 0);
 
     // 保存
     $("#mappingSubmitBtn").click(function () {

+ 8 - 6
dbsyncer-web/src/main/resources/static/js/mapping/editFilterAndConvert.js

@@ -66,9 +66,9 @@ function bindConditionAddClick() {
     var $conditionAdd = $("#conditionAdd");
     $conditionAdd.unbind("click");
     $conditionAdd.bind('click', function () {
-        var conditionOperation = $("#conditionOperation").select2("val");
-        var conditionSourceField = $("#conditionSourceField").select2("val");
-        var conditionFilter = $("#conditionFilter").select2("val");
+        var conditionOperation = $("#conditionOperation").selectpicker("val");
+        var conditionSourceField = $("#conditionSourceField").selectpicker("val");
+        var conditionFilter = $("#conditionFilter").selectpicker("val");
         var conditionArg = $("#conditionArg").val();
         // 非空检查
         if(conditionSourceField == null || conditionSourceField == undefined || conditionSourceField == ''){
@@ -121,9 +121,9 @@ function bindConvertAddClick() {
     $convertAdd.unbind("click");
     $convertAdd.bind('click', function () {
         var $convertOperator = $("#convertOperator");
-        var convertOperatorVal = $convertOperator.select2("val");
-        var convertOperatorText = $convertOperator.select2("data")[0].text;
-        var convertTargetField = $("#convertTargetField").select2("val");
+        var convertOperatorVal = $convertOperator.selectpicker("val");
+        var convertOperatorText = $convertOperator.find("option:selected")[0].text;
+        var convertTargetField = $("#convertTargetField").selectpicker("val");
         var convertArg = $(".convertArg:eq(0)").val();
         var convertArg1 = $(".convertArg:eq(1)").val();
         // 多个参数时,英文符号“,”拼接
@@ -163,6 +163,8 @@ function bindConvertAddClick() {
 }
 
 $(function() {
+    initSelect($(".select-control-default"));
+    initSelectIndex($(".select-control"), 1);
     // 过滤条件
     initFilter();
     bindConditionAddClick();

+ 2 - 2
dbsyncer-web/src/main/resources/static/js/mapping/editParam.js

@@ -10,9 +10,9 @@ function bingMappingParamsInputClick(){
 }
 
 // 生成参数配置
-function genMappingParams($inputs){
+function genMappingParams($select){
     var params = {};
-    $inputs.each(function () {
+    $select.each(function () {
         if('' != $(this).val()){
             params[$(this).attr("name")] = $(this).val();
         }

+ 16 - 29
dbsyncer-web/src/main/resources/static/js/mapping/editTableGroup.js

@@ -10,14 +10,6 @@ function submit(data) {
     });
 }
 
-// 初始化select2插件
-function bindSelectEvent($selector){
-    $selector.find(".select-control").select2({
-        width : "100%",
-        theme : "classic"
-    });
-}
-
 // 初始化映射关系参数
 function initFieldMappingParams(){
     // 生成JSON参数
@@ -85,12 +77,23 @@ function bindFieldMappingListClick(){
         initFieldMappingParams();
     });
 }
+// 绑定下拉选择事件自动匹配相似字段事件
+function bindTableFieldSelect(){
+    var $sourceSelect = $("#sourceTableField");
+    var $targetSelect = $("#targetTableField");
+
+    // 绑定数据源下拉切换事件
+    $sourceSelect.on('changed.bs.select',function(e){
+        $targetSelect.selectpicker('val', $(this).selectpicker('val'));
+    });
+    bindFieldMappingAddClick($sourceSelect, $targetSelect)
+}
 // 绑定添加字段映射点击事件
-function bindFieldMappingAddClick(){
+function bindFieldMappingAddClick($sourceSelect, $targetSelect){
     var $btn = $("#fieldMappingAddBtn");
     $btn.bind('click', function(){
-        var sField = $("#sourceFieldMapping").select2("val");
-        var tField = $("#targetFieldMapping").select2("val");
+        var sField = $sourceSelect.selectpicker("val");
+        var tField = $targetSelect.selectpicker("val");
         sField = sField == null ? "" : sField;
         tField = tField == null ? "" : tField;
         // 非空检查
@@ -139,17 +142,6 @@ function bindFieldMappingDelClick(){
         }
     });
 }
-// 绑定下拉自动匹配字段
-function bindAutoSelect(){
-    var $sourceSelect = $("#sourceFieldMapping");
-    var $targetSelect = $("#targetFieldMapping");
-
-    // 绑定数据源下拉切换事件
-    $sourceSelect.change(function () {
-        var v = $(this).select2("val");
-        $targetSelect.val(v).trigger("change");
-    });
-}
 // 返回驱动配置页面
 function backMappingPage($this){
     doLoader('/mapping/page/edit?id=' + $this.attr("mappingId"));
@@ -158,17 +150,12 @@ function backMappingPage($this){
 $(function() {
     // 绑定表字段关系点击事件
     initFieldMappingParams();
+    // 绑定下拉选择事件自动匹配相似字段事件
+    bindTableFieldSelect();
     // 绑定删除表字段映射事件
     bindFieldMappingCheckBoxClick();
     bindFieldMappingListClick();
-    bindFieldMappingAddClick();
     bindFieldMappingDelClick();
-    // 绑定下拉自动匹配字段
-    bindAutoSelect();
-
-    // 初始化select2插件
-    bindSelectEvent($("#tableGroupBaseConfig"));
-    bindSelectEvent($("#tableGroupSuperConfig"));
 
     //保存
     $("#tableGroupSubmitBtn").click(function () {

+ 6 - 9
dbsyncer-web/src/main/resources/static/js/monitor/index.js

@@ -108,8 +108,8 @@ function showMore($this, $url, $params, $call){
 function bindQueryDataEvent() {
     $("#queryDataBtn").click(function () {
         var keyword = $("#searchDataKeyword").val();
-        var id = $("#searchMetaData").select2("val");
-        var success = $("#searchDataSuccess").select2("val");
+        var id = $("#searchMetaData").selectpicker("val");
+        var success = $("#searchDataSuccess").selectpicker("val");
         doGetter('/monitor/queryData', {"error": keyword, "success": success, "id" : id, "pageNum" : 1, "pageSize" : 10}, function (data) {
             if (data.success == true) {
                 refreshDataList(data.resultValue);
@@ -122,8 +122,8 @@ function bindQueryDataEvent() {
 function bindQueryDataMoreEvent() {
     $("#queryDataMore").click(function () {
         var keyword = $("#searchDataKeyword").val();
-        var id = $("#searchMetaData").select2("val");
-        var success = $("#searchDataSuccess").select2("val");
+        var id = $("#searchMetaData").selectpicker("val");
+        var success = $("#searchDataSuccess").selectpicker("val");
         showMore($(this), '/monitor/queryData', {"error": keyword, "success": success, "id" : id}, function(resultValue){
             refreshDataList(resultValue, true)
         });
@@ -435,11 +435,8 @@ function createTimer(){
 }
 
 $(function () {
-    // 初始化select2插件
-    $(".select-control").select2({
-        width: "100%",
-        theme: "classic"
-    });
+    // 初始化select插件
+    initSelect($(".select-control"));
 
     // 连接类型切换事件
     $("#searchMetaData").change(function () {

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 5 - 0
dbsyncer-web/src/main/resources/static/plugins/css/bootstrap-select/bootstrap-select.min.css


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dbsyncer-web/src/main/resources/static/plugins/css/select2/select2.min.css


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 7 - 0
dbsyncer-web/src/main/resources/static/plugins/js/bootstrap-select/bootstrap-select.min.js


+ 5 - 5
dbsyncer-web/src/main/resources/static/plugins/js/loading-plus/loading-plus.js

@@ -1,8 +1,8 @@
 /***************************************************** 
  *                                                 *#*
- * @项目:loadingT                                 *#*
- * @作者:AE86                                     *#*
- * @Date:2016-11-21 23:46:56                     *#*
+ * @项目:loadingT                                   *#*
+ * @作者:AE86                                       *#*
+ * @Date:2016-11-21 23:46:56                       *#*
  *****************************************************
  *###################################################*/
 
@@ -17,7 +17,7 @@ $.loadingT = {
 		$loadingT.html("<div class='loading-indicator' unselectable='on' onselectstart='return false;'>"+title+content+"</div>");
 		$loadingT.css({ "height":$(document.body).height()+'px' });
 		var $indicato = $(".loading-indicator");
-		$indicato.css({ "margin-top":(document.body.clientHeight / 2) -($indicato.height() / 2) });
+		$indicato.css({ "margin-top":($(window).height() / 2) -($indicato.height() / 2) });
 	}
 }
 //创建遮罩层
@@ -30,7 +30,7 @@ jQuery.extend({
 	resetIndicato:function(){
 		$(".loadingT").css({ "height":$(document.body).height()+'px' });
 		var $indicato = $(".loading-indicator");
-		$indicato.css({ "margin-top":(document.body.clientHeight / 2) -($indicato.height() / 2) });
+		$indicato.css({ "margin-top":($(window).height() / 2) -($indicato.height() / 2) });
 	}
 });
 //兼容浏览器缩放

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 3
dbsyncer-web/src/main/resources/static/plugins/js/select2/select2.min.js


Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно