From 53961b00aca1162c424aba13fc5fca6cb8114181 Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Thu, 8 Dec 2022 17:15:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=8C=E5=AF=B9=E6=AF=94=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/flyfish/fluent/chain/SQLImpl.java | 6 +- .../fluent/debug/FluentSqlDebugger.java | 17 ++++ fluent-sql-spring-jdbc/pom.xml | 26 +++++ .../flyfish/framework/FluentJdbcTest.java | 43 +++----- .../group/flyfish/framework/TestCase.java | 38 +++++++ .../framework/cases/AbstractTestCase.java | 62 ++++++++++++ .../framework/cases/FluentSqlTestCase.java | 61 ++++++++++++ .../flyfish/framework/cases/JdbcTestCase.java | 99 +++++++++++++++++++ .../framework/cases/MybatisTestCase.java | 62 ++++++++++++ .../framework/mapper/TenantContextMapper.java | 23 +++++ .../framework/mapper/TenantContextMapper.xml | 36 +++++++ .../flyfish/framework/utils/LogUtils.java | 25 +++++ pom.xml | 10 ++ 13 files changed, 474 insertions(+), 34 deletions(-) create mode 100644 fluent-sql-core/src/main/java/group/flyfish/fluent/debug/FluentSqlDebugger.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/TestCase.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/AbstractTestCase.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/FluentSqlTestCase.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/JdbcTestCase.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/MybatisTestCase.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.java create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.xml create mode 100644 fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/utils/LogUtils.java diff --git a/fluent-sql-core/src/main/java/group/flyfish/fluent/chain/SQLImpl.java b/fluent-sql-core/src/main/java/group/flyfish/fluent/chain/SQLImpl.java index a473e75..ed6e01d 100644 --- a/fluent-sql-core/src/main/java/group/flyfish/fluent/chain/SQLImpl.java +++ b/fluent-sql-core/src/main/java/group/flyfish/fluent/chain/SQLImpl.java @@ -6,6 +6,7 @@ import group.flyfish.fluent.chain.common.PreSqlChain; import group.flyfish.fluent.chain.select.AfterOrderSqlChain; import group.flyfish.fluent.chain.select.AfterWhereSqlChain; import group.flyfish.fluent.chain.update.AfterSetSqlChain; +import group.flyfish.fluent.debug.FluentSqlDebugger; import group.flyfish.fluent.entity.SQLEntity; import group.flyfish.fluent.operations.FluentSQLOperations; import group.flyfish.fluent.query.JoinCandidate; @@ -38,9 +39,6 @@ final class SQLImpl extends ConcatSegment implements SQLOperations, Pre // 参数map,有序 private final List parameters = new ArrayList<>(); - // 调试标识 - private final boolean debug = false; - // 主表class,默认是第一个from的表为主表 private Class primaryClass; @@ -229,7 +227,7 @@ final class SQLImpl extends ConcatSegment implements SQLOperations, Pre private String sql() { Assert.notNull(SHARED_OPERATIONS, "未指定执行数据源!"); String sql = segments.stream().map(SQLSegment::get).collect(Collectors.joining(" ")); - if (debug) { + if (FluentSqlDebugger.enabled()) { System.out.println("prepared sql: " + sql); System.out.println("prepared args:" + parameters.stream().map(ParameterUtils::convert).map(String::valueOf) .collect(Collectors.joining(","))); diff --git a/fluent-sql-core/src/main/java/group/flyfish/fluent/debug/FluentSqlDebugger.java b/fluent-sql-core/src/main/java/group/flyfish/fluent/debug/FluentSqlDebugger.java new file mode 100644 index 0000000..4401002 --- /dev/null +++ b/fluent-sql-core/src/main/java/group/flyfish/fluent/debug/FluentSqlDebugger.java @@ -0,0 +1,17 @@ +package group.flyfish.fluent.debug; + +/** + * 调试器 + */ +public class FluentSqlDebugger { + + private static boolean debug = false; + + public static void enable() { + debug = true; + } + + public static boolean enabled() { + return debug; + } +} diff --git a/fluent-sql-spring-jdbc/pom.xml b/fluent-sql-spring-jdbc/pom.xml index 78e97d9..7e9c538 100644 --- a/fluent-sql-spring-jdbc/pom.xml +++ b/fluent-sql-spring-jdbc/pom.xml @@ -30,6 +30,11 @@ junit test + + org.mybatis + mybatis + test + mysql mysql-connector-java @@ -40,5 +45,26 @@ spring-context test + + com.baomidou + mybatis-plus-extension + test + + + + + + + src/test/java + + **/*.properties + **/*.xml + + + false + + + + diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/FluentJdbcTest.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/FluentJdbcTest.java index 59224c3..ad32677 100644 --- a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/FluentJdbcTest.java +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/FluentJdbcTest.java @@ -4,25 +4,19 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.mysql.cj.jdbc.Driver; import group.flyfish.fluent.operations.FluentSQLOperations; import group.flyfish.fluent.operations.JdbcTemplateFluentSQLOperations; -import group.flyfish.fluent.utils.data.ObjectMappers; -import group.flyfish.framework.entity.SaasOrder; -import group.flyfish.framework.entity.SaasPlan; -import group.flyfish.framework.entity.SaasTenant; -import group.flyfish.framework.vo.TenantContext; +import group.flyfish.framework.cases.FluentSqlTestCase; +import group.flyfish.framework.cases.JdbcTestCase; +import group.flyfish.framework.cases.MybatisTestCase; import org.junit.Test; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.SimpleDriverDataSource; import javax.sql.DataSource; import java.sql.SQLException; +import java.util.Arrays; import java.util.List; -import static group.flyfish.fluent.chain.SQL.select; -import static group.flyfish.fluent.chain.select.SelectComposite.composite; -import static group.flyfish.fluent.query.Query.where; - /** * 链式jdbc测试 * @@ -42,27 +36,16 @@ public class FluentJdbcTest { new Driver(), "jdbc:mysql://127.0.0.1:3306/epi_project?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=Asia/Shanghai", "root", - "oI3WtMO8h%mSYARp" + "Unicom#2018" ); - // 基于构造器自动绑定注册,在实际应用中使用@Bean声明即可,可参考下面的demo - new JdbcTemplateFluentSQLOperations(new JdbcTemplate(dataSource)); - - // 一个平平无奇的查询 - List list = select( - // 查询租户全量字段 - composite(SaasTenant::getId, SaasTenant::getName, SaasTenant::getIdentifier, SaasTenant::getDatasource, - SaasTenant::getStorage, SaasTenant::getStatus, SaasTenant::getEnable), - // 查询套餐 - composite(SaasOrder::getQuotaConfig, SaasOrder::getOrderTime, SaasOrder::getExpireTime, - SaasOrder::getOrderType)) - .from(SaasTenant.class) - .leftJoin(SaasOrder.class).on(where(SaasOrder::getTenantId).eq(SaasTenant::getId)) - .leftJoin(SaasPlan.class).on(where(SaasPlan::getId).eq(SaasOrder::getPlanId)) - .matching(where(SaasTenant::getEnable).eq(true)) - .list(TenantContext.class); - - // 打印效果 - System.out.println(ObjectMappers.shared().writeValueAsString(list)); + // 准备待测试用例 + List> cases = Arrays.asList( + new JdbcTestCase(dataSource), + new MybatisTestCase(dataSource), + new FluentSqlTestCase(dataSource) + ); + // 执行测试 + cases.forEach(TestCase::test); } /** diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/TestCase.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/TestCase.java new file mode 100644 index 0000000..1169fc6 --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/TestCase.java @@ -0,0 +1,38 @@ +package group.flyfish.framework; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 测试器 + * + * @author wangyu + */ +public interface TestCase { + + /** + * 初始化 + * + * @throws Exception 异常 + */ + void initialize() throws Exception; + + /** + * 执行并获取结果 + * + * @return 结果 + */ + T test(); + + /** + * 测试用例名称 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @interface Name { + + String value(); + } +} diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/AbstractTestCase.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/AbstractTestCase.java new file mode 100644 index 0000000..695e62c --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/AbstractTestCase.java @@ -0,0 +1,62 @@ +package group.flyfish.framework.cases; + +import group.flyfish.framework.TestCase; + +import javax.sql.DataSource; + +import static group.flyfish.framework.utils.LogUtils.print; +import static group.flyfish.framework.utils.LogUtils.printResult; + +/** + * 抽象测试用例 + * + * @param 泛型 + */ +public abstract class AbstractTestCase implements TestCase { + + protected DataSource dataSource; + + protected AbstractTestCase(DataSource dataSource) { + this.dataSource = dataSource; + try { + this.initialize(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 测试运行逻辑 + * + * @return 运行结果 + * @throws Exception 异常 + */ + public abstract T run() throws Exception; + + /** + * 测试逻辑 + * + * @return 测试结果值 + */ + @Override + public T test() { + Name anno = getClass().getAnnotation(Name.class); + assert anno != null; + String name = anno.value(); + long current = System.currentTimeMillis(); + T result = null; + try { + result = run(); + print("【初次执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current); + current = System.currentTimeMillis(); + result = run(); + return result; + } catch (Exception e) { + print("执行失败!{0}", e.getMessage()); + throw new RuntimeException(e); + } finally { + print("【正常执行】执行任务《{0}》用时:{1}ms", name, System.currentTimeMillis() - current); + printResult(result); + } + } +} diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/FluentSqlTestCase.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/FluentSqlTestCase.java new file mode 100644 index 0000000..d6c1d03 --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/FluentSqlTestCase.java @@ -0,0 +1,61 @@ +package group.flyfish.framework.cases; + +import group.flyfish.fluent.debug.FluentSqlDebugger; +import group.flyfish.fluent.operations.JdbcTemplateFluentSQLOperations; +import group.flyfish.framework.TestCase; +import group.flyfish.framework.entity.SaasOrder; +import group.flyfish.framework.entity.SaasPlan; +import group.flyfish.framework.entity.SaasTenant; +import group.flyfish.framework.vo.TenantContext; +import org.springframework.jdbc.core.JdbcTemplate; + +import javax.sql.DataSource; +import java.util.List; + +import static group.flyfish.fluent.chain.SQL.select; +import static group.flyfish.fluent.chain.select.SelectComposite.composite; +import static group.flyfish.fluent.query.Query.where; + +@TestCase.Name("使用fluent-sql") +public class FluentSqlTestCase extends AbstractTestCase> { + + public FluentSqlTestCase(DataSource dataSource) { + super(dataSource); + } + + /** + * 初始化 + * + * @throws Exception 异常 + */ + @Override + public void initialize() throws Exception { + // 基于构造器自动绑定注册,在实际应用中使用@Bean声明即可,可参考下面的demo + new JdbcTemplateFluentSQLOperations(new JdbcTemplate(dataSource)); + // 启用调试 + FluentSqlDebugger.enable(); + } + + /** + * 测试运行逻辑 + * + * @return 运行结果 + * @throws Exception 异常 + */ + @Override + public List run() throws Exception { + // 一个平平无奇的查询 + return select( + // 查询租户全量字段 + composite(SaasTenant::getId, SaasTenant::getName, SaasTenant::getIdentifier, SaasTenant::getDatasource, + SaasTenant::getStorage, SaasTenant::getStatus, SaasTenant::getEnable), + // 查询套餐 + composite(SaasOrder::getQuotaConfig, SaasOrder::getOrderTime, SaasOrder::getExpireTime, + SaasOrder::getOrderType)) + .from(SaasTenant.class) + .leftJoin(SaasOrder.class).on(where(SaasOrder::getTenantId).eq(SaasTenant::getId)) + .leftJoin(SaasPlan.class).on(where(SaasPlan::getId).eq(SaasOrder::getPlanId)) + .matching(where(SaasTenant::getEnable).eq(true)) + .list(TenantContext.class); + } +} diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/JdbcTestCase.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/JdbcTestCase.java new file mode 100644 index 0000000..9dce1e7 --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/JdbcTestCase.java @@ -0,0 +1,99 @@ +package group.flyfish.framework.cases; + +import com.fasterxml.jackson.core.JsonProcessingException; +import group.flyfish.fluent.utils.data.ObjectMappers; +import group.flyfish.framework.TestCase; +import group.flyfish.framework.entity.SaasOrder; +import group.flyfish.framework.entity.SaasQuota; +import group.flyfish.framework.entity.SaasTenant; +import group.flyfish.framework.vo.TenantContext; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@TestCase.Name("使用JDBC") +public class JdbcTestCase extends AbstractTestCase> { + + public JdbcTestCase(DataSource dataSource) { + super(dataSource); + } + + /** + * 初始化 + * + * @throws Exception 异常 + */ + @Override + public void initialize() throws Exception { + // do nothing + } + + /** + * 测试运行逻辑 + * + * @return 运行结果 + * @throws Exception 异常 + */ + @Override + public List run() throws Exception { + String statement = "SELECT t1.`id` as `id`,t1.`name` as `name`,t1.`identifier` as `identifier`,t1.`datasource` as `datasource`,t1.`storage` as `storage`,t1.`status` as `status`,t1.`enable` as `enable`,t2.`quota_config` as `quotaConfig`,t2.`order_time` as `orderTime`,t2.`expire_time` as `expireTime`,t2.`order_type` as `orderType` FROM saas_tenant `t1` LEFT JOIN saas_order `t2` ON t2.`tenant_id` = t1.`id` LEFT JOIN saas_plan `t3` ON t3.`id` = t2.`plan_id` WHERE t1.`enable` = ?"; + try (Connection connection = dataSource.getConnection(); + PreparedStatement pst = connection.prepareStatement(statement); + ResultSet rs = execute(pst, true) + ) { + return extract(rs); + } + } + + /** + * 执行prepared statement并绑定值 + * + * @param statement 已经准备好的statement + * @param args 参数 + * @return 结果集 + * @throws SQLException 异常 + */ + private ResultSet execute(PreparedStatement statement, Object... args) throws SQLException { + statement.setBoolean(1, (Boolean) args[0]); + return statement.executeQuery(); + } + + /** + * 从结果集取得对象 + * + * @param resultSet 结果集 + * @return 结果 + */ + private List extract(ResultSet resultSet) throws SQLException { + List list = new ArrayList<>(); + while (resultSet.next()) { + TenantContext context = new TenantContext(); + context.setId(resultSet.getString("id")); + context.setName(resultSet.getString("name")); + context.setIdentifier(resultSet.getString("identifier")); + context.setDatasource(readValue(resultSet.getString("datasource"), SaasTenant.DataSourceConfig.class)); + context.setStorage(readValue(resultSet.getString("storage"), SaasTenant.StorageConfig.class)); + context.setStatus(SaasTenant.Status.valueOf(resultSet.getString("status"))); + context.setEnable(resultSet.getBoolean("enable")); + context.setQuota(readValue(resultSet.getString("quotaConfig"), SaasQuota.class)); + context.setOrderTime(resultSet.getDate("orderTime")); + context.setExpireTime(resultSet.getDate("expireTime")); + context.setOrderType(SaasOrder.Type.valueOf(resultSet.getString("orderType"))); + list.add(context); + } + return list; + } + + private T readValue(String value, Class clazz) { + try { + return ObjectMappers.shared().readValue(value, clazz); + } catch (JsonProcessingException e) { + return null; + } + } +} diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/MybatisTestCase.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/MybatisTestCase.java new file mode 100644 index 0000000..0cb6332 --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/cases/MybatisTestCase.java @@ -0,0 +1,62 @@ +package group.flyfish.framework.cases; + +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import group.flyfish.framework.TestCase; +import group.flyfish.framework.entity.SaasQuota; +import group.flyfish.framework.entity.SaasTenant; +import group.flyfish.framework.mapper.TenantContextMapper; +import group.flyfish.framework.vo.TenantContext; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.transaction.TransactionFactory; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.apache.ibatis.type.TypeHandlerRegistry; + +import javax.sql.DataSource; +import java.util.List; + +@TestCase.Name("使用mybatis执行") +public class MybatisTestCase extends AbstractTestCase> { + + private SqlSessionFactory sqlSessionFactory; + + public MybatisTestCase(DataSource dataSource) { + super(dataSource); + } + + /** + * 初始化 + * + * @throws Exception 异常 + */ + @Override + public void initialize() throws Exception { + // 使用mybatis执行 + TransactionFactory transactionFactory = new JdbcTransactionFactory(); + Environment environment = new Environment("development", transactionFactory, dataSource); + Configuration configuration = new Configuration(environment); + configuration.addMapper(TenantContextMapper.class); + TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry(); + registry.register(SaasTenant.DataSourceConfig.class, JacksonTypeHandler.class); + registry.register(SaasQuota.class, JacksonTypeHandler.class); + registry.register(SaasTenant.StorageConfig.class, JacksonTypeHandler.class); + this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); + } + + /** + * 测试运行逻辑 + * + * @return 运行结果 + * @throws Exception 异常 + */ + @Override + public List run() throws Exception { + try (SqlSession session = sqlSessionFactory.openSession()) { + TenantContextMapper mapper = session.getMapper(TenantContextMapper.class); + return mapper.selectList(true); + } + } +} diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.java new file mode 100644 index 0000000..c07ca97 --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.java @@ -0,0 +1,23 @@ +package group.flyfish.framework.mapper; + +import group.flyfish.framework.vo.TenantContext; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 测试用的mapper + * + * @author wangyu + */ +@Mapper +public interface TenantContextMapper { + + /** + * 查询列表 + * + * @param enable 启用与否 + * @return 结果 + */ + List selectList(Boolean enable); +} diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.xml b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.xml new file mode 100644 index 0000000..64aacff --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/mapper/TenantContextMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + diff --git a/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/utils/LogUtils.java b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/utils/LogUtils.java new file mode 100644 index 0000000..5782e9e --- /dev/null +++ b/fluent-sql-spring-jdbc/src/test/java/group/flyfish/framework/utils/LogUtils.java @@ -0,0 +1,25 @@ +package group.flyfish.framework.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import group.flyfish.fluent.utils.data.ObjectMappers; + +import java.text.MessageFormat; + +public class LogUtils { + + public static void print(String message, Object... args) { + System.out.println(MessageFormat.format(message, args)); + } + + public static void printResult(Object value) { + if (null == value) { + print("执行结果为null"); + } else { + try { + print("执行结果为{0}", ObjectMappers.shared().writeValueAsString(value)); + } catch (JsonProcessingException e) { + print("执行结果为{0}", value); + } + } + } +} diff --git a/pom.xml b/pom.xml index 710e3f0..3f0a5ba 100644 --- a/pom.xml +++ b/pom.xml @@ -121,6 +121,16 @@ spring-context ${spring.version} + + org.mybatis + mybatis + 3.5.10 + + + com.baomidou + mybatis-plus-extension + 3.5.2 + org.slf4j slf4j-api