From cf211a6766859f551bec20017617f67e2a3f6336 Mon Sep 17 00:00:00 2001 From: "zhy6599@163.com" Date: Sun, 1 Dec 2019 22:30:19 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E9=93=BE=E6=8E=A5=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/mnt/rest/DatabaseController.java | 9 + .../modules/mnt/service/DatabaseService.java | 7 + .../mnt/service/impl/DatabaseServiceImpl.java | 14 ++ .../modules/mnt/util/DataTypeEnum.java | 123 +++++++++++++ .../zhengjie/modules/mnt/util/SqlUtils.java | 163 ++++++++++++++++++ sql/eladmin.sql | 2 + 6 files changed, 318 insertions(+) create mode 100644 eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java create mode 100644 eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java index eb22d0c7..0148ec9e 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java @@ -61,4 +61,13 @@ public class DatabaseController { databaseService.delete(id); return new ResponseEntity(HttpStatus.OK); } + + @Log("测试数据库链接") + @ApiOperation(value = "测试数据库链接") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('database:testConnect')") + public ResponseEntity testConnect(@Validated @RequestBody Database resources){ + return new ResponseEntity<>(databaseService.testConnection(resources),HttpStatus.CREATED); + } + } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java index 9e2e7b18..aaa77a69 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/DatabaseService.java @@ -51,4 +51,11 @@ public interface DatabaseService { * @param id / */ void delete(String id); + + /** + * 测试连接数据库 + * @param resources + * @return + */ + boolean testConnection(Database resources); } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java index aa9e3cf7..ab1819d9 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/service/impl/DatabaseServiceImpl.java @@ -1,12 +1,14 @@ package me.zhengjie.modules.mnt.service.impl; import cn.hutool.core.util.IdUtil; +import lombok.extern.slf4j.Slf4j; import me.zhengjie.modules.mnt.domain.Database; import me.zhengjie.modules.mnt.repository.DatabaseRepository; import me.zhengjie.modules.mnt.service.DatabaseService; import me.zhengjie.modules.mnt.service.dto.DatabaseDto; import me.zhengjie.modules.mnt.service.dto.DatabaseQueryCriteria; import me.zhengjie.modules.mnt.service.mapper.DatabaseMapper; +import me.zhengjie.modules.mnt.util.SqlUtils; import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.QueryHelp; import me.zhengjie.utils.ValidationUtil; @@ -21,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional; * @date 2019-08-24 */ @Service +@Slf4j @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class DatabaseServiceImpl implements DatabaseService { @@ -72,4 +75,15 @@ public class DatabaseServiceImpl implements DatabaseService { public void delete(String id) { databaseRepository.deleteById(id); } + + @Override + public boolean testConnection(Database resources) { + try { + return SqlUtils.testConnection(resources.getJdbcUrl(), resources.getUserName(), resources.getPwd()); + } catch (Exception e) { + log.error(e.getMessage()); + return false; + } + + } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java new file mode 100644 index 00000000..e6d4ef46 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/DataTypeEnum.java @@ -0,0 +1,123 @@ +/* + * << + * Davinci + * == + * Copyright (C) 2016 - 2019 EDP + * == + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * >> + * + */ + +package me.zhengjie.modules.mnt.util; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public enum DataTypeEnum { + + MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"), + + ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""), + + SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""), + + H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""), + + PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""), + + MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""), + + ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"), + + PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""), + + MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"), + + CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"), + + CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""), + + KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""), + + VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"), + + HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"), + + IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'"); + + + private String feature; + private String desc; + private String driver; + private String keywordPrefix; + private String keywordSuffix; + private String aliasPrefix; + private String aliasSuffix; + + private static final String jdbcUrlPrefix = "jdbc:"; + + DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) { + this.feature = feature; + this.desc = desc; + this.driver = driver; + this.keywordPrefix = keywordPrefix; + this.keywordSuffix = keywordSuffix; + this.aliasPrefix = aliasPrefix; + this.aliasSuffix = aliasSuffix; + } + + public static DataTypeEnum urlOf(String jdbcUrl) { + String url = jdbcUrl.toLowerCase().trim(); + for (DataTypeEnum dataTypeEnum : values()) { + if (url.startsWith(jdbcUrlPrefix + dataTypeEnum.feature)) { + try { + Class aClass = Class.forName(dataTypeEnum.getDriver()); + if (null == aClass) { + throw new RuntimeException("Unable to get driver instance for jdbcUrl: " + jdbcUrl); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unable to get driver instance: " + jdbcUrl); + } + return dataTypeEnum; + } + } + return null; + } + + public String getFeature() { + return feature; + } + + public String getDesc() { + return desc; + } + + public String getDriver() { + return driver; + } + + public String getKeywordPrefix() { + return keywordPrefix; + } + + public String getKeywordSuffix() { + return keywordSuffix; + } + + public String getAliasPrefix() { + return aliasPrefix; + } + + public String getAliasSuffix() { + return aliasSuffix; + } +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java new file mode 100644 index 00000000..6e59f8c8 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java @@ -0,0 +1,163 @@ +package me.zhengjie.modules.mnt.util; + +import cn.hutool.crypto.SecureUtil; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class SqlUtils { + + public static final String COLON = ":"; + + private static volatile Map map = new HashMap<>(); + + private static String getKey(String jdbcUrl, String username, String password) { + StringBuilder sb = new StringBuilder(); + if (!StringUtils.isEmpty(username)) { + sb.append(username); + } + if (!StringUtils.isEmpty(password)) { + sb.append(COLON).append(password); + } + sb.append(COLON).append(jdbcUrl.trim()); + + return SecureUtil.md5(sb.toString()); + } + + /** + * 获取数据源 + * + * @param jdbcUrl + * @param userName + * @param password + * @return + */ + private static DataSource getDataSource(String jdbcUrl, String userName, String password) { + String key = getKey(jdbcUrl, userName, password); + if (!map.containsKey(key) || null == map.get(key)) { + DruidDataSource druidDataSource = new DruidDataSource(); + + String className = null; + try { + className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName(); + } catch (SQLException e) { + throw new RuntimeException("Get class name error: =" + jdbcUrl); + } + if (StringUtils.isEmpty(className)) { + DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl); + if (null == dataTypeEnum ) { + throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl); + } + druidDataSource.setDriverClassName(dataTypeEnum.getDriver()); + } else { + druidDataSource.setDriverClassName(className); + } + + + druidDataSource.setUrl(jdbcUrl); + druidDataSource.setUsername(userName); + druidDataSource.setPassword(password); + // 配置获取连接等待超时的时间 + druidDataSource.setMaxWait(3000); + // 配置初始化大小、最小、最大 + druidDataSource.setInitialSize(1); + druidDataSource.setMinIdle(1); + druidDataSource.setMaxActive(1); + + // 配置间隔多久才进行一次检测需要关闭的空闲连接,单位是毫秒 + druidDataSource.setTimeBetweenEvictionRunsMillis(50000); + // 配置一旦重试多次失败后等待多久再继续重试连接,单位是毫秒 + druidDataSource.setTimeBetweenConnectErrorMillis(18000); + // 配置一个连接在池中最小生存的时间,单位是毫秒 + druidDataSource.setMinEvictableIdleTimeMillis(300000); + // 这个特性能解决 MySQL 服务器8小时关闭连接的问题 + druidDataSource.setMaxEvictableIdleTimeMillis(25200000); + + try { + druidDataSource.init(); + } catch (SQLException e) { + log.error("Exception during pool initialization", e); + throw new RuntimeException(e.getMessage()); + } + map.put(key, druidDataSource); + } + return map.get(key); + } + + private static Connection getConnection(String jdbcUrl, String userName, String password) { + DataSource dataSource = getDataSource(jdbcUrl, userName, password); + Connection connection = null; + try { + connection = dataSource.getConnection(); + } catch (Exception e) { + connection = null; + } + try { + if (null == connection || connection.isClosed() || !connection.isValid(5)) { + log.info("connection is closed or invalid, retry get connection!"); + connection = dataSource.getConnection(); + } + } catch (Exception e) { + log.error("create connection error, jdbcUrl: {}", jdbcUrl); + throw new RuntimeException("create connection error, jdbcUrl: " + jdbcUrl); + } + return connection; + } + + private static void releaseConnection(Connection connection) { + if (null != connection) { + try { + connection.close(); + connection = null; + } catch (Exception e) { + e.printStackTrace(); + log.error("connection close error", e.getMessage()); + } + } + } + + + public static void closeResult(ResultSet rs) { + if (rs != null) { + try { + rs.close(); + rs = null; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static boolean testConnection(String jdbcUrl, String userName, String password) { + Connection connection = null; + try { + connection = getConnection(jdbcUrl, userName, password); + if (null != connection) { + return true; + } + }catch (Exception e){ + log.info("Get connection failed:",e.getMessage()); + }finally { + releaseConnection(connection); + } + return false; + } + + public JdbcTemplate jdbcTemplate(String jdbcUrl, String userName, String password) { + DataSource dataSource = getDataSource(jdbcUrl, userName, password); + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + jdbcTemplate.setFetchSize(1000); + return jdbcTemplate; + } + +} diff --git a/sql/eladmin.sql b/sql/eladmin.sql index 4df5cc02..bc7b8ca6 100644 --- a/sql/eladmin.sql +++ b/sql/eladmin.sql @@ -368,6 +368,8 @@ CREATE TABLE `mnt_database` ( PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +INSERT INTO `mnt_database` VALUES ('604dd98ae8b44b128544c2135628f87d', '本机', 'jdbc:log4jdbc:mysql://localhost:3306/eladmin?serverTimezone=UTC', 'root', '123456'); + -- ---------------------------- -- Table structure for mnt_deploy -- ---------------------------- From 6d16bcda3b871a9e0c0f92591ccfef0e125e532e Mon Sep 17 00:00:00 2001 From: zhanghouying Date: Mon, 9 Dec 2019 14:53:26 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=89=A7=E8=A1=8CSQL?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/mnt/rest/DatabaseController.java | 29 ++++++ .../zhengjie/modules/mnt/util/SqlUtils.java | 90 +++++++++++++++---- 2 files changed, 104 insertions(+), 15 deletions(-) diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java index 0148ec9e..d99bade0 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/rest/DatabaseController.java @@ -3,15 +3,23 @@ package me.zhengjie.modules.mnt.rest; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import me.zhengjie.aop.log.Log; +import me.zhengjie.exception.BadRequestException; import me.zhengjie.modules.mnt.domain.Database; import me.zhengjie.modules.mnt.service.DatabaseService; +import me.zhengjie.modules.mnt.service.dto.DatabaseDto; import me.zhengjie.modules.mnt.service.dto.DatabaseQueryCriteria; +import me.zhengjie.modules.mnt.util.SqlUtils; +import me.zhengjie.utils.FileUtil; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; /** * @author zhanghouying @@ -22,6 +30,8 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/api/database") public class DatabaseController { + private String fileSavePath = System.getProperty("java.io.tmpdir"); + private final DatabaseService databaseService; public DatabaseController(DatabaseService databaseService) { @@ -70,4 +80,23 @@ public class DatabaseController { return new ResponseEntity<>(databaseService.testConnection(resources),HttpStatus.CREATED); } + @Log("执行SQL脚本") + @ApiOperation(value = "执行SQL脚本") + @PostMapping(value = "/upload") + @PreAuthorize("@el.check('database:add')") + public ResponseEntity upload(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{ + String id = request.getParameter("id"); + DatabaseDto database = databaseService.findById(id); + String fileName = ""; + if(database != null){ + fileName = file.getOriginalFilename(); + File executeFile = new File(fileSavePath+fileName); + FileUtil.del(executeFile); + file.transferTo(executeFile); + String result = SqlUtils.executeFile(database.getJdbcUrl(), database.getUserName(), database.getPwd(), executeFile); + return new ResponseEntity<>(result,HttpStatus.OK); + }else{ + throw new BadRequestException("Database not exist"); + } + } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java index 6e59f8c8..9920dc87 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mnt/util/SqlUtils.java @@ -3,15 +3,14 @@ package me.zhengjie.modules.mnt.util; import cn.hutool.crypto.SecureUtil; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.util.StringUtils; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; -import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.io.*; +import java.sql.*; import java.util.HashMap; +import java.util.List; import java.util.Map; @Slf4j @@ -55,7 +54,7 @@ public class SqlUtils { } if (StringUtils.isEmpty(className)) { DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl); - if (null == dataTypeEnum ) { + if (null == dataTypeEnum) { throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl); } druidDataSource.setDriverClassName(dataTypeEnum.getDriver()); @@ -141,23 +140,84 @@ public class SqlUtils { public static boolean testConnection(String jdbcUrl, String userName, String password) { Connection connection = null; try { - connection = getConnection(jdbcUrl, userName, password); + connection = getConnection(jdbcUrl, userName, password); if (null != connection) { return true; } - }catch (Exception e){ - log.info("Get connection failed:",e.getMessage()); - }finally { + } catch (Exception e) { + log.info("Get connection failed:", e.getMessage()); + } finally { releaseConnection(connection); } return false; } - public JdbcTemplate jdbcTemplate(String jdbcUrl, String userName, String password) { - DataSource dataSource = getDataSource(jdbcUrl, userName, password); - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); - jdbcTemplate.setFetchSize(1000); - return jdbcTemplate; + public static String executeFile(String jdbcUrl, String userName, String password, File sqlFile) { + Connection connection = getConnection(jdbcUrl, userName, password); + try { + batchExecute(connection, readSqlList( sqlFile)); + } catch (Exception e) { + log.error("sql脚本执行发生异常:{}",e.getMessage()); + return e.getMessage(); + }finally { + releaseConnection(connection); + } + return "success"; + } + + + /** + * 批量执行sql + * @param connection + * @param sqlList + * @return + */ + public static void batchExecute(Connection connection, List sqlList) throws SQLException { + Statement st = connection.createStatement(); + for (String sql : sqlList) { + if (sql.endsWith(";")) { + sql = sql.substring(0, sql.length() - 1); + } + st.addBatch(sql); + } + st.executeBatch(); + } + + /** + * 将文件中的sql语句以;为单位读取到列表中 + * @param sqlFile + * @return + * @throws Exception + */ + private static List readSqlList(File sqlFile) throws Exception { + List sqlList = Lists.newArrayList(); + StringBuilder sb = new StringBuilder(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader( + new FileInputStream(sqlFile), "UTF-8")); + String tmp = null; + while ((tmp = reader.readLine()) != null) { + log.info("line:{}", tmp); + if (tmp.endsWith(";")) { + sb.append(tmp); + sqlList.add(sb.toString()); + sb.delete(0, sb.length()); + } else { + sb.append(tmp); + } + } + if (!"".endsWith(sb.toString().trim())) { + sqlList.add(sb.toString()); + } + } finally { + try { + reader.close(); + } catch (IOException e1) { + } + } + + return sqlList; } }