Browse Source

动态支持MySQL/Oracle

张泳健 5 years ago
parent
commit
e7c8d4acb8

+ 5 - 1
config/application-mysql.yml View File

1
-database:
1
+from-db:
2
+  url: jdbc:mysql:replication://192.168.10.210:6446,192.168.10.210:6447/fmmp?serverTimezone=Asia/Shanghai
3
+  user: root
4
+  password: R00T@mysql
5
+to-db:
2
   url: jdbc:mysql:replication://192.168.10.210:6446,192.168.10.210:6447/fmmp?serverTimezone=Asia/Shanghai
6
   url: jdbc:mysql:replication://192.168.10.210:6446,192.168.10.210:6447/fmmp?serverTimezone=Asia/Shanghai
3
   user: root
7
   user: root
4
   password: R00T@mysql
8
   password: R00T@mysql

+ 5 - 1
config/application-oracle.yml View File

1
-database:
1
+from-db:
2
   url: jdbc:oracle:thin:@192.168.10.236:1521:orcl
2
   url: jdbc:oracle:thin:@192.168.10.236:1521:orcl
3
   user: C##FMMP
3
   user: C##FMMP
4
   password: vcare~1(^_^)
4
   password: vcare~1(^_^)
5
+to-db:
6
+  url: jdbc:mysql:replication://192.168.10.210:6446,192.168.10.210:6447/fmmp?serverTimezone=Asia/Shanghai
7
+  user: root
8
+  password: R00T@mysql
5
 export:
9
 export:
6
   folder: ./logs/
10
   folder: ./logs/

+ 2 - 2
config/application.yml View File

1
 profile:
1
 profile:
2
-  active: mysql
3
-#   active: oracle
2
+#  active: mysql
3
+   active: oracle

+ 3 - 0
import.sh View File

1
+#/bin/bash
2
+
3
+echo "test"

+ 0 - 6
pom.xml View File

99
             <artifactId>reflections</artifactId>
99
             <artifactId>reflections</artifactId>
100
             <version>0.9.11</version>
100
             <version>0.9.11</version>
101
         </dependency>
101
         </dependency>
102
-
103
-        <dependency>
104
-            <groupId>org.apache.shardingsphere</groupId>
105
-            <artifactId>sharding-jdbc-core</artifactId>
106
-            <version>4.0.0-RC2</version>
107
-        </dependency>
108
         <dependency>
102
         <dependency>
109
             <groupId>javax.persistence</groupId>
103
             <groupId>javax.persistence</groupId>
110
             <artifactId>persistence-api</artifactId>
104
             <artifactId>persistence-api</artifactId>

+ 6 - 2
src/main/java/com/vcarecity/cvs/FileExporterApp.java View File

10
 import com.vcarecity.cvs.starter.SQLStarter;
10
 import com.vcarecity.cvs.starter.SQLStarter;
11
 import me.yuxiaoyao.config.loader.ConfigLoader;
11
 import me.yuxiaoyao.config.loader.ConfigLoader;
12
 
12
 
13
+import java.util.Map;
14
+import java.util.concurrent.ConcurrentHashMap;
15
+
13
 /**
16
 /**
14
  * @author Kerry on 19/11/27
17
  * @author Kerry on 19/11/27
15
  */
18
  */
