From f63e8dc76320ced32fc46f32b2ed4856c56ebc53 Mon Sep 17 00:00:00 2001 From: jiangw <39796328+b6688c@users.noreply.github.com> Date: Sun, 22 Oct 2023 10:48:00 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=8E=BB=E9=99=A4=E4=B8=8D=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E7=9A=84=E4=BE=9D=E8=B5=96=E4=BB=A5=E5=8F=8A=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/test.md | 1 - uno-bom/pom.xml | 96 ++---- .../uno-component-sequential/pom.xml | 10 - uno-data/pom.xml | 24 +- .../uno/data/query/excel/CellDataDeal.java | 24 -- .../data/query/excel/CellDataDealFactory.java | 14 - .../uno/data/query/excel/CellHeader.java | 62 ---- .../allio/uno/data/query/excel/CellIndex.java | 23 -- .../query/excel/CollectionCellDataDeal.java | 46 --- .../excel/ContemporaneousCellDataDeal.java | 61 ---- .../uno/data/query/excel/TimeFormatDeal.java | 39 --- .../query/excel/ValueTimeExcelWriter.java | 34 -- uno-starters/pom.xml | 1 - uno-starters/uno-starter-liquibase/README.md | 294 ------------------ .../doc/images/example1.png | Bin 21797 -> 0 bytes uno-starters/uno-starter-liquibase/pom.xml | 66 ---- .../BaseLiquibaseDataSourceAdapter.java | 143 --------- .../DataSourceAdapterDispatcher.java | 54 ---- .../liquibase/DruidDataSourceAdapter.java | 29 -- .../DynamicRoutingDataSourceAdapter.java | 74 ----- .../liquibase/HikariDataSourceAdapter.java | 46 --- .../liquibase/LiquibaseDataSourceAdapter.java | 153 --------- .../config/UnoLiquibaseAutoConfiguration.java | 83 ----- .../liquibase/DruidDataSourceAdapterTest.java | 49 --- .../DynamicRoutingDataSourceAdapterTest.java | 67 ---- .../HikariDataSourceAdapterTest.java | 54 ---- .../uno/starter/liquibase/MigrationTest.java | 62 ---- .../liquibase/changetask/TestChangeTask.java | 34 -- .../migrations/mysql/db_migration-second.yaml | 0 .../db/migrations/mysql/db_migration.yaml | 17 - .../db/migrations/mysql/sql/V1__Person.sql | 6 - .../migrations/mysql/sql/V1__Person_Data.sql | 1 - .../postgres/db_migration-master.yaml | 0 .../db/migrations/postgres/db_migration.yaml | 0 .../src/test/resources/uno.yaml | 4 - .../properties/FeignClientProperties.java | 24 -- .../properties/FeignEncoderProperties.java | 22 -- .../uno/test/annotation/MybatisEnvTest.java | 3 +- 38 files changed, 25 insertions(+), 1695 deletions(-) delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDeal.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDealFactory.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/CellHeader.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/CellIndex.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/CollectionCellDataDeal.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/ContemporaneousCellDataDeal.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/TimeFormatDeal.java delete mode 100644 uno-data/src/main/java/cc/allio/uno/data/query/excel/ValueTimeExcelWriter.java delete mode 100644 uno-starters/uno-starter-liquibase/README.md delete mode 100644 uno-starters/uno-starter-liquibase/doc/images/example1.png delete mode 100644 uno-starters/uno-starter-liquibase/pom.xml delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/BaseLiquibaseDataSourceAdapter.java delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DataSourceAdapterDispatcher.java delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapter.java delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapter.java delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapter.java delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/LiquibaseDataSourceAdapter.java delete mode 100644 uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/config/UnoLiquibaseAutoConfiguration.java delete mode 100644 uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapterTest.java delete mode 100644 uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapterTest.java delete mode 100644 uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapterTest.java delete mode 100644 uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/MigrationTest.java delete mode 100644 uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/changetask/TestChangeTask.java delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration-second.yaml delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration.yaml delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person.sql delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person_Data.sql delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/postgres/db_migration-master.yaml delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/postgres/db_migration.yaml delete mode 100644 uno-starters/uno-starter-liquibase/src/test/resources/uno.yaml delete mode 100644 uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignClientProperties.java delete mode 100644 uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignEncoderProperties.java diff --git a/docs/test.md b/docs/test.md index eef42e72..35253ff7 100644 --- a/docs/test.md +++ b/docs/test.md @@ -121,7 +121,6 @@ public class RedisEnvTest extends BaseTestCase { | Redis | `@RedisEnv` | `@RedisProperties` | | | DataSource | `@DataSourceEnv` | `@DataSourceProperties` | | | ElasticSearch | `@EsEnv` | `@EsProperties` | | -| Feign | `@FeignEnv` | | | | Mybatis | `@MybatisEnv` | `@MybatisProperties` | | | MybatisPlus | `@MybatisPlusEnv` | `@MybatisPlusProperties` | | | ... | | | | diff --git a/uno-bom/pom.xml b/uno-bom/pom.xml index 77e51d0e..88ca1c6d 100644 --- a/uno-bom/pom.xml +++ b/uno-bom/pom.xml @@ -5,8 +5,8 @@ org.springframework.boot spring-boot-starter-parent - 2.3.12.RELEASE - + 3.1.5 + 4.0.0 @@ -24,48 +24,46 @@ 1.0.1 2.11.4 - 1.2.78 1.12.2 3.3.0 1.18.22 5.6.2 - 4.0.0 - 30.1.1-jre + 5.6.0 + 31.1-jre 2.2.17 1.6.2 - 3.2.0 + 3.0.0 3.0.2 3.5.3 - - 4.0.11 - 1.2.5 + 1.2.20 8.0.22 12.2.0.1 42.2.22 8.4.1.jre8 - 3.3.6 - - 0.31.0 - 3.0.0 + 4.1.3 + 27.0 + 3.7.0 2.5.1 - 4.4.0 - 1.8 8.7.1 6.7.0 5.3.1 - 2.4.0 3.2.4 + 3.2.1 - 2.0.1 + + + 2.0.1 + + 0.4.6 @@ -264,18 +262,18 @@ ${swagger-v2.version} provided - - - com.alibaba - QLExpress - ${qlexpress.version} - org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis-spring-boot.version} provided + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + ${mybatis-spring-boot.version} + test + com.baomidou mybatis-plus-boot-starter @@ -328,36 +326,6 @@ ${mybatis-plus-dynamic.version} provided - - org.hswebframework.web - hsweb-commons-crud - ${hsweb-framework.version} - - - io.opentracing - opentracing-api - ${oepntracing.version} - - - io.opentracing - opentracing-util - ${oepntracing.version} - - - com.playtika.reactivefeign - feign-reactor-cloud - ${feign-reactor.version} - - - com.playtika.reactivefeign - feign-reactor-webclient - ${feign-reactor.version} - - - com.playtika.reactivefeign - feign-reactor-spring-configuration - ${feign-reactor.version} - io.springfox springfox-swagger2 @@ -383,26 +351,6 @@ postgis-jdbc ${postgis-jdbc.version} - - cn.afterturn - easypoi-annotation - ${easypoi.version} - - - cn.afterturn - easypoi-base - ${easypoi.version} - - - cn.afterturn - easypoi-web - ${easypoi-version} - - - org.apache.commons - commons-csv - ${appache-commons-csv.version} - com.influxdb influxdb-client-java @@ -437,7 +385,7 @@ jakarta.json jakarta.json-api - ${jakarta.json-api.version} + ${jakarta.version} com.taosdata.jdbc diff --git a/uno-components/uno-component-sequential/pom.xml b/uno-components/uno-component-sequential/pom.xml index 36c2441b..9cffbd4e 100644 --- a/uno-components/uno-component-sequential/pom.xml +++ b/uno-components/uno-component-sequential/pom.xml @@ -43,20 +43,10 @@ elasticsearch-java test - - org.elasticsearch.client - elasticsearch-rest-high-level-client - test - org.elasticsearch.client elasticsearch-rest-client test - - org.elasticsearch - elasticsearch - test - \ No newline at end of file diff --git a/uno-data/pom.xml b/uno-data/pom.xml index 742d29ce..e081571e 100644 --- a/uno-data/pom.xml +++ b/uno-data/pom.xml @@ -51,20 +51,11 @@ elasticsearch-java provided - - org.elasticsearch.client - elasticsearch-rest-high-level-client - provided - org.elasticsearch.client elasticsearch-rest-client provided - - org.elasticsearch - elasticsearch - jakarta.persistence jakarta.persistence-api @@ -81,10 +72,6 @@ taos-jdbcdriver provided - - cn.afterturn - easypoi-base - org.springframework.boot spring-boot-starter-data-jpa @@ -126,9 +113,8 @@ provided - dev.miku + io.asyncer r2dbc-mysql - provided io.r2dbc @@ -136,9 +122,8 @@ provided - io.r2dbc + org.postgresql r2dbc-postgresql - provided io.r2dbc @@ -184,11 +169,6 @@ - - org.apache.commons - commons-csv - test - org.springframework spring-webmvc diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDeal.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDeal.java deleted file mode 100644 index 5ee1267d..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDeal.java +++ /dev/null @@ -1,24 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** - * 实现设备历史监测数据进行导出时候,调用该类方法进行数据处理 - * - * @author cxd - * @date 2022/12/30 22:49 - * @since 1.1.2 - */ - -public interface CellDataDeal { - - /** - * @param dataMap - * @param cellHeader - * @return - */ - List> makeExcelData(Map> dataMap, CellHeader cellHeader); - -} diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDealFactory.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDealFactory.java deleted file mode 100644 index 9c4c0a43..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellDataDealFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import cc.allio.uno.data.query.param.DateDimension; - -public class CellDataDealFactory { - - public static CellDataDeal create(DateDimension[] contemporaneous) { - if (null != contemporaneous && contemporaneous.length > 0) { - return new ContemporaneousCellDataDeal(); - } else { - return new CollectionCellDataDeal(); - } - } -} diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellHeader.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellHeader.java deleted file mode 100644 index d803c790..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellHeader.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; -import cc.allio.uno.data.query.param.DateDimension; -import com.google.common.collect.Maps; -import lombok.Data; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * 实现设备历史监测数据进行导出时候,调用该类方法进行导出表格表头的生成 - * - * @author cxd - * @date 2022/12/30 22:49 - * @since 1.1.2 - */ -@Data -public class CellHeader { - - final Map headers; - final String timeField; - final String[] dataField; - final DateDimension[] contemporaneous; - - public CellHeader(DateDimension[] contemporaneous, String[] dataField, String timeField, List cellIndices) { - this.headers = Maps.newLinkedHashMap(); - Map cellIndicesMap = cellIndices.stream().collect(Collectors.toMap(CellIndex::getKey, CellIndex::getName)); - ExcelExportEntity colEntity = new ExcelExportEntity("采集时间", timeField); - colEntity.setNeedMerge(true); - colEntity.setWidth(20.00); - headers.put((String) colEntity.getKey(), colEntity); - if (null != contemporaneous && contemporaneous.length > 0) { - //同期数据 - for (int i = 0; i < dataField.length; i++) { - for (int i1 = 0; i1 < contemporaneous.length; i1++) { - colEntity = new ExcelExportEntity(cellIndicesMap.get(dataField[i]) + contemporaneous[i1].getDate(), dataField[i] + contemporaneous[i1].getDate()); - colEntity.setNeedMerge(true); - colEntity.setWidth(30.00); - headers.put((String) colEntity.getKey(), colEntity); - } - } - } else { - //非同期数据 - for (int i = 0; i < dataField.length; i++) { - colEntity = new ExcelExportEntity(cellIndicesMap.get(dataField[i]), dataField[i]); - colEntity.setWidth(20.00); - colEntity.setNeedMerge(true); - headers.put((String) colEntity.getKey(), colEntity); - } - } - this.timeField = timeField; - this.dataField = dataField; - this.contemporaneous = contemporaneous; - } - - - public ExcelExportEntity get(String field) { - return headers.get(field); - } -} diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellIndex.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellIndex.java deleted file mode 100644 index edb5e6e1..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CellIndex.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import lombok.*; - -import java.io.Serializable; - -@Getter -@Setter -@ToString -@RequiredArgsConstructor -@AllArgsConstructor -public class CellIndex implements Serializable { - - /** - * 指标值 - */ - private String key; - - /** - * 指标名称 - */ - private String name; -} diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CollectionCellDataDeal.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/CollectionCellDataDeal.java deleted file mode 100644 index cb96dc12..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/CollectionCellDataDeal.java +++ /dev/null @@ -1,46 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; -import cc.allio.uno.core.bean.ValueWrapper; -import cc.allio.uno.core.util.DateUtil; - -import java.util.*; - -/** - * 实现设备历史监测数据进行导出时候,调用该类方法进行{非同期的}数据处理 - * - * @author cxd - * @date 2022/12/30 22:49 - * @since 1.1.2 - */ -public class CollectionCellDataDeal implements CellDataDeal { - - @Override - public List> makeExcelData(Map> dataMap, CellHeader cellHeader) { - List colList = new ArrayList<>(cellHeader.getHeaders().values()); - String timeField = cellHeader.getTimeField(); - //非同期数据 - List> list = new ArrayList<>(); - Collection dataList = dataMap.values().stream().findFirst().orElse(new ArrayList<>()); - for (Object dataDatum : dataList) { - ValueWrapper valueWrapper = ValueWrapper.get(dataDatum); - Map valMap = new HashMap<>(); - for (ExcelExportEntity excelExportEntity : colList) { - if (timeField.equals(excelExportEntity.getKey())) { - Object maybeTime = valueWrapper.getForce(timeField); - Date dateTime = null; - if (maybeTime.getClass().isAssignableFrom(String.class)) { - dateTime = DateUtil.parse(maybeTime.toString()); - } else if (maybeTime.getClass().isAssignableFrom(Date.class)) { - dateTime = (Date) maybeTime; - } - valMap.put(timeField, DateUtil.format(dateTime, TimeFormatDeal.getTimeFieldFormat(null))); - } else { - valMap.put((String) excelExportEntity.getKey(), valueWrapper.getForce((String) excelExportEntity.getKey())); - } - } - list.add(valMap); - } - return list; - } -} diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/ContemporaneousCellDataDeal.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/ContemporaneousCellDataDeal.java deleted file mode 100644 index 5b1fef08..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/ContemporaneousCellDataDeal.java +++ /dev/null @@ -1,61 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import cc.allio.uno.core.bean.ValueWrapper; -import cc.allio.uno.core.util.DateUtil; -import cc.allio.uno.data.query.param.DateDimension; -import com.google.common.collect.Maps; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * 实现设备历史监测数据进行导出时候,调用该类方法进行{同期的}数据处理 - * - * @author cxd - * @date 2022/12/30 22:49 - * @since 1.1.2 - */ -public class ContemporaneousCellDataDeal extends CollectionCellDataDeal { - - @Override - public List> makeExcelData(Map> dataMap, CellHeader cellHeader) { - String timeField = cellHeader.getTimeField(); - DateDimension[] contemporaneous = cellHeader.getContemporaneous(); - String[] dataField = cellHeader.getDataField(); - //同期数据 - return dataMap.entrySet().stream() - .flatMap(entry -> - entry.getValue().stream().map(dataDatum -> { - ValueWrapper valueWrapper = ValueWrapper.get(dataDatum); - Object maybeTime = valueWrapper.getForce(timeField); - Map valMap = Maps.newHashMap(); - Date dateTime = null; - if (maybeTime.getClass().isAssignableFrom(String.class)) { - dateTime = DateUtil.parse(maybeTime.toString()); - } else if (maybeTime.getClass().isAssignableFrom(Date.class)) { - dateTime = (Date) maybeTime; - } - valMap.put(timeField, DateUtil.format(dateTime, TimeFormatDeal.getTimeFieldFormat(contemporaneous[0].getDimension()))); - String timeHeadFormat = TimeFormatDeal.getTimeHeadFormat(contemporaneous[0].getDimension()); - for (int i = 0; i < dataField.length; i++) { - valMap.put(dataField[i] + DateUtil.format(dateTime, timeHeadFormat), valueWrapper.getForce(dataField[i])); - } - return valMap; - })) - .collect(Collectors.groupingBy(k -> k.get(timeField))) - .values() - .stream() - .map(g -> g.stream().reduce(Maps.newHashMap(), (a, b) -> { - a.putAll(b); - return a; - })) - .sorted((o1, o2) -> { - Date time = DateUtil.parse((String) o2.get(timeField), TimeFormatDeal.getTimeFieldFormat(contemporaneous[0].getDimension())); - Date timeCom = DateUtil.parse((String) o1.get(timeField), TimeFormatDeal.getTimeFieldFormat(contemporaneous[0].getDimension())); - return time.compareTo(timeCom); - }) - .collect(Collectors.toList()); - } - -} - diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/TimeFormatDeal.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/TimeFormatDeal.java deleted file mode 100644 index 6b30fd4f..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/TimeFormatDeal.java +++ /dev/null @@ -1,39 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import cc.allio.uno.core.util.DateUtil; -import cc.allio.uno.data.query.param.TimeDimension; - -/** - * 导出表头和表数据的时间格式处理类 - * - * @author cxd - * @date 2022/12/30 22:49 - * @since 1.1.2 - */ -public class TimeFormatDeal { - - public static String getTimeFieldFormat(TimeDimension timeDimension) { - if (null != timeDimension) { - if (TimeDimension.MONTH.equals(timeDimension)) { - return "dd HH:mm"; - } else if (TimeDimension.DAY.equals(timeDimension)) { - return "HH:mm"; - } else { - throw new IllegalArgumentException("请输入合法参数"); - } - } else { - return "MM-dd HH:mm"; - } - } - - public static String getTimeHeadFormat(TimeDimension timeDimension) { - if (TimeDimension.MONTH.equals(timeDimension)) { - return DateUtil.PATTERN_MONTH; - } else if (TimeDimension.DAY.equals(timeDimension)) { - return DateUtil.PATTERN_DATE; - } else { - throw new IllegalArgumentException("请输入合法参数"); - } - } - -} diff --git a/uno-data/src/main/java/cc/allio/uno/data/query/excel/ValueTimeExcelWriter.java b/uno-data/src/main/java/cc/allio/uno/data/query/excel/ValueTimeExcelWriter.java deleted file mode 100644 index 058818cb..00000000 --- a/uno-data/src/main/java/cc/allio/uno/data/query/excel/ValueTimeExcelWriter.java +++ /dev/null @@ -1,34 +0,0 @@ -package cc.allio.uno.data.query.excel; - -import cn.afterturn.easypoi.excel.ExcelExportUtil; -import cn.afterturn.easypoi.excel.entity.ExportParams; -import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; -import cc.allio.uno.data.query.param.DateDimension; -import org.apache.poi.ss.usermodel.Workbook; - -import java.util.*; - -/** - * 历史监测数据的导出调用接口 - * - * @author cxd - * @date 2022/12/30 22:49 - * @since 1.1.2 - */ -public class ValueTimeExcelWriter { - - /** - * 根据入参构建导出表格,入参主要有是否同期,统计数据,统计字段 - * 添加数据(同期数据和非同期数据) - */ - public static Workbook exportHisExcel(CellHeader cellHeader, Map> dataMap) { - //生成表头 - DateDimension[] contemporaneous = cellHeader.getContemporaneous(); - List colList = new ArrayList<>(cellHeader.getHeaders().values()); - //插入表数据 - CellDataDeal cellDataDeal = CellDataDealFactory.create(contemporaneous); - List> list = cellDataDeal.makeExcelData(dataMap, cellHeader); - return ExcelExportUtil.exportExcel(new ExportParams(), colList, list); - } - -} diff --git a/uno-starters/pom.xml b/uno-starters/pom.xml index 8220d66f..94a6a270 100644 --- a/uno-starters/pom.xml +++ b/uno-starters/pom.xml @@ -20,7 +20,6 @@ uno-starter-core uno-starter-kafka - uno-starter-liquibase uno-starter-websocket uno-starter-sequential uno-starter-redis diff --git a/uno-starters/uno-starter-liquibase/README.md b/uno-starters/uno-starter-liquibase/README.md deleted file mode 100644 index ebffbfc6..00000000 --- a/uno-starters/uno-starter-liquibase/README.md +++ /dev/null @@ -1,294 +0,0 @@ -# Liquibase数据库版本控制 - -版本号:1.1.5.RELEASE - -liquibase是一个数据库变更的版本控制工具。项目中通过liquibase解析用户编写的liquibase的配置文件,生成sql语句,并执行和记录。执行是根据记录确定sql语句是否曾经执行过,和配置文件里的预判断语句确定sql是否执行。 - -特性: - -1、配置文件支持SQL、XML、JSON 或者 YAML - 2、版本控制按序执行 - 3、可以用上下文控制sql在何时何地如何执行。 - 4、支持schmea的变更 - 5、根据配置文件自动生成sql语句用于预览 - 6、可重复执行迁移 - 7、可插件拓展 - 8、可回滚 - 9、可兼容14中主流数据库如oracle,mysql,pg等,支持平滑迁移 - 10、支持schema方式的多租户(multi-tenant) - -## 为什么使用Liquibase - -在大多数项目仍然提供`sql`脚本甚至有时不这样(哪里漏水堵哪里): - -- What state is the database in onTrigger this machine?(不知道在这台机器数据库的状态) -- Has this script already been applied or not?(这个脚本是否被使用过) -- Has the quick fix in production been applied in test afterwards?(生产用了,测试是否用了?) -- How do you set up a new database instance?(怎么从头开始创建一个新的数据库) - -所以数据库版本管理框架是用来解决这种混乱的局面:他们允许你: - -- Recreate a database from scratch(重新开始创建一个数据库) -- Make it clear at all times what state a database is in(在任何时刻知道数据库状态) -- Migrate in a deterministic way from your current version of the database to a newer one(以一种确定的方式从你当前的数据库版本迁移到一个较新的版本) - -### 为什么不使用flyway - -[Flyway](https://flywaydb.org/) 是一款开源的数据库版本管理工具,使用方式和学习成本与Liquibase差不多,但它无法很好适用于微服务形式,原因在于它的版本控制多团队开发可能存在冲突。但Liquibase可以自定义版本,这点就很适合用于多团队多服务数据库版本管理 - -## 使用 - -blade的Liqubase目前仅支持change-log文件读取,暂不支持指定rollback等更多配置内容。 - -Liquibase的核心原理是通过读取`change-log`文件。所以在使用时,我们首先创建这个文件,这个文件应该创建在哪里? - -默认需要创建在类路径下:**/db/migrations/#{dbType}/db_migration.yaml**。 - -### 文件路径 - -#### 单数据源 - -我们可以看到这个目录中存在一个占位符,这个占位符的类型表示当前服务使用的数据源类型,比如当前数据源是**mysql**,文件存放路径如:/db/migrations/mysql/db_migration.yaml(后缀也可以是`.xml/.json/.sql`,怎么配置详细看官网文档)。同理如果切换其他数据源我们就需要创建相应的目录文件。 - -有时候我们又想指定目录就能读取到,基于这个需要,单数据源只需要在spring 配置中增加`spring.liquibase.change-log`并且填写对应的目录 - -```yaml -spring: - liquibase: - change-log: classpath:test.yaml -``` - -#### 多数据源 - -会存在一个情况我们使用的服务存在多数据源,这个时候可以对不同的数据源执行不同的版本控制,但前提我们的文件名称需要变一下。比如说:想使用master数据源进行版本控制,那么此时你的文件名称就变为`db_migration-master.yaml`,同理其他数据源也是一样的配置。就如下面这张图一样 - - - -指定目录在多数据源配置如下: - -```yaml -spring: - #排除DruidDataSourceAutoConfigure - autoconfigure: - exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure - datasource: - dynamic: - druid: - #通用校验配置 - validation-query: select 1 - #启用sql日志拦截器 - proxy-filters: - - sqlLogInterceptor - #设置默认的数据源或者数据源组,默认值即为master - primary: master - datasource: - master: - druid: - #独立校验配置 - validation-query: select 1 - #oracle校验 - #validation-query: select 1 from dual - url: ${blade.datasource.dev.master.url} - username: ${blade.datasource.dev.master.username} - password: ${blade.datasource.dev.master.password} - liquibase: - change-log: classpath:test.yaml -``` - -### 文件内容 - -在知道change-log文件路径在哪后,我们来具体看看它里面存在什么内容: - -```yaml -databaseChangeLog: - # 一次数据库版本变化都是一个变更集 - - changeSet: - # 命名规则:框架(系统名)-服务-版本号-功能(或者目的) - id: jw-test-V1-Person - author: jiangwei - comment: 创建Person表 - runInTransaction: true - changes: - # 创建表结构 - - sqlFile: - path: classpath:db/migrations/mysql/sql/V1__Person.sql - encoding: utf8 - # 创建表数据 - - sqlFile: - path: classpath:db/migrations/mysql/sql/V1__Person_Data.sql - encoding: utf8 - - changeSet: - id: jw-test-V1-Person-task - author: jiangwei - changes: - # 创建自定义数据变更类 - - customChange: { "class": "com.jw.liquibase.change.PersonChangeTask" } - -``` - -Liquibase每次数据库变更都是以`change-set`作为一个变更集,所以我们每次一个功能版本都是一个`change-log`。在一个`change-log`中需要指定`id`、`author`。其中: - -- id:命名规则:框架(系统名)-服务-版本号-功能(或者目的),比如:blade-auth-V1-init(blade系统-认证服务-第一个版本-初始化) - -在`change-set`中`changes`是为最重要,他表示当前变更的内容。它有两种好使用的方式: - -- sqlFile:指定一个sql文件路径 - -- customChange:指定一个实现`CustomTaskChange`接口的权限类名,如下: - - ```java - public class PersonChangeTask implements CustomTaskChange { - - @Override - public void execute(Database database) throws CustomChangeException { - Person person = new Person(4, "Jiang Wei"); - PersonMapper mapper = SpringUtil.getContext().getBean(PersonMapper.class); - mapper.insert(person); - } - - @Override - public String getConfirmationMessage() { - return null; - } - - @Override - public void setUp() throws SetupException { - - } - - @Override - public void setFileOpener(ResourceAccessor resourceAccessor) { - - } - - @Override - public ValidationErrors validate(Database database) { - return null; - } - } - - ``` - -需要注意的点:如果使用自定义变更类(`CustomTaskChange`)他不能读取和他在一个变更集执行的库表数据内容(比如我当前sqlFile是创建`Person`表,但是如果在`CustomTaskChange`中将读取不到这张表的内容,因为他们处于同一个事物中)解决办法是放在不同的变更集中。如上面所示。 - -## uno-starter-liquibase原理 - -在具体实现最重要的是两点: - -1. 读取到change-log的内容 -2. 不同的数据源具有不同的change-log内容 - -解决办法是,制定如下规则: - -1.自动读取配置文件(也可以人工配置,如果有):分数据库类型 - -​ 单数据源:以db_migration.yaml或者db_migration.xml作为查找条件 - -​ 多数据源:以db_migration-#{dynamic}.yaml或者db_migration-#{dynamic}.xml作为查找条件 - -2.指定配置读取 - -​ 单数据源:读取spring.liquibase.changelog - -​ 多数据源:读取spring.datasource.dynamic.datasource.\#{dynamic}.liquibase.changelog配置 - -因为考虑到数据源类型的多种多样,所以采取适配器设计模式,它的顶层接口是`LiquibaseDataSourceAdapter`。 - -我们在获取到`change-log`路径后需要创建`SpringLiquibase`注册到Spring中,让他自动执行变更集,具体代码如下: - -```java - /** - * 向Spring注册Liquibase对象 - * - * @param dataSource 数据源对象 - * @param beanFactory bean工厂 - */ - default void registerLiquibase(DataSource dataSource, DefaultListableBeanFactory beanFactory) { - String changeLog = getChangeLog(dataSource); - if (StringUtils.isEmpty(changeLog)) { - return; - } - SpringLiquibase liquibase = new SpringLiquibase(); - liquibase.setChangeLog(changeLog); - liquibase.setDataSource(dataSource); - BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(SpringLiquibase.class, () -> liquibase); - beanFactory.registerBeanDefinition("liquibase-".concat(dbType(dataSource)), beanDefinitionBuilder.getRawBeanDefinition()); - } -``` - -## change-log - -changelog是LiquiBase用来记录数据库的变更,一般放在`CLASSPATH`下,然后配置到执行路径中。 - -changelog支持多种格式,主要有`XML/JSON/YAML/SQL,其中XML/JSON/YAML除了具体格式语法不同,节点配置很类似,SQL格式中主要记录SQL语句,这里仅给出XML格式和SQL格式的示例: - -`change-log.xml`: - -```xml - - - 3 - title 3 - content 3 - - -``` - -`change-log.sql` - -```sql ---liquibase formatted sql ---changeset daniel:16040707 -CREATE TABLE `role_authority_sum` ( - `row_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `role_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联role的role_id', - `authority_sum` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'perms的值的和', - `data_type_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联data_type的id', - PRIMARY KEY (`row_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色的权限值的和,如角色有RD权限,则和为2+8=10'; -``` - -### change-set - -一个``标签对应一个变更集,由id、name、以及changelog的文件路径组成唯一标识。changelog在执行的时候并不是按照id的顺序,而是按照changeSet在changelog中出现的顺序。 - -LiquiBase在执行changelog时,会在数据库中插入两张表:`DATABASECHANGELOG`和`DATABASECHANGELOGLOCK`,分别记录changelog的执行日志和锁日志。 - -LiquiBase在执行changelog中的changeSet时,会首先查看`DATABASECHANGELOG`表,如果已经执行过,则会跳过(除非changeSet的`runAlways`属性为true,后面会介绍),如果没有执行过,则执行并记录changelog日志; - -changelog中的一个changeSet对应一个事务,在changeSet执行完后commit,如果出现错误则rollback; - -- runAlways:即使已经执行过,仍然每次都执行;**注意**: 由于`DATABASECHANGELOG`表中还记录了changeSet的MD5校验值MD5SUM,如果changeSet的`id`和`name`没变,而内容变了,则由于MD5值变了,即使runAlways的值为True,执行也是失败的,会报错。这种情况应该使用`runOnChange`属性。 -- runOnChange:第一次的时候执行以及当changeSet的内容发生变化时执行。不受MD5校验值的约束。 -- runInTransaction:是否作为一个事务执行,默认为true。设置为false时需要**小心**:如果执行过程中出错了则不会rollback,数据库很可能处于不一致的状态; - -``下有一个重要的子标签``,即定义回滚的SQL语句。对于`create table`, `rename column`和`add column`等,LiquiBase会自动生成对应的rollback语句,而对于`drop table`、`insert data`等则需要显示定义rollback语句。 - -### include与include-all - -当changelog文件越来越多时,可以使用``将文件管理起来,如: - -```xml - - - - -``` -## Spring-Liquibase配置文件 - -| 属性名 | 说明 | 默认值 | -| ------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------------- | -| spring.liquibase.change-log | 变更日志配置路径 | classpath:/db/changelog/db.changelog-master.
yaml | -| spring.liquibase.check-change-log-location | 检查变更日志位置是否存在 | true | -| spring.liquibase.liquibase.contexts | 要使用的运行时上下文的逗号分隔列表。 | | -| spring.liquibase.default-schema | 默认的数据库Schema | | -| spring.liquibase.drop-first | 先删除数据库Schema | | -| spring.liquibase.enabled | 是否开启liquibase | | -| spring.liquibase.password | 待迁移数据库的登录密码。 | | -| spring.liquibase.url | 待迁移数据库的JDBC URL。如果没有设置,就使用配置的主数据源。 | | -| spring.liquibase.user | 待迁移数据库的登录用户。 | | - diff --git a/uno-starters/uno-starter-liquibase/doc/images/example1.png b/uno-starters/uno-starter-liquibase/doc/images/example1.png deleted file mode 100644 index 36a321762ea57068d0b2b9dcdd609c0cdab6b165..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21797 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 - - - uno-starters - cc.allio - 1.1.5.RELEASE - - 4.0.0 - - uno-starter-liquibase - - - 8 - 8 - - - - - cc.allio - uno-core - - - cc.allio - uno-test - test - - - org.liquibase - liquibase-core - - - - com.alibaba - druid-spring-boot-starter - - - - mysql - mysql-connector-java - provided - - - - org.postgresql - postgresql - provided - - - - com.microsoft.sqlserver - mssql-jdbc - provided - - - com.h2database - h2 - provided - - - com.baomidou - dynamic-datasource-spring-boot-starter - - - \ No newline at end of file diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/BaseLiquibaseDataSourceAdapter.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/BaseLiquibaseDataSourceAdapter.java deleted file mode 100644 index 8c27d54d..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/BaseLiquibaseDataSourceAdapter.java +++ /dev/null @@ -1,143 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import cc.allio.uno.core.util.template.GenericTokenParser; -import cc.allio.uno.core.util.template.Tokenizer; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.ApplicationContext; -import org.springframework.util.StringUtils; - -import javax.sql.DataSource; -import java.io.File; -import java.util.Objects; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * 提高是否有change-log文件的基本适配器 - * - * @author jiangwei - * @date 2022/1/19 20:34 - * @since 1.0 - */ -@Slf4j -public abstract class BaseLiquibaseDataSourceAdapter implements LiquibaseDataSourceAdapter { - - private ApplicationContext applicationContext; - - private static final String XML = ".xml"; - - private static final String YAML = ".yaml"; - - private static final String JSON = ".json"; - - private static final String SQL = ".sql"; - - @Override - public LiquibaseDataSourceAdapter setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - return this; - } - - @Override - public ApplicationContext getApplicationContext() { - return applicationContext; - } - - @Override - public String getChangeLog(DataSource dataSource) { - String propertiesChangeLog = getPropertiesChangeLog(dataSource); - if (!StringUtils.isEmpty(propertiesChangeLog)) { - return propertiesChangeLog; - } - GenericTokenParser parser = getDbParser().apply(dataSource); - String changeLogPath = changeLogPath(dataSource, parser); - String changeLogName = changeLogName(dataSource, parser); - return getMaybeChangeLog(changeLogPath, changeLogName); - } - - /** - * 获取可能的change-log文件路径 - * - * @param changeLogPath change-path - * @param expectedChangeLogName 期望change-log名称,无后缀文件名称 - * @return 某个具体文件路径 - */ - protected String getMaybeChangeLog(String changeLogPath, String expectedChangeLogName) { - String changeLog = changeLog(changeLogPath, expectedChangeLogName.concat(YAML)); - if (!StringUtils.isEmpty(changeLog)) { - return changeLog; - } - changeLog = changeLog(changeLogPath, expectedChangeLogName.concat(XML)); - if (!StringUtils.isEmpty(changeLog)) { - return changeLog; - } - changeLog = changeLog(changeLogPath, expectedChangeLogName.concat(JSON)); - if (!StringUtils.isEmpty(changeLog)) { - return changeLog; - } - changeLog = changeLog(changeLogPath, expectedChangeLogName.concat(SQL)); - if (!StringUtils.isEmpty(changeLog)) { - return changeLog; - } - return ""; - } - - /** - * 获取change-log名称 - * - * @param changeLogPath change-log文件存放的路径 - * @param changeLogName change-log文件具体名称 - * @return 可能能在目标目录找到的change-log文件 - */ - private String changeLog(String changeLogPath, String changeLogName) { - Predicate predicate = hasChangeLogFile(changeLogName); - if (predicate.test(changeLogPath)) { - Function expect = getFile(changeLogName); - File file = expect.apply(changeLogPath); - if (Objects.nonNull(file)) { - return changeLogPath.concat("/").concat(file.getName()); - } - } - return ""; - } - - /** - * 获取change-path路径名称 - * - * @param dataSource 数据源对象 - * @param parser 占位符解析器 - * @return change-log路径名称 - */ - protected String changeLogPath(DataSource dataSource, GenericTokenParser parser) { - return parser.parse(CHANGE_LOG_PATH, content -> dbType(dataSource)); - } - - /** - * 获取change-log文件名称 - * - * @param dataSource 数据源对象 - * @param parser 占位符解析器 - * @return change-log文件名称 - */ - protected String changeLogName(DataSource dataSource, GenericTokenParser parser) { - return parser.parse(CHANGE_LOG_NAME, content -> dbType(dataSource)); - } - - protected Function getDbParser() { - return dataSource -> new GenericTokenParser(Tokenizer.HASH_BRACE); - } - - /** - * 获取配置文件中的change-log路径, - *
    - *
  • 当spring.liquibase.changelog有值则取该路径的change-log
  • - *
  • 否则取db/migrations/#{dbType}/db_migration.yaml
  • - *
- * - * @param dataSource 数据源对象 - * @return 可能存在的change-log路径 - */ - protected String getPropertiesChangeLog(DataSource dataSource) { - return applicationContext.getEnvironment().getProperty("spring.liquibase.changelog"); - } -} diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DataSourceAdapterDispatcher.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DataSourceAdapterDispatcher.java deleted file mode 100644 index 9d520007..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DataSourceAdapterDispatcher.java +++ /dev/null @@ -1,54 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import org.springframework.context.ApplicationContext; - -import javax.sql.DataSource; -import java.util.ArrayList; -import java.util.List; -import java.util.ServiceLoader; - -/** - * 数据源适配处理器,数据源分派 - * - * @author jiangwei - * @date 2022/1/19 18:04 - * @since 1.0 - */ -public class DataSourceAdapterDispatcher { - - /** - * 适配器缓存 - */ - private final List adapters = new ArrayList<>(); - - /** - * 单例 - */ - private static final DataSourceAdapterDispatcher DISPATCHER = new DataSourceAdapterDispatcher(); - - private DataSourceAdapterDispatcher() { - ServiceLoader load = ServiceLoader.load(LiquibaseDataSourceAdapter.class); - for (LiquibaseDataSourceAdapter liquibaseDataSourceAdapter : load) { - adapters.add(liquibaseDataSourceAdapter); - } - } - - /** - * 数据源适配派发 - * - * @param clazz 数据源Class对象 - * @throws NullPointerException 当没有找到合适的适配器时抛出 - */ - public LiquibaseDataSourceAdapter handle(ApplicationContext applicationContext, Class clazz) { - return adapters.stream() - .filter(adapter -> adapter.isAdapter().test(clazz)) - .findFirst() - .orElseThrow(NullPointerException::new) - .setApplicationContext(applicationContext); - } - - public static DataSourceAdapterDispatcher getInstance() { - return DISPATCHER; - } - -} diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapter.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapter.java deleted file mode 100644 index f366045e..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapter.java +++ /dev/null @@ -1,29 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import com.alibaba.druid.pool.DruidDataSource; -import com.google.auto.service.AutoService; - -import javax.sql.DataSource; -import java.util.function.Predicate; - -/** - * Druid数据源适配器 - * - * @author jiangwei - * @date 2022/1/19 18:06 - * @since 1.0 - */ -@AutoService(LiquibaseDataSourceAdapter.class) -public class DruidDataSourceAdapter extends BaseLiquibaseDataSourceAdapter { - - @Override - public String dbType(DataSource dataSource) { - DruidDataSource druidDataSource = (DruidDataSource) dataSource; - return druidDataSource.getDbType(); - } - - @Override - public Predicate> isAdapter() { - return DruidDataSource.class::isAssignableFrom; - } -} diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapter.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapter.java deleted file mode 100644 index 048827ff..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapter.java +++ /dev/null @@ -1,74 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import cc.allio.uno.core.util.template.GenericTokenParser; -import cc.allio.uno.core.util.template.Tokenizer; -import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; -import com.baomidou.dynamic.datasource.ds.ItemDataSource; -import com.google.auto.service.AutoService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.util.ClassUtils; - -import javax.sql.DataSource; -import java.util.Map; -import java.util.function.Predicate; - -/** - * 多数据源适配器 - * - * @author jiangwei - * @date 2022/1/19 21:10 - * @since 1.0 - */ -@Slf4j -@AutoService(LiquibaseDataSourceAdapter.class) -public class DynamicRoutingDataSourceAdapter extends BaseLiquibaseDataSourceAdapter { - - private static final String CHANGE_LOG_PROPERTIES = "spring.datasource.dynamic.datasource.#{dynamic}.liquibase.changelog"; - - @Override - public String dbType(DataSource dataSource) { - ItemDataSource itemDataSource = (ItemDataSource) dataSource; - DataSource realDataSource = itemDataSource.getRealDataSource(); - return DataSourceAdapterDispatcher.getInstance().handle(null, realDataSource.getClass()).dbType(realDataSource); - } - - /** - * @param dataSource 数据源对象 - * @param parser 占位符解析器 - * @return 获取以多数据源的db_migration-#{dynamicType}名称的文件名称 - */ - @Override - protected String changeLogName(DataSource dataSource, GenericTokenParser parser) { - String changeLogName = super.changeLogName(dataSource, parser); - ItemDataSource itemDataSource = (ItemDataSource) dataSource; - return changeLogName.concat("-").concat(itemDataSource.getName()); - } - - @Override - protected String getPropertiesChangeLog(DataSource dataSource) { - ApplicationContext applicationContext = getApplicationContext(); - GenericTokenParser parser = new GenericTokenParser(Tokenizer.HASH_BRACE); - String changeLogProperties = parser.parse(CHANGE_LOG_PROPERTIES, content -> ((ItemDataSource) dataSource).getName()); - return applicationContext.getEnvironment().getProperty(changeLogProperties); - } - - @Override - public void registerLiquibase(DataSource dataSource, DefaultListableBeanFactory beanFactory) { - DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) dataSource; - Map currentDataSources = dynamicRoutingDataSource.getCurrentDataSources(); - currentDataSources.forEach((k, v) -> super.registerLiquibase(v, beanFactory)); - } - - @Override - public Predicate> isAdapter() { - return clazz -> { - boolean present = ClassUtils.isPresent("com.baomidou.dynamic.datasource.DynamicRoutingDataSource", ClassUtils.getDefaultClassLoader()); - if (present) { - return DynamicRoutingDataSource.class.isAssignableFrom(clazz); - } - return false; - }; - } -} diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapter.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapter.java deleted file mode 100644 index 8bf43ab6..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapter.java +++ /dev/null @@ -1,46 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import cc.allio.uno.core.StringPool; -import cc.allio.uno.core.util.StringUtils; -import com.google.auto.service.AutoService; -import com.zaxxer.hikari.HikariDataSource; - -import javax.sql.DataSource; -import java.util.function.Predicate; - -/** - * HikariDataSource数据源适配器 - * - * @author jiangwei - * @date 2022/8/29 13:05 - * @since 1.0.9 - */ -@AutoService(LiquibaseDataSourceAdapter.class) -public class HikariDataSourceAdapter extends BaseLiquibaseDataSourceAdapter { - @Override - public String dbType(DataSource dataSource) { - // org.postgresql.Driver - // com.mysql.cj.jdbc.Driver - // org.h2.Driver - // com.microsoft.sqlserver.jdbc.SQLServerDriver - // oracle.jdbc.driver.OracleDriver - String driverClassName = ((HikariDataSource) dataSource).getDriverClassName(); - if (StringUtils.isEmpty(driverClassName)) { - throw new NullPointerException(String.format("DataSource Driver Class is empty %s", dataSource)); - } - String maybeDriverClassName = driverClassName.split(StringPool.DOT)[1]; - - // sqlserver做特殊处理 - if (maybeDriverClassName.equals("microsoft")) { - return "mssql"; - } else if (maybeDriverClassName.equals("jdbc")) { - return "oracle"; - } - return maybeDriverClassName; - } - - @Override - public Predicate> isAdapter() { - return HikariDataSource.class::isAssignableFrom; - } -} diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/LiquibaseDataSourceAdapter.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/LiquibaseDataSourceAdapter.java deleted file mode 100644 index 8452548a..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/LiquibaseDataSourceAdapter.java +++ /dev/null @@ -1,153 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import liquibase.integration.spring.SpringLiquibase; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ResourceUtils; -import org.springframework.util.StringUtils; - -import javax.sql.DataSource; -import java.io.File; -import java.io.FileNotFoundException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -/** - * Liquibase适配器,对于不同的数据源类型来创建Liquibase对象 - * - * @author jiangwei - * @date 2022/1/19 16:28 - * @since 1.0 - */ -public interface LiquibaseDataSourceAdapter { - - /** - * change-log配置文件的目录 - */ - String CHANGE_LOG_PATH = "classpath:db/migrations/#{dbType}"; - - /** - * change-log文件名称 - */ - String CHANGE_LOG_NAME = "db_migration"; - - /** - * 获取change-log文件路径。
- * 默认优先级顺序:db_migration_#{dbType}(或者db_migration_#{dbType}-#{dynamic})>.yaml>.yml>.xml - * - * @param dataSource 数据源对象 - * @return change-log文件目录 - * @see BaseLiquibaseDataSourceAdapter - */ - String getChangeLog(DataSource dataSource); - - /** - * 获取dbType - * - * @param dataSource 数据源对象 - * @return dbType字符串 - */ - String dbType(DataSource dataSource); - - /** - * 测试当前数据源适配器是否可以适配 - * - * @return 返回一个断言对象 - */ - Predicate> isAdapter(); - - /** - * 设置application实例 - * - * @param applicationContext 上下文实例 - * @return 当前实例 - */ - LiquibaseDataSourceAdapter setApplicationContext(ApplicationContext applicationContext); - - /** - * 获取ApplicationContext上下文 - * - * @return application上下文实例 - */ - ApplicationContext getApplicationContext(); - - // ---------------- default ---------------- - - /** - * 获取指定目录下的所以文件 - * - * @return 入参为文件路径,获取文件List - */ - default Function> getFiles() { - return path -> { - try { - File changeFile = ResourceUtils.getFile(path); - // 判断边界条件 - File[] listableFile = changeFile.listFiles(); - if (ObjectUtils.isEmpty(listableFile)) { - return Collections.emptyList(); - } - return Arrays.stream(listableFile) - .filter(File::isFile) - .collect(Collectors.toList()); - } catch (FileNotFoundException e) { - return Collections.emptyList(); - } - }; - } - - /** - * 根据文件目录判断目标路径存在有change-log文件:
- * 1.判断是否有目录
- * 2.如果有目录,判断目录下是否有以db_migration.yaml或者db_migration.xml或者db_migration.json为文件名
- * - * @param maybeName change-log文件名称或者.yaml文件 - * @return 返回一个断言对象 - * @see BaseLiquibaseDataSourceAdapter - * @see DynamicRoutingDataSourceAdapter - */ - default Predicate hasChangeLogFile(String maybeName) { - return path -> - getFiles().apply(path) - .stream() - .anyMatch(file -> file.getName().equals(maybeName)); - } - - /** - * 获取文件,调用{@link String#contains(CharSequence)}方法进行判断。 - * - * @param expectedFileName 期望获取的文件名称,可能不是具体文件名称。 - * @return 以文件路径作为入参,获取具体文件(当找不到时返回null) - */ - default Function getFile(String expectedFileName) { - return path -> getFiles().apply(path) - .stream() - .filter(file -> file.getName().equals(expectedFileName)) - .findFirst() - .orElse(null); - } - - /** - * 向Spring注册Liquibase对象 - * - * @param dataSource 数据源对象 - * @param beanFactory bean工厂 - */ - default void registerLiquibase(DataSource dataSource, DefaultListableBeanFactory beanFactory) { - String changeLog = getChangeLog(dataSource); - if (StringUtils.isEmpty(changeLog)) { - return; - } - SpringLiquibase liquibase = new SpringLiquibase(); - liquibase.setChangeLog(changeLog); - liquibase.setDataSource(dataSource); - BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(SpringLiquibase.class, () -> liquibase); - beanFactory.registerBeanDefinition("liquibase-".concat(dbType(dataSource)), beanDefinitionBuilder.getRawBeanDefinition()); - } -} diff --git a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/config/UnoLiquibaseAutoConfiguration.java b/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/config/UnoLiquibaseAutoConfiguration.java deleted file mode 100644 index 5eda6b5a..00000000 --- a/uno-starters/uno-starter-liquibase/src/main/java/cc/allio/uno/starter/liquibase/config/UnoLiquibaseAutoConfiguration.java +++ /dev/null @@ -1,83 +0,0 @@ -package cc.allio.uno.starter.liquibase.config; - -import cc.allio.uno.starter.liquibase.DataSourceAdapterDispatcher; -import liquibase.integration.spring.SpringLiquibase; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; -import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.util.CollectionUtils; - -import javax.sql.DataSource; -import java.util.Map; - -/** - * Blade-Liquibase自动配置类。
- *
    - *
  1. 扫描在/db/migrations/#{dbType}目录下是否存在db_migration格式的文件
  2. - *
  3. 代码逻辑将会根据当前服务数据源的配置创建Liquibase对象。
  4. - *
  5. 如果当前项目配置多数据源,需要在db_migration-#{dynamic}。以此适配多数据源
  6. - *
- * - * @author jiangwei - * @date 2022/1/19 10:47 - * @since 1.0 - */ -@Slf4j -@EnableAutoConfiguration -@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", havingValue = "true") -@AutoConfigureBefore({LiquibaseAutoConfiguration.class}) -@AutoConfigureAfter({DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) -@Order(Ordered.HIGHEST_PRECEDENCE) -public class UnoLiquibaseAutoConfiguration implements ApplicationContextAware, InitializingBean { - - private ApplicationContext applicationContext; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void afterPropertiesSet() throws Exception { - ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext; - DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory(); - Map dataSourceMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, DataSource.class); - if (CollectionUtils.isEmpty(dataSourceMap)) { - return; - } - if (dataSourceMap.size() == 1) { - DataSource dataSource = applicationContext.getBean(DataSource.class); - try { - DataSourceAdapterDispatcher.getInstance().handle(applicationContext, dataSource.getClass()).registerLiquibase(dataSource, beanFactory); - } catch (Throwable e) { - log.error("register liquibase failed", e); - } - - } else { - dataSourceMap.forEach((k, v) -> { - try { - DataSourceAdapterDispatcher.getInstance().handle(applicationContext, v.getClass()).registerLiquibase(v, beanFactory); - } catch (Throwable e) { - log.error("register liquibase failed", e); - } - }); - } - // 使注册的Liquibase生效 - BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, SpringLiquibase.class); - } - -} diff --git a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapterTest.java b/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapterTest.java deleted file mode 100644 index 38dd4511..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DruidDataSourceAdapterTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import com.alibaba.druid.pool.DruidDataSource; -import cc.allio.uno.core.util.template.GenericTokenParser; -import cc.allio.uno.test.BaseTestCase; -import org.junit.jupiter.api.Test; - -class DruidDataSourceAdapterTest extends BaseTestCase { - - DruidDataSource dataSource; - - DruidDataSourceAdapter adapter; - - @Override - protected void onInit() throws Throwable { - dataSource = new DruidDataSource(); - dataSource.setDbType("postgres"); - adapter = new DruidDataSourceAdapter(); - } - - @Test - void testDbType() { - String dbType = adapter.dbType(dataSource); - assertEquals("postgres", dbType); - } - - @Test - void testChangeFilePath() { - GenericTokenParser parser = adapter.getDbParser().apply(dataSource); - String changeLogPath = adapter.changeLogPath(dataSource, parser); - assertEquals("classpath:db/migrations/postgres", changeLogPath); - } - - @Test - void testChangeFileName() { - GenericTokenParser parser = adapter.getDbParser().apply(dataSource); - String changeLogName = adapter.changeLogName(dataSource, parser); - assertEquals("db_migration", changeLogName); - } - - @Test - void testGetChangeLog() { - assertEquals("classpath:db/migrations/postgres/db_migration.yaml", adapter.getChangeLog(dataSource)); - } - - @Override - protected void onDown() throws Throwable { - } -} diff --git a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapterTest.java b/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapterTest.java deleted file mode 100644 index 0804faf4..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/DynamicRoutingDataSourceAdapterTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import com.alibaba.druid.pool.DruidDataSource; -import cc.allio.uno.core.util.template.GenericTokenParser; -import cc.allio.uno.test.BaseTestCase; -import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; -import com.baomidou.dynamic.datasource.ds.ItemDataSource; -import com.baomidou.dynamic.datasource.enums.SeataMode; -import org.junit.jupiter.api.Test; - -class DynamicRoutingDataSourceAdapterTest extends BaseTestCase { - - DynamicRoutingDataSource dataSource; - - DynamicRoutingDataSourceAdapter adapter; - - ItemDataSource master; - - ItemDataSource second; - - @Override - protected void onInit() throws Throwable { - dataSource = new DynamicRoutingDataSource(); - DruidDataSource masterDruidDataSource = new DruidDataSource(); - masterDruidDataSource.setDbType("postgres"); - master = new ItemDataSource("master", masterDruidDataSource, masterDruidDataSource, false, false, SeataMode.AT); - dataSource.addDataSource("master", master); - DruidDataSource secondDruidDataSource = new DruidDataSource(); - secondDruidDataSource.setDbType("mysql"); - second = new ItemDataSource("second", secondDruidDataSource, secondDruidDataSource, false, false, SeataMode.AT); - dataSource.addDataSource("second", second); - adapter = new DynamicRoutingDataSourceAdapter(); - } - - @Test - void testDbType() { - assertEquals("postgres", adapter.dbType(master)); - assertEquals("mysql", adapter.dbType(second)); - } - - @Test - void testChangeFilePath() { - GenericTokenParser masterParser = adapter.getDbParser().apply(master); - assertEquals("classpath:db/migrations/postgres", adapter.changeLogPath(master, masterParser)); - GenericTokenParser secondParser = adapter.getDbParser().apply(second); - assertEquals("classpath:db/migrations/mysql", adapter.changeLogPath(second, secondParser)); - } - - @Test - void testChangeName() { - GenericTokenParser masterParser = adapter.getDbParser().apply(master); - assertEquals("db_migration-master", adapter.changeLogName(master, masterParser)); - GenericTokenParser secondParser = adapter.getDbParser().apply(second); - assertEquals("db_migration-second", adapter.changeLogName(second, secondParser)); - } - - @Test - void testGetChangeLog() { - assertEquals("classpath:db/migrations/postgres/db_migration-master.yaml", adapter.getChangeLog(master)); - assertEquals("classpath:db/migrations/mysql/db_migration-second.yaml", adapter.getChangeLog(second)); - } - - @Override - protected void onDown() throws Throwable { - - } -} diff --git a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapterTest.java b/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapterTest.java deleted file mode 100644 index f83658ab..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/HikariDataSourceAdapterTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import cc.allio.uno.test.BaseTestCase; -import com.microsoft.sqlserver.jdbc.SQLServerDriver; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.jupiter.api.Test; -import org.postgresql.Driver; - -/** - * HikariDataSource测试 - * - * @author jiangwei - * @date 2022/8/29 13:46 - * @since 1.0.9 - */ -class HikariDataSourceAdapterTest extends BaseTestCase { - - - @Override - protected void onInit() throws Throwable { - - } - - @Override - protected void onDown() throws Throwable { - - } - - @Test - void testDbType() { - HikariDataSourceAdapter dataSourceAdapter = new HikariDataSourceAdapter(); - HikariDataSource hikariDataSource = new HikariDataSource(); - hikariDataSource.setDriverClassName(com.mysql.cj.jdbc.Driver.class.getName()); - - // 验证mysql - String dbType = dataSourceAdapter.dbType(hikariDataSource); - assertEquals("mysql", dbType); - - // 验证Postgresql - hikariDataSource.setDriverClassName(Driver.class.getName()); - dbType = dataSourceAdapter.dbType(hikariDataSource); - assertEquals("postgresql", dbType); - - // 验证h2 - hikariDataSource.setDriverClassName(org.h2.Driver.class.getName()); - dbType = dataSourceAdapter.dbType(hikariDataSource); - assertEquals("h2", dbType); - - // sqlserver - hikariDataSource.setDriverClassName(SQLServerDriver.class.getName()); - dbType = dataSourceAdapter.dbType(hikariDataSource); - assertEquals("mssql", dbType); - } -} diff --git a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/MigrationTest.java b/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/MigrationTest.java deleted file mode 100644 index 382d9b13..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/MigrationTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.allio.uno.starter.liquibase; - -import cc.allio.uno.starter.liquibase.config.UnoLiquibaseAutoConfiguration; -import cc.allio.uno.test.CoreTest; -import cc.allio.uno.test.env.Environment; -import liquibase.integration.spring.SpringLiquibase; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; - -import javax.sql.DataSource; -import java.util.Map; - -/** - * 迁移单元测试 - * - * @author jiangwei - * @date 2022/8/29 11:20 - * @since 1.0.9 - */ -public class MigrationTest extends CoreTest { - - @Override - protected void onEnvBuild() { - registerComponent( - UnoLiquibaseAutoConfiguration.class, - DataSourceAutoConfiguration.class - ); - } - - @Override - public Environment supportEnv() { - // TODO 更改测试类 -// DataSourceProperties dataSourceProperties = new DataSourceProperties(); -// dataSourceProperties.setDriverClassName("com.mysql.cj.jdbc.Driver"); -// dataSourceProperties.setUrl("jdbc:mysql://192.168.2.29:3306/migration?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true"); -// dataSourceProperties.setUsername("root"); -// dataSourceProperties.setPassword("123456"); -// return new EnvironmentFacade(new DataSourceEnvironment(dataSourceProperties)); - return null; - } - - @Override - protected void onRefreshComplete() throws Throwable { - - } - - @Override - protected void onContextClose() throws Throwable { - - } - - /** - * Test Case: 测试数据源与Liquibase的数量 - */ - @Test - void testSpringLiquibaseSize() { - Map dataSourceMap = getContext().getBeansOfType(DataSource.class); - Map liquibaseMap = getContext().getBeansOfType(SpringLiquibase.class); - assertEquals(dataSourceMap.size(), liquibaseMap.size()); - } - -} diff --git a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/changetask/TestChangeTask.java b/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/changetask/TestChangeTask.java deleted file mode 100644 index c21f3971..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/java/cc/allio/uno/starter/liquibase/changetask/TestChangeTask.java +++ /dev/null @@ -1,34 +0,0 @@ -package cc.allio.uno.starter.liquibase.changetask; - -import liquibase.change.custom.CustomTaskChange; -import liquibase.database.Database; -import liquibase.exception.CustomChangeException; -import liquibase.exception.SetupException; -import liquibase.exception.ValidationErrors; -import liquibase.resource.ResourceAccessor; - -public class TestChangeTask implements CustomTaskChange { - @Override - public void execute(Database database) throws CustomChangeException { - } - - @Override - public String getConfirmationMessage() { - return null; - } - - @Override - public void setUp() throws SetupException { - - } - - @Override - public void setFileOpener(ResourceAccessor resourceAccessor) { - - } - - @Override - public ValidationErrors validate(Database database) { - return null; - } -} diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration-second.yaml b/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration-second.yaml deleted file mode 100644 index e69de29b..00000000 diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration.yaml b/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration.yaml deleted file mode 100644 index 35a31c89..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/db_migration.yaml +++ /dev/null @@ -1,17 +0,0 @@ -databaseChangeLog: - # 一次数据库版本变化都是一个变更集 - - changeSet: - # 命名规则:框架(系统名)-服务-版本号-功能(或者目的) - id: jw-test-V1-Person - author: jiangwei - comment: 创建Person表 - runInTransaction: true - changes: - # 创建表结构 - - sqlFile: - path: classpath:db/migrations/mysql/sql/V1__Person.sql - encoding: utf8 - # 创建表数据 - - sqlFile: - path: classpath:db/migrations/mysql/sql/V1__Person_Data.sql - encoding: utf8 diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person.sql b/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person.sql deleted file mode 100644 index 21b2146a..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE `person` -( - `id` int(11) NOT NULL, - `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, - PRIMARY KEY (`id`) -) \ No newline at end of file diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person_Data.sql b/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person_Data.sql deleted file mode 100644 index e6a41c85..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/mysql/sql/V1__Person_Data.sql +++ /dev/null @@ -1 +0,0 @@ -INSERT INTO person(id, name) VALUES (1, 'test') \ No newline at end of file diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/postgres/db_migration-master.yaml b/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/postgres/db_migration-master.yaml deleted file mode 100644 index e69de29b..00000000 diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/postgres/db_migration.yaml b/uno-starters/uno-starter-liquibase/src/test/resources/db/migrations/postgres/db_migration.yaml deleted file mode 100644 index e69de29b..00000000 diff --git a/uno-starters/uno-starter-liquibase/src/test/resources/uno.yaml b/uno-starters/uno-starter-liquibase/src/test/resources/uno.yaml deleted file mode 100644 index 2b52649e..00000000 --- a/uno-starters/uno-starter-liquibase/src/test/resources/uno.yaml +++ /dev/null @@ -1,4 +0,0 @@ -spring: - liquibase: - enabled: true - changelog: classpath:db/migrations/mysql/db_migration.yaml \ No newline at end of file diff --git a/uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignClientProperties.java b/uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignClientProperties.java deleted file mode 100644 index d8e911c9..00000000 --- a/uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignClientProperties.java +++ /dev/null @@ -1,24 +0,0 @@ -package cc.allio.uno.test.env.annotation.properties; - -import java.lang.annotation.*; - -/** - * {@link org.springframework.cloud.openfeign.FeignClientProperties}的注解描述 - * - * @author jiangwei - * @date 2023/3/9 12:08 - * @since 1.1.4 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Properties("feign.client") -public @interface FeignClientProperties { - - boolean defaultToProperties() default true; - - String defaultConfig() default "default"; - - boolean decodeSlash() default true; - -} diff --git a/uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignEncoderProperties.java b/uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignEncoderProperties.java deleted file mode 100644 index fd8581e2..00000000 --- a/uno-test/src/main/java/cc/allio/uno/test/env/annotation/properties/FeignEncoderProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -package cc.allio.uno.test.env.annotation.properties; - -import java.lang.annotation.*; - -/** - * {@link org.springframework.cloud.openfeign.support.FeignEncoderProperties}的注解描述 - * - * @author jiangwei - * @date 2023/3/9 12:40 - * @since 1.1.4 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Properties("feign.encoder") -public @interface FeignEncoderProperties { - - /** - * Indicates whether the charset should be derived from the Content-Type header. - */ - boolean charsetFromContentType() default false; -} diff --git a/uno-test/src/test/java/cc/allio/uno/test/annotation/MybatisEnvTest.java b/uno-test/src/test/java/cc/allio/uno/test/annotation/MybatisEnvTest.java index 85081fd6..b2f95cda 100644 --- a/uno-test/src/test/java/cc/allio/uno/test/annotation/MybatisEnvTest.java +++ b/uno-test/src/test/java/cc/allio/uno/test/annotation/MybatisEnvTest.java @@ -3,12 +3,11 @@ import cc.allio.uno.test.Inject; import cc.allio.uno.test.env.annotation.MybatisEnv; import cc.allio.uno.test.RunTest; +import jakarta.annotation.Resource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import javax.annotation.Resource; - @RunTest @MybatisEnv public class MybatisEnvTest {