diff --git a/api/src/main/java/com/databasir/api/ProjectController.java b/api/src/main/java/com/databasir/api/ProjectController.java index 7587b84..f8fe747 100644 --- a/api/src/main/java/com/databasir/api/ProjectController.java +++ b/api/src/main/java/com/databasir/api/ProjectController.java @@ -55,4 +55,10 @@ public class ProjectController { ProjectListCondition condition) { return JsonData.ok(projectService.list(page, condition)); } + + @PostMapping(Routes.GroupProject.TEST_CONNECTION) + public JsonData testConnection(@RequestBody @Valid ProjectTestConnectionRequest request) { + projectService.testConnection(request); + return JsonData.ok(); + } } diff --git a/api/src/main/java/com/databasir/api/Routes.java b/api/src/main/java/com/databasir/api/Routes.java index 409551d..b30a546 100644 --- a/api/src/main/java/com/databasir/api/Routes.java +++ b/api/src/main/java/com/databasir/api/Routes.java @@ -57,6 +57,8 @@ public interface Routes { String UPDATE = BASE + "/groups/{groupId}/projects"; String DELETE = BASE + "/groups/{groupId}/projects/{projectId}"; + + String TEST_CONNECTION = BASE + "/projects/test_connection"; } interface Document { diff --git a/api/src/main/resources/application-local.properties b/api/src/main/resources/application-local.properties index 8030a11..b3da7a4 100644 --- a/api/src/main/resources/application-local.properties +++ b/api/src/main/resources/application-local.properties @@ -1,5 +1,5 @@ server.port=8080 -logging.level.org.jooq=DEBUG +logging.level.org.jooq=INFO spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=123456 diff --git a/common/src/main/java/com/databasir/common/DatabasirException.java b/common/src/main/java/com/databasir/common/DatabasirException.java index 563fb90..4ea5287 100644 --- a/common/src/main/java/com/databasir/common/DatabasirException.java +++ b/common/src/main/java/com/databasir/common/DatabasirException.java @@ -46,4 +46,11 @@ public class DatabasirException extends RuntimeException { this.errCode = errorCodeMessage.getErrCode(); this.errMessage = errorCodeMessage.getErrMessage(); } + + public DatabasirException(DatabasirErrors errorCodeMessage, String overrideMessage, Throwable cause) { + super(overrideMessage, cause); + this.errorCodeMessage = errorCodeMessage; + this.errCode = errorCodeMessage.getErrCode(); + this.errMessage = overrideMessage; + } } diff --git a/core/src/main/java/com/databasir/core/domain/DomainErrors.java b/core/src/main/java/com/databasir/core/domain/DomainErrors.java index 18b4483..115f1bd 100644 --- a/core/src/main/java/com/databasir/core/domain/DomainErrors.java +++ b/core/src/main/java/com/databasir/core/domain/DomainErrors.java @@ -35,4 +35,8 @@ public enum DomainErrors implements DatabasirErrors { public DatabasirException exception(Throwable origin) { return new DatabasirException(this, origin); } + + public DatabasirException exception(String message, Throwable origin) { + return new DatabasirException(this, message, origin); + } } diff --git a/core/src/main/java/com/databasir/core/domain/project/data/ProjectTestConnectionRequest.java b/core/src/main/java/com/databasir/core/domain/project/data/ProjectTestConnectionRequest.java new file mode 100644 index 0000000..81030ac --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/project/data/ProjectTestConnectionRequest.java @@ -0,0 +1,29 @@ +package com.databasir.core.domain.project.data; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.util.ArrayList; +import java.util.List; + +@Data +public class ProjectTestConnectionRequest { + + private Integer projectId; + + @NotBlank + private String username; + + private String password; + + @NotBlank + private String url; + + @NotBlank + private String databaseName; + + @NotBlank + private String databaseType; + + private List properties = new ArrayList<>(); +} diff --git a/core/src/main/java/com/databasir/core/domain/project/service/ProjectService.java b/core/src/main/java/com/databasir/core/domain/project/service/ProjectService.java index e1f8adf..f6a7228 100644 --- a/core/src/main/java/com/databasir/core/domain/project/service/ProjectService.java +++ b/core/src/main/java/com/databasir/core/domain/project/service/ProjectService.java @@ -6,6 +6,7 @@ import com.databasir.core.domain.project.converter.DataSourcePojoConverter; import com.databasir.core.domain.project.converter.ProjectPojoConverter; import com.databasir.core.domain.project.converter.ProjectResponseConverter; import com.databasir.core.domain.project.data.*; +import com.databasir.core.infrastructure.connection.DatabaseConnectionService; import com.databasir.dao.impl.*; import com.databasir.dao.tables.pojos.*; import lombok.RequiredArgsConstructor; @@ -19,6 +20,7 @@ import org.springframework.util.StringUtils; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Properties; import java.util.function.Function; import java.util.stream.Collectors; @@ -42,6 +44,8 @@ public class ProjectService { private final ProjectResponseConverter projectResponseConverter; + private final DatabaseConnectionService databaseConnectionService; + public ProjectDetailResponse getOne(Integer id) { return projectDao.selectOptionalById(id) .map(schemaSource -> { @@ -142,4 +146,25 @@ public class ProjectService { }); } + public void testConnection(ProjectTestConnectionRequest request) { + String password; + if (request.getProjectId() != null && !StringUtils.hasText(request.getPassword())) { + DataSourcePojo dataSource = dataSourceDao.selectByProjectId(request.getProjectId()); + SysKeyPojo sysKey = sysKeyDao.selectTopOne(); + password = Aes.decryptFromBase64Data(dataSource.getPassword(), sysKey.getAesKey()); + } else if (StringUtils.hasText(request.getPassword())) { + password = request.getPassword(); + } else { + throw DomainErrors.PASSWORD_MUST_NOT_BE_BLANK.exception(); + } + Properties properties = new Properties(); + request.getProperties().forEach(prop -> properties.put(prop.getKey(), prop.getValue())); + databaseConnectionService.testConnection(request.getUsername(), + password, + request.getUrl(), + request.getDatabaseName(), + request.getDatabaseType(), + properties); + } + } diff --git a/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionFactory.java b/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionFactory.java index 472c746..6676a5a 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionFactory.java +++ b/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionFactory.java @@ -1,6 +1,7 @@ package com.databasir.core.infrastructure.connection; import java.sql.Connection; +import java.sql.SQLException; import java.util.Properties; public interface DatabaseConnectionFactory { @@ -11,5 +12,5 @@ public interface DatabaseConnectionFactory { String password, String url, String schema, - Properties properties); + Properties properties) throws SQLException; } diff --git a/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionService.java b/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionService.java index 2d5b6fb..cb21e96 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionService.java +++ b/core/src/main/java/com/databasir/core/infrastructure/connection/DatabaseConnectionService.java @@ -10,6 +10,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.sql.Connection; +import java.sql.SQLException; import java.util.List; import java.util.Properties; @@ -30,10 +31,31 @@ public class DatabaseConnectionService { Properties info = new Properties(); dataSourceProperties.forEach(prop -> info.put(prop.getKey(), prop.getValue())); - return factories.stream() - .filter(factory -> factory.support(dataSource.getDatabaseType())) - .findFirst() - .orElseThrow(DomainErrors.NOT_SUPPORT_DATABASE_TYPE::exception) - .getConnection(username, password, url, dataSource.getDatabaseName(), info); + try { + return factories.stream() + .filter(factory -> factory.support(dataSource.getDatabaseType())) + .findFirst() + .orElseThrow(DomainErrors.NOT_SUPPORT_DATABASE_TYPE::exception) + .getConnection(username, password, url, dataSource.getDatabaseName(), info); + } catch (SQLException e) { + throw DomainErrors.CONNECT_DATABASE_FAILED.exception(e.getMessage(), e); + } + } + + public void testConnection(String username, + String password, + String url, + String databaseName, + String databaseType, + Properties properties) { + try { + factories.stream() + .filter(factory -> factory.support(databaseType)) + .findFirst() + .orElseThrow(DomainErrors.NOT_SUPPORT_DATABASE_TYPE::exception) + .getConnection(username, password, url, databaseName, properties); + } catch (SQLException e) { + throw DomainErrors.CONNECT_DATABASE_FAILED.exception(e.getMessage(), e); + } } } diff --git a/core/src/main/java/com/databasir/core/infrastructure/connection/MysqlDatabaseConnectionFactory.java b/core/src/main/java/com/databasir/core/infrastructure/connection/MysqlDatabaseConnectionFactory.java index cf59091..6e8e2d7 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/connection/MysqlDatabaseConnectionFactory.java +++ b/core/src/main/java/com/databasir/core/infrastructure/connection/MysqlDatabaseConnectionFactory.java @@ -1,6 +1,5 @@ package com.databasir.core.infrastructure.connection; -import com.databasir.core.domain.DomainErrors; import org.springframework.stereotype.Component; import java.sql.Connection; @@ -17,7 +16,11 @@ public class MysqlDatabaseConnectionFactory implements DatabaseConnectionFactory } @Override - public Connection getConnection(String username, String password, String url, String schema, Properties properties) { + public Connection getConnection(String username, + String password, + String url, + String schema, + Properties properties) throws SQLException { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { @@ -29,11 +32,7 @@ public class MysqlDatabaseConnectionFactory implements DatabaseConnectionFactory info.put("password", password); info.putAll(properties); String jdbcUrl = "jdbc:mysql://" + url + "/" + schema; - try { - return DriverManager.getConnection(jdbcUrl, info); - } catch (SQLException e) { - throw DomainErrors.CONNECT_DATABASE_FAILED.exception(e); - } + return DriverManager.getConnection(jdbcUrl, info); } } diff --git a/core/src/main/java/com/databasir/core/infrastructure/connection/PostgresqlDatabaseConnectionFactory.java b/core/src/main/java/com/databasir/core/infrastructure/connection/PostgresqlDatabaseConnectionFactory.java index c2166e7..ea7bd16 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/connection/PostgresqlDatabaseConnectionFactory.java +++ b/core/src/main/java/com/databasir/core/infrastructure/connection/PostgresqlDatabaseConnectionFactory.java @@ -1,7 +1,6 @@ package com.databasir.core.infrastructure.connection; -import com.databasir.core.domain.DomainErrors; import org.springframework.stereotype.Component; import java.sql.Connection; @@ -18,7 +17,11 @@ public class PostgresqlDatabaseConnectionFactory implements DatabaseConnectionFa } @Override - public Connection getConnection(String username, String password, String url, String schema, Properties properties) { + public Connection getConnection(String username, + String password, + String url, + String schema, + Properties properties) throws SQLException { try { Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException e) { @@ -30,10 +33,6 @@ public class PostgresqlDatabaseConnectionFactory implements DatabaseConnectionFa info.put("password", password); info.putAll(properties); String jdbcUrl = "jdbc:postgresql://" + url + "/" + schema; - try { - return DriverManager.getConnection(jdbcUrl, info); - } catch (SQLException e) { - throw DomainErrors.CONNECT_DATABASE_FAILED.exception(e); - } + return DriverManager.getConnection(jdbcUrl, info); } }