17
 public class FileExporterApp {
20
 public class FileExporterApp {
18
 
21
 
19
     public static Injector injector;
22
     public static Injector injector;
23
+    public static Map<String, String[]> TABLE_COLUMN = new ConcurrentHashMap<>();
20
 
24
 
21
 
25
 
22
     public static void main(String[] args) throws Exception {
26
     public static void main(String[] args) throws Exception {
57
 
61
 
58
 
62
 
59
     private static void jdbcArgs(String[] args, AppProperties properties) {
63
     private static void jdbcArgs(String[] args, AppProperties properties) {
60
-        final DbProperties database = properties.getDatabase();
64
+        final DbProperties database = properties.getFromDb();
61
         for (String arg : args) {
65
         for (String arg : args) {
62
             if (arg.startsWith("jdbc.url=")) {
66
             if (arg.startsWith("jdbc.url=")) {
63
                 database.setUrl(arg.substring("jdbc.url=".length()).trim());
67
                 database.setUrl(arg.substring("jdbc.url=".length()).trim());
67
                 database.setPassword(arg.substring("jdbc.password=".length()).trim());
71
                 database.setPassword(arg.substring("jdbc.password=".length()).trim());
68
             }
72
             }
69
         }
73
         }
70
-        properties.setDatabase(database);
74
+        properties.setFromDb(database);
71
     }
75
     }
72
 }
76
 }

+ 76 - 0
src/main/java/com/vcarecity/cvs/core/ColumnUpdateMapper.java View File

1
+package com.vcarecity.cvs.core;
2
+
3
+import lombok.AllArgsConstructor;
4
+import lombok.Data;
5
+import lombok.NoArgsConstructor;
6
+
7
+import java.util.ArrayList;
8
+import java.util.HashSet;
9
+import java.util.List;
10
+import java.util.Set;
11
+
12
+/**
13
+ * @author Kerry on 19/11/29
14
+ */
15
+
16
+public class ColumnUpdateMapper {
17
+
18
+
19
+    @AllArgsConstructor
20
+    @NoArgsConstructor
21
+    @Data
22
+    private static class ColumnMapper {
23
+        private String origin;
24
+        private String update;
25
+    }
26
+
27
+    private static List<ColumnMapper> manualMapper;
28
+
29
+    private static List<String> MYSQL_KEY_WORD;
30
+
31
+    static {
32
+        manualMapper = new ArrayList<>();
33
+        manualMapper.add(new ColumnMapper("POSITION", "POSITIONS"));
34
+
35
+
36
+        Set<String> keyWord = new HashSet<>();
37
+        keyWord.add("POSITION");
38
+
39
+        MYSQL_KEY_WORD = new ArrayList<>(keyWord);
40
+    }
41
+
42
+
43
+    /**
44
+     * Oracle数据库的字段可能跟 MySQL 不一样,统一这里处理
45
+     *
46
+     * @param table
47
+     * @param headers
48
+     * @return
49
+     */
50
+    public static String[] updateColumnName(String table, String[] headers) {
51
+        // common mapper
52
+        for (int i = 0; i < headers.length; i++) {
53
+            final String h = headers[i].toUpperCase();
54
+            for (ColumnMapper columnMapper : manualMapper) {
55
+                if (columnMapper.getOrigin().equalsIgnoreCase(h)) {
56
+                    headers[i] = columnMapper.getUpdate();
57
+                    break;
58
+                }
59
+            }
60
+        }
61
+
62
+        // 关键字先处理下
63
+        for (int i = 0; i < headers.length; i++) {
64
+            final String h = headers[i].toUpperCase();
65
+            for (String s : MYSQL_KEY_WORD) {
66
+                if (s.equalsIgnoreCase(h)) {
67
+                    headers[i] = "`" + headers[i] + "`";
68
+                    break;
69
+                }
70
+            }
71
+        }
72
+
73
+        return headers;
74
+    }
75
+
76
+}

+ 33 - 0
src/main/java/com/vcarecity/cvs/event/ExportEventListener.java View File

1
+package com.vcarecity.cvs.event;
2
+
3
+/**
4
+ * @author Kerry on 19/11/29
5
+ */
6
+
7
+public interface ExportEventListener {
8
+
9
+    /**
10
+     * 导出之前
11
+     *
12
+     * @param filename
13
+     */
14
+    void beforeExport(String filename);
15
+
16
+    /**
17
+     * 导出成功
18
+     *
19
+     * @param filename
20
+     * @param table
21
+     * @param header
22
+     */
23
+    void exportSuccess(String filename, String table, String[] header);
24
+
25
+    /**
26
+     * 异常
27
+     *
28
+     * @param throwable
29
+     */
30
+    void exceptionCatch(Throwable throwable);
31
+
32
+
33
+}

+ 58 - 0
src/main/java/com/vcarecity/cvs/event/MySQLImportEvent.java View File

1
+package com.vcarecity.cvs.event;
2
+
3
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
4
+import com.google.inject.Inject;
5
+import com.vcarecity.cvs.core.ColumnUpdateMapper;
6
+import com.vcarecity.cvs.properties.AppProperties;
7
+import com.vcarecity.cvs.properties.DbProperties;
8
+import com.vcarecity.cvs.shell.MySQLImporter;
9
+import lombok.extern.slf4j.Slf4j;
10
+
11
+import java.util.concurrent.LinkedBlockingQueue;
12
+import java.util.concurrent.ThreadFactory;
13
+import java.util.concurrent.ThreadPoolExecutor;
14
+import java.util.concurrent.TimeUnit;
15
+import java.util.concurrent.atomic.AtomicInteger;
16
+
17
+/**
18
+ * @author Kerry on 19/11/29
19
+ */
20
+
21
+@Slf4j
22
+public class MySQLImportEvent implements ExportEventListener {
23
+
24
+    private AtomicInteger callIndex = new AtomicInteger(0);
25
+
26
+    private final DbProperties dbProperties;
27
+
28
+    @Inject
29
+    public MySQLImportEvent(AppProperties properties) {
30
+        this.dbProperties = properties.getToDb();
31
+    }
32
+
33
+    @Override
34
+    public void beforeExport(String filename) {
35
+        logger.info("MySQLImportEvent.beforeExport. filename = {}", filename);
36
+    }
37
+
38
+    @Override
39
+    public void exportSuccess(String filename, String table, String[] header) {
40
+        logger.info("MySQLImportEvent.exportSuccess. filename = {}", filename);
41
+
42
+        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("export-" + (callIndex.incrementAndGet()) + "+-%d").build();
43
+
44
+        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
45
+                new LinkedBlockingQueue<>(1024), factory, new ThreadPoolExecutor.AbortPolicy());
46
+
47
+        // 列名不一样时,转换
48
+        final String[] newHeader = ColumnUpdateMapper.updateColumnName(table, header);
49
+        executor.execute(new MySQLImporter(dbProperties, filename, table, newHeader));
50
+        executor.shutdown();
51
+    }
52
+
53
+
54
+    @Override
55
+    public void exceptionCatch(Throwable throwable) {
56
+        logger.info("MySQLImportEvent.exceptionCatch. throwable = {}", throwable);
57
+    }
58
+}

+ 5 - 1
src/main/java/com/vcarecity/cvs/module/SQLModule.java View File

5
 import com.google.inject.Provides;
5
 import com.google.inject.Provides;
6
 import com.google.inject.Singleton;
6
 import com.google.inject.Singleton;
7
 import com.google.inject.assistedinject.FactoryModuleBuilder;
7
 import com.google.inject.assistedinject.FactoryModuleBuilder;
8
+import com.vcarecity.cvs.event.ExportEventListener;
9
+import com.vcarecity.cvs.event.MySQLImportEvent;
8
 import com.vcarecity.cvs.factory.ResultHandlerFactory;
10
 import com.vcarecity.cvs.factory.ResultHandlerFactory;
9
 import com.vcarecity.cvs.properties.AppProperties;
11
 import com.vcarecity.cvs.properties.AppProperties;
10
 import com.vcarecity.cvs.properties.DbProperties;
12
 import com.vcarecity.cvs.properties.DbProperties;
24
     @Override
26
     @Override
25
     protected void configure() {
27
     protected void configure() {
26
 
28
 
29
+        bind(ExportEventListener.class).to(MySQLImportEvent.class);
30
+
27
         install(new FactoryModuleBuilder()
31
         install(new FactoryModuleBuilder()
28
                 .implement(ResultHandlerService.class, CSVResultHandlerServiceImpl.class)
32
                 .implement(ResultHandlerService.class, CSVResultHandlerServiceImpl.class)
29
                 .build(ResultHandlerFactory.class));
33
                 .build(ResultHandlerFactory.class));
49
     public HikariDataSource dataSource(AppProperties properties) {
53
     public HikariDataSource dataSource(AppProperties properties) {
50
         // @see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
54
         // @see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
51
 
55
 
52
-        final DbProperties database = properties.getDatabase();
56
+        final DbProperties database = properties.getFromDb();
53
         HikariConfig config = new HikariConfig();
57
         HikariConfig config = new HikariConfig();
54
         config.setJdbcUrl(database.getUrl());
58
         config.setJdbcUrl(database.getUrl());
55
         config.setUsername(database.getUser());
59
         config.setUsername(database.getUser());

+ 10 - 1
src/main/java/com/vcarecity/cvs/properties/AppProperties.java View File

1
 package com.vcarecity.cvs.properties;
1
 package com.vcarecity.cvs.properties;
2
 
2
 
3
+import com.fasterxml.jackson.annotation.JsonProperty;
3
 import lombok.Data;
4
 import lombok.Data;
4
 
5
 
5
 /**
6
 /**
8
 
9
 
9
 @Data
10
 @Data
10
 public class AppProperties {
11
 public class AppProperties {
11
-    private DbProperties database;
12
+
13
+    @JsonProperty("from-db")
14
+    private DbProperties fromDb;
15
+
16
+    @JsonProperty("to-db")
17
+    private DbProperties toDb;
18
+
12
     private Export export;
19
     private Export export;
13
 
20
 
14
     @Data
21
     @Data
15
     public static class Export {
22
     public static class Export {
16
         private String folder;
23
         private String folder;
17
     }
24
     }
25
+
26
+
18
 }
27
 }

+ 3 - 1
src/main/java/com/vcarecity/cvs/service/ResultHandlerService.java View File

12
     /**
12
     /**
13
      * ins
13
      * ins
14
      *
14
      *
15
+     * @param table
16
+     * @param header
15
      * @param dataList
17
      * @param dataList
16
      * @throws Exception
18
      * @throws Exception
17
      */
19
      */
18
-    <T> void resultHandler(List<T> dataList) throws Exception;
20
+    <T> void resultHandler(String table, String[] header, List<T> dataList) throws Exception;
19
 
21
 
20
 
22
 
21
 }
23
 }

+ 0 - 1
src/main/java/com/vcarecity/cvs/service/SQLQueryService.java View File

9
 
9
 
10
 public interface SQLQueryService {
10
 public interface SQLQueryService {
11
 
11
 
12
-
13
     /**
12
     /**
14
      * query by page
13
      * query by page
15
      *
14
      *

+ 52 - 17
src/main/java/com/vcarecity/cvs/service/impl/AbstractSQLQueryService.java View File

3
 import com.vcarecity.cvs.core.AutoMapper;
3
 import com.vcarecity.cvs.core.AutoMapper;
4
 import com.vcarecity.cvs.service.SQLQueryService;
4
 import com.vcarecity.cvs.service.SQLQueryService;
5
 import com.zaxxer.hikari.HikariDataSource;
5
 import com.zaxxer.hikari.HikariDataSource;
6
+import lombok.AllArgsConstructor;
7
+import lombok.Data;
8
+import lombok.NoArgsConstructor;
6
 import lombok.extern.slf4j.Slf4j;
9
 import lombok.extern.slf4j.Slf4j;
7
 
10
 
8
 import java.sql.*;
11
 import java.sql.*;
9
 import java.util.ArrayList;
12
 import java.util.ArrayList;
10
 import java.util.List;
13
 import java.util.List;
14
+import java.util.Set;
15
+import java.util.stream.Collectors;
16
+
17
+import static com.vcarecity.cvs.FileExporterApp.TABLE_COLUMN;
11
 
18
 
12
 /**
19
 /**
13
  * @author Kerry on 19/11/27
20
  * @author Kerry on 19/11/27
16
 @Slf4j
23
 @Slf4j
17
 public abstract class AbstractSQLQueryService implements SQLQueryService {
24
 public abstract class AbstractSQLQueryService implements SQLQueryService {
18
 
25
 
26
+    private boolean isFirst = true;
27
+
28
+
19
     protected final HikariDataSource dataSource;
29
     protected final HikariDataSource dataSource;
20
 
30
 
21
     protected AbstractSQLQueryService(HikariDataSource dataSource) {
31
     protected AbstractSQLQueryService(HikariDataSource dataSource) {
36
 
46
 
37
         ResultSet resultSet = preparedStatement.executeQuery();
47
         ResultSet resultSet = preparedStatement.executeQuery();
38
 
48
 
39
-        List<T> list = resultMapper(resultSet, clazz);
49
+        List<T> list = resultMapper(table, resultSet, clazz);
40
 
50
 
41
         logger.debug("query success. size = {}. usageTime = {} /ms", list.size(), (System.currentTimeMillis() - startTime));
51
         logger.debug("query success. size = {}. usageTime = {} /ms", list.size(), (System.currentTimeMillis() - startTime));
42
 
52
 
67
      */
77
      */
68
     protected abstract PreparedStatement getPreparedStatement(Connection connection, String sql, int start, int pageCount) throws SQLException;
78
     protected abstract PreparedStatement getPreparedStatement(Connection connection, String sql, int start, int pageCount) throws SQLException;
69
 
79
 
70
-    public <T> List<T> resultMapper(ResultSet resultSet, Class<T> clazz) throws SQLException {
80
+    public <T> List<T> resultMapper(String table, ResultSet resultSet, Class<T> clazz) throws SQLException {
71
         if (clazz == Object.class) {
81
         if (clazz == Object.class) {
72
             //noinspection unchecked
82
             //noinspection unchecked
73
-            return (List<T>) resultSetToObject(resultSet);
83
+            return (List<T>) resultSetToObject(table, resultSet);
74
         }
84
         }
75
         return autoMapper(resultSet, clazz);
85
         return autoMapper(resultSet, clazz);
76
     }
86
     }
77
 
87
 
78
-    public List<Object[]> resultSetToObject(ResultSet resultSet) throws SQLException {
88
+    public List<Object[]> resultSetToObject(String table, ResultSet resultSet) throws SQLException {
79
         final ResultSetMetaData metaData = resultSet.getMetaData();
89
         final ResultSetMetaData metaData = resultSet.getMetaData();
80
         final int columnCount = metaData.getColumnCount() - 1;
90
         final int columnCount = metaData.getColumnCount() - 1;
81
 
91
 
82
 
92
 
83
-        int skipRnIndex = -1;
84
-        int index = 0;
85
-        String[] header = new String[columnCount];
86
-        for (int i = 0; i < columnCount; i++) {
87
-            String s = metaData.getColumnName(i + 1);
88
-            if ("RN".equalsIgnoreCase(s)) {
89
-                skipRnIndex = i;
90
-            } else {
91
-                header[index++] = s;
92
-            }
93
-        }
93
+        final List<ColumnIndexName> columnWithObject = getColumnWithObject(metaData);
94
+        final Set<Integer> skipIndex = columnWithObject.stream().map(ColumnIndexName::getIndex).collect(Collectors.toSet());
94
 
95
 
95
-        logger.info("header = ({})", String.join(",", header));
96
+        final String[] header = columnWithObject.stream().map(ColumnIndexName::getName).toArray(String[]::new);
97
+
98
+
99
+        TABLE_COLUMN.put(table, header);
100
+
101
+
102
+        if (isFirst) {
103
+            final String join = String.join(",", header);
104
+            logger.info("header = ({})", join);
105
+            isFirst = false;
106
+        }
96
 
107
 
97
         List<Object[]> data = new ArrayList<>();
108
         List<Object[]> data = new ArrayList<>();
98
         while (resultSet.next()) {
109
         while (resultSet.next()) {
99
             Object[] objects = new Object[columnCount];
110
             Object[] objects = new Object[columnCount];
100
             int cIndex = 0;
111
             int cIndex = 0;
101
             for (int i = 0; i < columnCount; i++) {
112
             for (int i = 0; i < columnCount; i++) {
102
-                if (i == skipRnIndex) {
113
+                if (!skipIndex.contains(i)) {
103
                     continue;
114
                     continue;
104
                 }
115
                 }
105
                 objects[cIndex++] = resultSet.getObject(i + 1);
116
                 objects[cIndex++] = resultSet.getObject(i + 1);
109
         return data;
120
         return data;
110
     }
121
     }
111
 
122
 
123
+
124
+    @NoArgsConstructor
125
+    @AllArgsConstructor
126
+    @Data
127
+    public static class ColumnIndexName {
128
+        private int index;
129
+        private String name;
130
+    }
131
+
132
+    /**
133
+     * @param metaData
134
+     * @return
135
+     */
136
+    protected List<ColumnIndexName> getColumnWithObject(ResultSetMetaData metaData) throws SQLException {
137
+        final int columnCount = metaData.getColumnCount();
138
+        List<ColumnIndexName> res = new ArrayList<>(columnCount);
139
+        for (int i = 0; i < columnCount; i++) {
140
+            String name = metaData.getColumnName(i + 1);
141
+            res.add(new ColumnIndexName(i, name));
142
+        }
143
+        return res;
144
+    }
145
+
112
     public <T> List<T> autoMapper(ResultSet resultSet, Class<T> clazz) throws SQLException {
146
     public <T> List<T> autoMapper(ResultSet resultSet, Class<T> clazz) throws SQLException {
113
         List<T> list = new ArrayList<>();
147
         List<T> list = new ArrayList<>();
114
         while (resultSet.next()) {
148
         while (resultSet.next()) {
119
         }
153
         }
120
         return list;
154
         return list;
121
     }
155
     }
156
+
122
 }
157
 }

+ 23 - 4
src/main/java/com/vcarecity/cvs/service/impl/CSVResultHandlerServiceImpl.java View File

6
 import com.vcarecity.cvs.core.AutoMapper;
6
 import com.vcarecity.cvs.core.AutoMapper;
7
 import com.vcarecity.cvs.core.JavaMapColumn;
7
 import com.vcarecity.cvs.core.JavaMapColumn;
8
 import com.vcarecity.cvs.core.ReflectionUtil;
8
 import com.vcarecity.cvs.core.ReflectionUtil;
9
+import com.vcarecity.cvs.event.ExportEventListener;
9
 import com.vcarecity.cvs.service.ResultHandlerService;
10
 import com.vcarecity.cvs.service.ResultHandlerService;
10
 import lombok.extern.slf4j.Slf4j;
11
 import lombok.extern.slf4j.Slf4j;
11
 import org.apache.commons.csv.CSVFormat;
12
 import org.apache.commons.csv.CSVFormat;
37
     private int counter;
38
     private int counter;
38
     private int fileNameIndex = 0;
39
     private int fileNameIndex = 0;
39
 
40
 
41
+    private File lastFile;
42
+
43
+    private String table;
44
+    private String[] lastHeader;
40
 
45
 
41
     /**
46
     /**
42
      * 分割文件行数
47
      * 分割文件行数
43
      */
48
      */
44
     private static final int SPLIT_LINE_NUM = 200_0000;
49
     private static final int SPLIT_LINE_NUM = 200_0000;
45
 
50
 
51
+    private final ExportEventListener eventListener;
46
 
52
 
47
     @Inject
53
     @Inject
48
-    public CSVResultHandlerServiceImpl(@Assisted String filePattern) {
54
+    public CSVResultHandlerServiceImpl(ExportEventListener eventListener, @Assisted String filePattern) {
55
+        this.eventListener = eventListener;
49
         this.filePattern = filePattern;
56
         this.filePattern = filePattern;
50
         this.csvFormat = CSVFormat.MYSQL;
57
         this.csvFormat = CSVFormat.MYSQL;
51
         this.counter = 0;
58
         this.counter = 0;
54
     private File getFile() {
61
     private File getFile() {
55
         final int index = fileNameIndex;
62
         final int index = fileNameIndex;
56
         fileNameIndex++;
63
         fileNameIndex++;
57
-        return new File(filePattern + "-" + +index + ".csv");
64
+
65
+        lastFile = new File(filePattern + "-" + +index + ".csv");
66
+        // call back
67
+        eventListener.beforeExport(lastFile.getAbsolutePath());
68
+
69
+        return lastFile;
58
     }
70
     }
59
 
71
 
60
 
72
 
62
         synchronized (this) {
74
         synchronized (this) {
63
             if (counter % SPLIT_LINE_NUM == 0) {
75
             if (counter % SPLIT_LINE_NUM == 0) {
64
                 try {
76
                 try {
77
+                    if (lastFile != null) {
78
+                        eventListener.exportSuccess(this.lastFile.getAbsolutePath(), table, lastHeader);
79
+                    }
65
                     if (bufferedWriter != null) {
80
                     if (bufferedWriter != null) {
66
                         bufferedWriter.close();
81
                         bufferedWriter.close();
67
                     }
82
                     }
72
                     writer = new CSVPrinter(bufferedWriter, csvFormat);
87
                     writer = new CSVPrinter(bufferedWriter, csvFormat);
73
                 } catch (IOException e) {
88
                 } catch (IOException e) {
74
                     e.printStackTrace();
89
                     e.printStackTrace();
90
+                    eventListener.exceptionCatch(e);
75
                 }
91
                 }
76
             }
92
             }
77
         }
93
         }
78
     }
94
     }
79
 
95
 
80
     @Override
96
     @Override
81
-    public <T> void resultHandler(List<T> dataList) throws Exception {
97
+    public <T> void resultHandler(String table, String[] header, List<T> dataList) throws Exception {
98
+        this.table = table;
99
+        this.lastHeader = header;
82
         checkFile();
100
         checkFile();
83
 
101
 
84
         logger.debug("start write to csv file size = {}", dataList.size());
102
         logger.debug("start write to csv file size = {}", dataList.size());
85
 
103
 
86
         long startTime = System.currentTimeMillis();
104
         long startTime = System.currentTimeMillis();
87
 
105
 
88
-
89
         Class<?> cls = Object.class;
106
         Class<?> cls = Object.class;
90
 
107
 
91
         for (T t : dataList) {
108
         for (T t : dataList) {
125
     }
142
     }
126
 
143
 
127
     public void close() throws IOException {
144
     public void close() throws IOException {
145
+        eventListener.exportSuccess(this.lastFile.getAbsolutePath(), table, this.lastHeader);
128
         bufferedWriter.close();
146
         bufferedWriter.close();
129
         writer.close();
147
         writer.close();
130
     }
148
     }
192
         return localTime.format(TIME_FORMATTER);
210
         return localTime.format(TIME_FORMATTER);
193
     }
211
     }
194
 
212
 
213
+
195
 }
214
 }

+ 5 - 2
src/main/java/com/vcarecity/cvs/service/impl/MySQLResultHandlerServiceImpl.java View File

2
 
2
 
3
 import com.google.inject.Inject;
3
 import com.google.inject.Inject;
4
 import com.google.inject.assistedinject.Assisted;
4
 import com.google.inject.assistedinject.Assisted;
5
+import com.vcarecity.cvs.event.ExportEventListener;
5
 import com.vcarecity.cvs.service.ResultHandlerService;
6
 import com.vcarecity.cvs.service.ResultHandlerService;
6
 import com.zaxxer.hikari.HikariDataSource;
7
 import com.zaxxer.hikari.HikariDataSource;
7
 import lombok.extern.slf4j.Slf4j;
8
 import lombok.extern.slf4j.Slf4j;
19
 public class MySQLResultHandlerServiceImpl implements ResultHandlerService {
20
 public class MySQLResultHandlerServiceImpl implements ResultHandlerService {
20
 
21
 
21
     private final HikariDataSource dataSource;
22
     private final HikariDataSource dataSource;
23
+    private final ExportEventListener eventListener;
22
     private final String sql;
24
     private final String sql;
23
 
25
 
24
     @Inject
26
     @Inject
25
-    public MySQLResultHandlerServiceImpl(HikariDataSource dataSource, @Assisted String sql) {
27
+    public MySQLResultHandlerServiceImpl(HikariDataSource dataSource, ExportEventListener eventListener, @Assisted String sql) {
26
         this.dataSource = dataSource;
28
         this.dataSource = dataSource;
29
+        this.eventListener = eventListener;
27
         this.sql = sql;
30
         this.sql = sql;
28
     }
31
     }
29
 
32
 
30
 
33
 
31
     @Override
34
     @Override
32
-    public <T> void resultHandler(List<T> dataList) throws Exception {
35
+    public <T> void resultHandler(String table, String[] header, List<T> dataList) throws Exception {
33
         logger.debug("start write to mysql size = {}, on = {}", dataList.size(), LocalDateTime.now());
36
         logger.debug("start write to mysql size = {}, on = {}", dataList.size(), LocalDateTime.now());
34
         long startTime = System.currentTimeMillis();
37
         long startTime = System.currentTimeMillis();
35
         final Connection connection = dataSource.getConnection();
38
         final Connection connection = dataSource.getConnection();

+ 17 - 0
src/main/java/com/vcarecity/cvs/service/impl/OracleQueryServiceImpl.java View File

6
 
6
 
7
 import java.sql.Connection;
7
 import java.sql.Connection;
8
 import java.sql.PreparedStatement;
8
 import java.sql.PreparedStatement;
9
+import java.sql.ResultSetMetaData;
9
 import java.sql.SQLException;
10
 import java.sql.SQLException;
11
+import java.util.ArrayList;
12
+import java.util.List;
10
 
13
 
11
 /**
14
 /**
12
  * @author Kerry on 19/11/25
15
  * @author Kerry on 19/11/25
37
         preparedStatement.setInt(2, (page - 1) * pageCount);
40
         preparedStatement.setInt(2, (page - 1) * pageCount);
38
         return preparedStatement;
41
         return preparedStatement;
39
     }
42
     }
43
+
44
+    @Override
45
+    protected List<ColumnIndexName> getColumnWithObject(ResultSetMetaData metaData) throws SQLException {
46
+        final int columnCount = metaData.getColumnCount();
47
+        List<ColumnIndexName> res = new ArrayList<>(columnCount);
48
+        for (int i = 0; i < columnCount; i++) {
49
+            String name = metaData.getColumnName(i + 1);
50
+            if ("RN".equalsIgnoreCase(name)) {
51
+                continue;
52
+            }
53
+            res.add(new ColumnIndexName(i, name));
54
+        }
55
+        return res;
56
+    }
40
 }
57
 }

+ 81 - 0
src/main/java/com/vcarecity/cvs/shell/MySQLImporter.java View File

1
+package com.vcarecity.cvs.shell;
2
+
3
+import com.vcarecity.cvs.properties.DbProperties;
4
+import lombok.extern.slf4j.Slf4j;
5
+
6
+import java.io.File;
7
+import java.sql.Connection;
8
+import java.sql.DriverManager;
9
+import java.sql.PreparedStatement;
10
+import java.sql.SQLException;
11
+
12
+/**
13
+ * @author Kerry on 19/11/29
14
+ */
15
+
16
+@Slf4j
17
+public class MySQLImporter implements Runnable {
18
+
19
+    private final DbProperties dbProperties;
20
+
21
+    private final String filepath;
22
+    private final String table;
23
+    private final String[] header;
24
+
25
+    private static final String LOAD_DATA_SQL_TEP = "LOAD DATA INFILE '%s' " +
26
+            "INTO TABLE %s " +
27
+            "FIELDS " +
28
+            "TERMINATED BY '\\t' " +
29
+            "ENCLOSED BY '\\\"' " +
30
+            "ESCAPED BY '\\\\' " +
31
+            "LINES TERMINATED BY '\\n' (%s)";
32
+
33
+    public MySQLImporter(DbProperties dbProperties, String filepath, String table, String[] header) {
34
+        this.dbProperties = dbProperties;
35
+        this.filepath = filepath;
36
+        this.table = table;
37
+        this.header = header;
38
+    }
39
+
40
+    @Override
41
+    public void run() {
42
+        File file = new File(filepath);
43
+        if (!file.exists()) {
44
+            return;
45
+        }
46
+
47
+        final String sql = String.format(LOAD_DATA_SQL_TEP, filepath, table, String.join(",", this.header));
48
+
49
+        logger.info("sql = {}", sql);
50
+        try {
51
+            importData(sql);
52
+        } catch (SQLException e) {
53
+            e.printStackTrace();
54
+        }
55
+    }
56
+
57
+    private void execShell(String sql) {
58
+        //Runtime.getRuntime().exec()
59
+    }
60
+
61
+
62
+    private void importFromLocal(String sql) {
63
+        //if (statement.isWrapperFor(JdbcStatement.class)) {
64
+        //    final JdbcStatement unwrap = statement.unwrap(JdbcStatement.class);
65
+        //    unwrap.setLocalInfileInputStream();
66
+        //}
67
+    }
68
+
69
+
70
+    private void importData(String sql) throws SQLException {
71
+        try (final Connection connection = getConnection();
72
+             final PreparedStatement statement = connection.prepareStatement(sql)) {
73
+            statement.executeUpdate();
74
+        }
75
+    }
76
+
77
+    private Connection getConnection() throws SQLException {
78
+        return DriverManager.getConnection(dbProperties.getUrl(), dbProperties.getUser(), dbProperties.getPassword());
79
+    }
80
+
81
+}

+ 5 - 1
src/main/java/com/vcarecity/cvs/starter/SQLStarter.java View File

9
 import javax.inject.Inject;
9
 import javax.inject.Inject;
10
 import java.util.List;
10
 import java.util.List;
11
 
11
 
12
+import static com.vcarecity.cvs.FileExporterApp.TABLE_COLUMN;
13
+
12
 /**
14
 /**
13
  * @author Kerry on 19/11/20
15
  * @author Kerry on 19/11/20
14
  */
16
  */
47
             //noinspection unchecked
49
             //noinspection unchecked
48
             cls = (Class<T>) Object.class;
50
             cls = (Class<T>) Object.class;
49
         }
51
         }
52
+
50
         ResultHandlerService resultHandler = resultHandlerFactory.createResultHandler(properties);
53
         ResultHandlerService resultHandler = resultHandlerFactory.createResultHandler(properties);
51
 
54
 
52
 
55
 
59
 
62
 
60
         do {
63
         do {
61
             List<T> result = queryService.queryByPage(table, page, this.pageCount, cls);
64
             List<T> result = queryService.queryByPage(table, page, this.pageCount, cls);
62
-            resultHandler.resultHandler(result);
65
+            final String[] headers = TABLE_COLUMN.get(table);
66
+            resultHandler.resultHandler(table, headers, result);
63
             currentSize = result.size();
67
             currentSize = result.size();
64
 
68
 
65
             page++;
69
             page++;

+ 1 - 1
src/main/resources/logback-test.xml View File

27
         <appender-ref ref="FILE_APPENDER"/>
27
         <appender-ref ref="FILE_APPENDER"/>
28
     </appender>
28
     </appender>
29
 
29
 
30
-    <logger name="com.vcarecity" level="DEBUG" additivity="false">
30
+    <logger name="com.vcarecity" level="INFO" additivity="false">
31
         <appender-ref ref="STDOUT"/>
31
         <appender-ref ref="STDOUT"/>
32
     </logger>
32
     </logger>
33
 
33