From 19fb15bd03e544218e33850766bf7003a603c7a6 Mon Sep 17 00:00:00 2001 From: yhl452493373 Date: Mon, 14 Feb 2022 16:23:24 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81Generator=E4=B8=AD=E5=8D=A0=E4=BD=8D?= =?UTF-8?q?=E7=AC=A6=E9=83=A8=E5=88=86=E8=BD=AC=E5=88=B0FormatPlaceholder?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E4=B8=AD=EF=BC=8C=E8=A7=84=E8=8C=83=E5=85=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=202=E3=80=81SequencesGenerator=E4=B8=AD?= =?UTF-8?q?=EF=BC=8C=E5=9F=BA=E7=A1=80=E9=85=8D=E7=BD=AE=E8=BD=AC=E5=88=B0?= =?UTF-8?q?BaseConfig=EF=BC=8C=E8=AF=A5=E7=B1=BB=E4=B8=BA=E5=8D=95?= =?UTF-8?q?=E4=BE=8B=EF=BC=8C=E4=BE=BF=E4=BA=8E=E5=85=B6=E4=BB=96=E5=9C=B0?= =?UTF-8?q?=E6=96=B9=E8=B0=83=E7=94=A8=203=E3=80=81Generator=E4=B8=AD?= =?UTF-8?q?=EF=BC=8Cformat=E6=96=B9=E6=B3=95=E9=87=8D=E6=9E=84=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=8D=E9=9C=80=E8=A6=81minLength=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E6=96=B9=E6=B3=95=EF=BC=8CminLength=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BB=8EBaseConfig=E5=8D=95=E4=BE=8B=E4=B8=AD?= =?UTF-8?q?=E6=88=96=204=E3=80=81Sequences=E4=B8=AD=EF=BC=8Cformat?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E9=87=8D=E6=9E=84=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=B8=8D=E9=9C=80=E8=A6=81minLength=E5=8F=82=E6=95=B0=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8CminLength=E5=8F=82=E6=95=B0=E4=BB=8E?= =?UTF-8?q?BaseConfig=E5=8D=95=E4=BE=8B=E4=B8=AD=E6=88=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 142 +++++++++------ pom.xml | 2 +- .../yanghuanglin/seq/config/BaseConfig.java | 170 ++++++++++++++++++ .../seq/config/GeneratorConfig.java | 13 ++ .../seq/enums/FormatPlaceholder.java | 62 +++++++ .../yanghuanglin/seq/generator/Generator.java | 71 +++++--- .../generator/impl/SequencesGenerator.java | 102 ++++++----- .../com/yanghuanglin/seq/po/Sequences.java | 15 +- src/test/java/SeqTest.java | 10 +- 9 files changed, 454 insertions(+), 133 deletions(-) create mode 100644 src/main/java/com/yanghuanglin/seq/config/BaseConfig.java create mode 100644 src/main/java/com/yanghuanglin/seq/enums/FormatPlaceholder.java diff --git a/README.md b/README.md index 2690928..2f5b14e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 使用方法: -+ 在项目中放置jar包的地方把seq-1.3.1.jar、seq-1.3.1-sources.jar、seq-1.3.1-pom.xml复制过去 ++ 在项目中放置jar包的地方把seq-1.4.1.jar、seq-1.4.1-sources.jar、seq-1.4.1-pom.xml复制过去 + 在pom.xml中增加以下内容,然后执行maven命令:mvn clean ```xml @@ -18,7 +18,7 @@ com.yanghuanglin seq - 1.3.1 + 1.4.1 @@ -50,13 +50,13 @@ - ${project.basedir}/lib/seq-1.3.1.jar - ${pom.basedir}/lib/seq-1.3.1-pom.xml - ${project.basedir}/lib/seq-1.3.1-sources.jar + ${project.basedir}/lib/seq-1.4.1.jar + ${pom.basedir}/lib/seq-1.4.1-pom.xml + ${project.basedir}/lib/seq-1.4.1-sources.jar default com.yanghuanglin seq - 1.3.1 + 1.4.1 jar true @@ -71,10 +71,10 @@ + springboot中配置方式一(优先):直接注入已有jdbcTemplate和transactionTemplate ```java -package com.yanghuanglin.springseq.config; +package com.yanghuanglin.springseq.baseConfig; -import com.yanghuanglin.seq.config.GeneratorConfig; -import com.yanghuanglin.seq.config.TableConfig; +import com.yanghuanglin.seq.baseConfig.GeneratorConfig; +import com.yanghuanglin.seq.baseConfig.TableConfig; import com.yanghuanglin.seq.generator.Generator; import com.yanghuanglin.seq.generator.impl.SequencesGenerator; import org.springframework.context.annotation.Bean; @@ -107,11 +107,11 @@ public class SeqGeneratorConfig { public TableConfig tableConfig() { TableConfig tableConfig = new TableConfig(); //自定义表名、字段名 - //tableConfig.setTable("sequences"); - //tableConfig.setKeyColumn("SEQUENCE_KEY"); - //tableConfig.setTypeColumn("SEQUENCE_TYPE"); - //tableConfig.setSeqColumn("SEQUENCE_NEXT_ID"); - //tableConfig.setCreateTimeColumn("CREATE_TIME"); + tableConfig.setTable("sequences"); + tableConfig.setKeyColumn("SEQUENCE_KEY"); + tableConfig.setTypeColumn("SEQUENCE_TYPE"); + tableConfig.setSeqColumn("NEXT_ID"); + tableConfig.setCreateTimeColumn("CREATE_TIME"); return tableConfig; } @@ -142,10 +142,10 @@ public class SeqGeneratorConfig { + springboot中配置方式二:注入已有的dataSource或自行构建dataSource,通过dataSource自动生成jdbcTemplate和transactionTemplate ```java -package com.yanghuanglin.springseq.config; +package com.yanghuanglin.springseq.baseConfig; -import com.yanghuanglin.seq.config.GeneratorConfig; -import com.yanghuanglin.seq.config.TableConfig; +import com.yanghuanglin.seq.baseConfig.GeneratorConfig; +import com.yanghuanglin.seq.baseConfig.TableConfig; import com.yanghuanglin.seq.generator.Generator; import com.yanghuanglin.seq.generator.impl.SequencesGenerator; import org.springframework.context.annotation.Bean; @@ -172,11 +172,11 @@ public class SeqGeneratorConfig { public TableConfig tableConfig() { TableConfig tableConfig = new TableConfig(); //自定义表名、字段名 - //tableConfig.setTable("sequences"); - //tableConfig.setKeyColumn("SEQUENCE_KEY"); - //tableConfig.setTypeColumn("SEQUENCE_TYPE"); - //tableConfig.setSeqColumn("SEQUENCE_NEXT_ID"); - //tableConfig.setCreateTimeColumn("CREATE_TIME"); + tableConfig.setTable("sequences"); + tableConfig.setKeyColumn("SEQUENCE_KEY"); + tableConfig.setTypeColumn("SEQUENCE_TYPE"); + tableConfig.setSeqColumn("NEXT_ID"); + tableConfig.setCreateTimeColumn("CREATE_TIME"); return tableConfig; } @@ -184,6 +184,7 @@ public class SeqGeneratorConfig { * 序号生成器配置类 * @param tableConfig 序号表配置类 */ + @DependsOn("tableConfig") @Bean public GeneratorConfig generatorConfig(TableConfig tableConfig) { GeneratorConfig generatorConfig = new GeneratorConfig(); @@ -195,6 +196,7 @@ public class SeqGeneratorConfig { * 注册序号生成器类 * @param generatorConfig 序号生成器配置类 */ + @DependsOn("generatorConfig") @Bean public Generator generator(GeneratorConfig generatorConfig) { return new SequencesGenerator(generatorConfig); @@ -205,7 +207,7 @@ public class SeqGeneratorConfig { + 使用: ```java -package com.yanghuanglin.springseq.config; +package com.yanghuanglin.springseq.baseConfig; import com.yanghuanglin.seq.generator.Generator; import com.yanghuanglin.seq.po.Sequences; @@ -271,19 +273,20 @@ TableConfig配置项,通过set方法设置(一般不用改,如果已有相 GeneratorConfig配置项,通过set方法设置 -| 配置项 | 类型 | 默认值 | 说明 | -|---------------------|------------------------------------------------------------------|------------------|----------| -| dataSource | javax.sql.DataSource | null | 数据源 | -| jdbcTemplate | org.springframework.jdbc.core.JdbcTemplate | null | 数据库操作模板 | -| transactionTemplate | org.springframework.jdbc.core.JdbcTemplate | null | 事务操作模板 | -| transactionManager | org.springframework.jdbc.datasource.DataSourceTransactionManager | null | 事务管理器 | -| autoCreate | Boolean | true | 开启自动建表 | -| step | Integer | 1 | 序号增加时的步长 | -| type | String | DEFAULT | 默认序号类型 | -| tableConfig | com.yanghuanglin.seq.config.TableConfig | TableConfig的默认配置 | 表配置 | +| 配置项 | 类型 | 默认值 | 说明 | +|---------------------|------------------------------------------------------------------|------------------|------------------| +| dataSource | javax.sql.DataSource | null | 数据源 | +| jdbcTemplate | org.springframework.jdbc.core.JdbcTemplate | null | 数据库操作模板 | +| transactionTemplate | org.springframework.jdbc.core.JdbcTemplate | null | 事务操作模板 | +| transactionManager | org.springframework.jdbc.datasource.DataSourceTransactionManager | null | 事务管理器 | +| autoCreate | Boolean | true | 开启自动建表 | +| step | Integer | 1 | 序号增加时的步长 | +| type | String | DEFAULT | 默认序号类型 | +| minLength | Integer | 1 | 默认序号格式化后长度,不足的补零 | +| tableConfig | com.yanghuanglin.seq.baseConfig.TableConfig | TableConfig的默认配置 | 表配置 | 以上配置中,jdbcTemplate和transactionTemplate优先级最高,如果jdbcTemplate、transactionTemplate、dataSource、transactionManager同时配置,则dataSource和transactionManager无效; -进行这几种组合:dataSource+autoCreate+step+tableConfig,jdbcTemplate+transactionTemplate+autoCreate+step+tableConfig,jdbcTemplate+transactionManager+autoCreate+step+tableConfig +可进行这几种组合:dataSource+autoCreate+step+minLength+tableConfig,jdbcTemplate+transactionTemplate+autoCreate+step+minLength+tableConfig,jdbcTemplate+transactionManager+autoCreate+step+minLength+tableConfig --- Generator方法如下: @@ -291,7 +294,9 @@ Generator方法如下: ```java package com.yanghuanglin.seq.generator; +import com.yanghuanglin.seq.config.BaseConfig; import com.yanghuanglin.seq.config.GeneratorConfig; +import com.yanghuanglin.seq.enums.FormatPlaceholder; import com.yanghuanglin.seq.po.Sequences; import com.yanghuanglin.seq.po.SequencesUnlock; import com.yanghuanglin.seq.po.SequencesUnused; @@ -299,23 +304,6 @@ import com.yanghuanglin.seq.po.SequencesUnused; import java.util.Date; public interface Generator { - /** - * 序号格式字符中的年 - */ - String YEAR = "#year#"; - /** - * 序号格式字符中的月 - */ - String MONTH = "#month#"; - /** - * 序号格式字符中的日 - */ - String DAY = "#day#"; - /** - * 序号格式字符中的格式化后的序号 - */ - String SEQ = "#seq#"; - /** * 根据传入的key和type生成可用的序号对象。 *

@@ -324,7 +312,7 @@ public interface Generator { * 如果根据key和默认的{@link GeneratorConfig#getType()}在{@link Sequences}中找到了记录,且在{@link SequencesUnused}也找到了记录,说明该组合生成的序号有部分未使用,返回的是{@link SequencesUnused}中找到的seq最小的序号对象。同时会将{@link SequencesUnused}中找到的seq最小的记录删除,然后写入到{@link SequencesUnlock}中。 *

* - * @param key 数据字典中的编码 + * @param key 数据字典中的编码 * @return 可用的序号对象 */ Sequences generate(String key); @@ -355,8 +343,21 @@ public interface Generator { */ String generate(String key, String type, Integer minLength); + /** + * 将{@link #generate(String, String)}得到的序号对象格式化为补零后的序号字符串,其最小长度通过{@link BaseConfig#getMinLength()}设定。实际上只会用到{@link Sequences#getSeq()}属性 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 + * + * @param sequences 生成的序号对象 + * @param pattern 格式 + * @return 格式化后的字符串 + */ + String format(Sequences sequences, String pattern); + /** * 将{@link #generate(String, String)}得到的序号对象格式化为补零后的序号字符串。实际上只会用到{@link Sequences#getSeq()}属性 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 * * @param sequences 生成的序号对象 * @param minLength 序号数字最小长度 @@ -365,10 +366,25 @@ public interface Generator { */ String format(Sequences sequences, Integer minLength, String pattern); + /** + * 将生成的序号对象格式化为指定格式,格式化后字符串最小长度为{@link BaseConfig#getMinLength()},不足则补零 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR#getPlaceholder()}(当前年份)、{@link FormatPlaceholder#MONTH#getPlaceholder()}(当前月份)、{@link FormatPlaceholder#DAY#getPlaceholder()}(当前日期)、{@link FormatPlaceholder#SEQ#getPlaceholder()}(生成的字符串序号)四个变量 + *

+ * seq为1,pattern为#year##month##day#6#seq#,则会格式化为2022013061。此序号含义如下: + *

+ * 序号格式:[年][月][日][固定6开头][序号1,最小位数为{@link BaseConfig#getMinLength()}设置,默认为1,不足则补零] + * + * @param seq 需要格式化的序号 + * @param pattern 格式 + * @return 格式化后的序号字符串 + */ + String format(Long seq, String pattern); + /** * 将生成的序号对象格式化为指定格式 *

- * pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量 + * pattern支持:{@link FormatPlaceholder#YEAR}}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 *

* seq为1,minLength为4,pattern为#year##month##day#6#seq#,则会格式化为2022013060001。此序号含义如下: *

@@ -381,10 +397,26 @@ public interface Generator { */ String format(Long seq, Integer minLength, String pattern); + /** + * 将生成的序号对象格式化为指定格式,格式化后字符串最小长度为{@link BaseConfig#getMinLength()},不足则补零 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 + *

+ * seq为1,start为6,minLength为4,pattern为#year##month##day##seq#,则会格式化为2022013061。此序号含义如下: + *

+ * 序号格式:[年][月][日][固定6开头][序号1,最小位数为{@link BaseConfig#getMinLength()}设置,默认为1,不足则补零] + * + * @param seq 需要格式化的序号 + * @param start 序号格式化后以什么字符串开头 + * @param pattern 序号格式 + * @return 格式化后的序号字符串 + */ + String format(Long seq, String start, String pattern); + /** * 将生成的序号对象格式化为指定格式 *

- * pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量 + * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 *

* seq为1,start为6,minLength为4,pattern为#year##month##day##seq#,则会格式化为2022013060001。此序号含义如下: *

@@ -401,6 +433,8 @@ public interface Generator { /** * 将已格式化的序号解析为序号对象 *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 + *

* 返回的序号对象{@link Sequences#getKey()}为null,{@link Sequences#getType()}为{@link GeneratorConfig#getType()}的默认值,但是临时字段{@link Sequences#getYear()}、{@link Sequences#getMonth()}、{@link Sequences#getDay()}可能有值 *

* 如果生成序号时,序号的key在年、月、日上有关联(如每年每月的序号要从1开始),则需要自行用序号字符串与{@link Sequences#getYear()}、{@link Sequences#getMonth()}、{@link Sequences#getDay()}进行组合,进而得到key diff --git a/pom.xml b/pom.xml index faca844..4e82545 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.yanghuanglin seq - 1.3.1 + 1.4.1 seq seq diff --git a/src/main/java/com/yanghuanglin/seq/config/BaseConfig.java b/src/main/java/com/yanghuanglin/seq/config/BaseConfig.java new file mode 100644 index 0000000..143697f --- /dev/null +++ b/src/main/java/com/yanghuanglin/seq/config/BaseConfig.java @@ -0,0 +1,170 @@ +package com.yanghuanglin.seq.config; + +import com.yanghuanglin.seq.dao.SequencesDao; +import com.yanghuanglin.seq.dao.SequencesUnlockDao; +import com.yanghuanglin.seq.dao.SequencesUnusedDao; +import com.yanghuanglin.seq.dao.impl.SequencesDaoImpl; +import com.yanghuanglin.seq.dao.impl.SequencesUnlockDaoImpl; +import com.yanghuanglin.seq.dao.impl.SequencesUnusedDaoImpl; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.sql.DataSource; + +/** + * 生成器最后的基础配置信息,单例模式,便于其他地方调用 + * + * @author yanghuanglin + * @since 2022/2/14 + */ +public class BaseConfig { + private static volatile BaseConfig instance; + + private TransactionTemplate transactionTemplate; + private SequencesDao sequencesDao; + private SequencesUnusedDao sequencesUnusedDao; + private SequencesUnlockDao sequencesUnlockDao; + private Integer step; + private String type; + private Integer minLength; + + private BaseConfig() { + } + + public static BaseConfig getInstance() { + if (instance == null) { + synchronized (BaseConfig.class) { + if (instance == null) { + instance = new BaseConfig(); + } + } + } + return instance; + } + + public static BaseConfig getInstance(GeneratorConfig generatorConfig) { + if (instance == null) { + synchronized (BaseConfig.class) { + if (instance == null) { + instance = new BaseConfig(); + } + } + } + instance.init(generatorConfig); + return instance; + } + + public static void setInstance(BaseConfig instance) { + BaseConfig.instance = instance; + } + + public TransactionTemplate getTransactionTemplate() { + if (transactionTemplate == null) + throw new NullPointerException("请先初始化BaseConfig"); + return transactionTemplate; + } + + public void setTransactionTemplate(TransactionTemplate transactionTemplate) { + this.transactionTemplate = transactionTemplate; + } + + public SequencesDao getSequencesDao() { + if (sequencesDao == null) + throw new NullPointerException("请先初始化BaseConfig"); + return sequencesDao; + } + + public void setSequencesDao(SequencesDao sequencesDao) { + this.sequencesDao = sequencesDao; + } + + public SequencesUnusedDao getSequencesUnusedDao() { + if (sequencesUnusedDao == null) + throw new NullPointerException("请先初始化BaseConfig"); + return sequencesUnusedDao; + } + + public void setSequencesUnusedDao(SequencesUnusedDao sequencesUnusedDao) { + this.sequencesUnusedDao = sequencesUnusedDao; + } + + public SequencesUnlockDao getSequencesUnlockDao() { + if (sequencesUnlockDao == null) + throw new NullPointerException("请先初始化BaseConfig"); + return sequencesUnlockDao; + } + + public void setSequencesUnlockDao(SequencesUnlockDao sequencesUnlockDao) { + this.sequencesUnlockDao = sequencesUnlockDao; + } + + public Integer getStep() { + if (step == null) + throw new NullPointerException("请先初始化BaseConfig"); + return step; + } + + public void setStep(Integer step) { + this.step = step; + } + + public String getType() { + if (type == null) + throw new NullPointerException("请先初始化BaseConfig"); + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Integer getMinLength() { + if (minLength == null) + throw new NullPointerException("请先初始化BaseConfig"); + return minLength; + } + + public void setMinLength(Integer minLength) { + this.minLength = minLength; + } + + private void init(GeneratorConfig generatorConfig) { + //数据库操作模板 + JdbcTemplate jdbcTemplate = generatorConfig.getJdbcTemplate(); + + if (jdbcTemplate == null) { + //数据源 + DataSource dataSource = generatorConfig.getDataSource(); + if (dataSource == null) + //若数据库操作模板为空,也没有配置数据源,则抛出异常 + throw new NullPointerException("数据源不能为空"); + //否则以数据源创建数据库操作模板 + jdbcTemplate = new JdbcTemplate(dataSource); + } + + if (generatorConfig.getTransactionTemplate() == null) { + //若没有配置事务操作模板,则从配置中取事务管理器 + DataSourceTransactionManager transactionManager = generatorConfig.getTransactionManager(); + if (transactionManager == null) { + //若未配置事务管理器,则通过数据源新建 + DataSource dataSource = jdbcTemplate.getDataSource(); + if (dataSource == null) + throw new NullPointerException("数据源不能为空"); + transactionManager = new DataSourceTransactionManager(dataSource); + } + //通过事务管理器创建事务操作模板 + transactionTemplate = new TransactionTemplate(transactionManager); + } else { + //获取事务操作模板 + transactionTemplate = generatorConfig.getTransactionTemplate(); + } + + this.sequencesDao = new SequencesDaoImpl(jdbcTemplate, generatorConfig.getTableConfig()); + this.sequencesUnusedDao = new SequencesUnusedDaoImpl(jdbcTemplate, generatorConfig.getTableConfig()); + this.sequencesUnlockDao = new SequencesUnlockDaoImpl(jdbcTemplate, generatorConfig.getTableConfig()); + this.step = generatorConfig.getStep(); + this.type = generatorConfig.getType(); + this.minLength = generatorConfig.getMinLength(); + } +} diff --git a/src/main/java/com/yanghuanglin/seq/config/GeneratorConfig.java b/src/main/java/com/yanghuanglin/seq/config/GeneratorConfig.java index ca98e55..a8757f3 100644 --- a/src/main/java/com/yanghuanglin/seq/config/GeneratorConfig.java +++ b/src/main/java/com/yanghuanglin/seq/config/GeneratorConfig.java @@ -43,6 +43,11 @@ public class GeneratorConfig { */ private Integer step = 1; + /** + * 格式化后序号字符串的最小长度,不足的部分补零 + */ + private Integer minLength = 1; + /** * 默认序号类型 */ @@ -100,6 +105,14 @@ public class GeneratorConfig { this.autoCreate = autoCreate; } + public Integer getMinLength() { + return minLength; + } + + public void setMinLength(Integer minLength) { + this.minLength = minLength; + } + public String getType() { return type; } diff --git a/src/main/java/com/yanghuanglin/seq/enums/FormatPlaceholder.java b/src/main/java/com/yanghuanglin/seq/enums/FormatPlaceholder.java new file mode 100644 index 0000000..0a1713d --- /dev/null +++ b/src/main/java/com/yanghuanglin/seq/enums/FormatPlaceholder.java @@ -0,0 +1,62 @@ +package com.yanghuanglin.seq.enums; + +/** + * 格式占位符枚举 + * + * @author yanghuanglin + * @since 2022/2/14 + */ +public enum FormatPlaceholder { + /** + * 序号格式字符中的年 + */ + YEAR("#year#"), + + /** + * 序号格式字符中的月 + */ + MONTH("#month#"), + + /** + * 序号格式字符中的日 + */ + DAY("#day#"), + + /** + * 序号格式字符中的格式化后的序号 + */ + SEQ("#seq#"); + + /** + * 调用toString()后的字符串,这个字符串用于正则匹配(替换格式字符串中的对应占位符)和反向查找(将占位符字符串转换为对应枚举) + */ + private final String placeholder; + + /** + * 构造函数 + * + * @param placeholder 格式占位符 + */ + FormatPlaceholder(String placeholder) { + this.placeholder = placeholder; + } + + public String getPlaceholder() { + return placeholder; + } + + /** + * 将格式占位符转为对应枚举 + * + * @param placeholder 格式占位符 + * @return 对应枚举 + */ + public static FormatPlaceholder of(String placeholder) { + FormatPlaceholder[] enumConstants = FormatPlaceholder.class.getEnumConstants(); + for (FormatPlaceholder enumConstant : enumConstants) { + if (enumConstant.getPlaceholder().equals(placeholder)) + return enumConstant; + } + return null; + } +} diff --git a/src/main/java/com/yanghuanglin/seq/generator/Generator.java b/src/main/java/com/yanghuanglin/seq/generator/Generator.java index 862fbbb..b9cdbca 100644 --- a/src/main/java/com/yanghuanglin/seq/generator/Generator.java +++ b/src/main/java/com/yanghuanglin/seq/generator/Generator.java @@ -1,6 +1,8 @@ package com.yanghuanglin.seq.generator; +import com.yanghuanglin.seq.config.BaseConfig; import com.yanghuanglin.seq.config.GeneratorConfig; +import com.yanghuanglin.seq.enums.FormatPlaceholder; import com.yanghuanglin.seq.po.Sequences; import com.yanghuanglin.seq.po.SequencesUnlock; import com.yanghuanglin.seq.po.SequencesUnused; @@ -8,23 +10,6 @@ import com.yanghuanglin.seq.po.SequencesUnused; import java.util.Date; public interface Generator { - /** - * 序号格式字符中的年 - */ - String YEAR = "#year#"; - /** - * 序号格式字符中的月 - */ - String MONTH = "#month#"; - /** - * 序号格式字符中的日 - */ - String DAY = "#day#"; - /** - * 序号格式字符中的格式化后的序号 - */ - String SEQ = "#seq#"; - /** * 根据传入的key和type生成可用的序号对象。 *

@@ -33,7 +18,7 @@ public interface Generator { * 如果根据key和默认的{@link GeneratorConfig#getType()}在{@link Sequences}中找到了记录,且在{@link SequencesUnused}也找到了记录,说明该组合生成的序号有部分未使用,返回的是{@link SequencesUnused}中找到的seq最小的序号对象。同时会将{@link SequencesUnused}中找到的seq最小的记录删除,然后写入到{@link SequencesUnlock}中。 *

* - * @param key 数据字典中的编码 + * @param key 数据字典中的编码 * @return 可用的序号对象 */ Sequences generate(String key); @@ -64,8 +49,21 @@ public interface Generator { */ String generate(String key, String type, Integer minLength); + /** + * 将{@link #generate(String, String)}得到的序号对象格式化为补零后的序号字符串,其最小长度通过{@link BaseConfig#getMinLength()}设定。实际上只会用到{@link Sequences#getSeq()}属性 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 + * + * @param sequences 生成的序号对象 + * @param pattern 格式 + * @return 格式化后的字符串 + */ + String format(Sequences sequences, String pattern); + /** * 将{@link #generate(String, String)}得到的序号对象格式化为补零后的序号字符串。实际上只会用到{@link Sequences#getSeq()}属性 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 * * @param sequences 生成的序号对象 * @param minLength 序号数字最小长度 @@ -74,10 +72,25 @@ public interface Generator { */ String format(Sequences sequences, Integer minLength, String pattern); + /** + * 将生成的序号对象格式化为指定格式,格式化后字符串最小长度为{@link BaseConfig#getMinLength()},不足则补零 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR#getPlaceholder()}(当前年份)、{@link FormatPlaceholder#MONTH#getPlaceholder()}(当前月份)、{@link FormatPlaceholder#DAY#getPlaceholder()}(当前日期)、{@link FormatPlaceholder#SEQ#getPlaceholder()}(生成的字符串序号)四个变量 + *

+ * seq为1,pattern为#year##month##day#6#seq#,则会格式化为2022013061。此序号含义如下: + *

+ * 序号格式:[年][月][日][固定6开头][序号1,最小位数为{@link BaseConfig#getMinLength()}设置,默认为1,不足则补零] + * + * @param seq 需要格式化的序号 + * @param pattern 格式 + * @return 格式化后的序号字符串 + */ + String format(Long seq, String pattern); + /** * 将生成的序号对象格式化为指定格式 *

- * pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量 + * pattern支持:{@link FormatPlaceholder#YEAR}}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 *

* seq为1,minLength为4,pattern为#year##month##day#6#seq#,则会格式化为2022013060001。此序号含义如下: *

@@ -90,10 +103,26 @@ public interface Generator { */ String format(Long seq, Integer minLength, String pattern); + /** + * 将生成的序号对象格式化为指定格式,格式化后字符串最小长度为{@link BaseConfig#getMinLength()},不足则补零 + *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 + *

+ * seq为1,start为6,minLength为4,pattern为#year##month##day##seq#,则会格式化为2022013061。此序号含义如下: + *

+ * 序号格式:[年][月][日][固定6开头][序号1,最小位数为{@link BaseConfig#getMinLength()}设置,默认为1,不足则补零] + * + * @param seq 需要格式化的序号 + * @param start 序号格式化后以什么字符串开头 + * @param pattern 序号格式 + * @return 格式化后的序号字符串 + */ + String format(Long seq, String start, String pattern); + /** * 将生成的序号对象格式化为指定格式 *

- * pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量 + * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 *

* seq为1,start为6,minLength为4,pattern为#year##month##day##seq#,则会格式化为2022013060001。此序号含义如下: *

@@ -110,6 +139,8 @@ public interface Generator { /** * 将已格式化的序号解析为序号对象 *

+ * pattern支持:{@link FormatPlaceholder#YEAR}(当前年份)、{@link FormatPlaceholder#MONTH}}(当前月份)、{@link FormatPlaceholder#DAY}}(当前日期)、{@link FormatPlaceholder#SEQ}}(生成的字符串序号)几个枚举值通过{@link FormatPlaceholder#getPlaceholder()}得到的字符串 + *

* 返回的序号对象{@link Sequences#getKey()}为null,{@link Sequences#getType()}为{@link GeneratorConfig#getType()}的默认值,但是临时字段{@link Sequences#getYear()}、{@link Sequences#getMonth()}、{@link Sequences#getDay()}可能有值 *

* 如果生成序号时,序号的key在年、月、日上有关联(如每年每月的序号要从1开始),则需要自行用序号字符串与{@link Sequences#getYear()}、{@link Sequences#getMonth()}、{@link Sequences#getDay()}进行组合,进而得到key diff --git a/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java b/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java index 96fc5e9..49f53f4 100644 --- a/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java +++ b/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java @@ -1,22 +1,18 @@ package com.yanghuanglin.seq.generator.impl; +import com.yanghuanglin.seq.config.BaseConfig; import com.yanghuanglin.seq.config.GeneratorConfig; import com.yanghuanglin.seq.dao.SequencesDao; import com.yanghuanglin.seq.dao.SequencesUnlockDao; import com.yanghuanglin.seq.dao.SequencesUnusedDao; -import com.yanghuanglin.seq.dao.impl.SequencesDaoImpl; -import com.yanghuanglin.seq.dao.impl.SequencesUnlockDaoImpl; -import com.yanghuanglin.seq.dao.impl.SequencesUnusedDaoImpl; +import com.yanghuanglin.seq.enums.FormatPlaceholder; import com.yanghuanglin.seq.generator.Generator; import com.yanghuanglin.seq.po.Sequences; import com.yanghuanglin.seq.po.SequencesUnlock; import com.yanghuanglin.seq.po.SequencesUnused; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.util.StringUtils; -import javax.sql.DataSource; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -24,6 +20,8 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.yanghuanglin.seq.enums.FormatPlaceholder.*; + public class SequencesGenerator implements Generator { private final TransactionTemplate transactionTemplate; private final SequencesDao sequencesDao; @@ -31,51 +29,28 @@ public class SequencesGenerator implements Generator { private final SequencesUnlockDao sequencesUnlockDao; private final Integer step; private final String type; + private final Integer minLength; public SequencesGenerator(GeneratorConfig generatorConfig) { - //数据库操作模板 - JdbcTemplate jdbcTemplate = generatorConfig.getJdbcTemplate(); + BaseConfig baseConfig = BaseConfig.getInstance(generatorConfig); - if (jdbcTemplate == null) { - //数据源 - DataSource dataSource = generatorConfig.getDataSource(); - if (dataSource == null) - //若数据库操作模板为空,也没有配置数据源,则抛出异常 - throw new NullPointerException("数据源不能为空"); - //否则以数据源创建数据库操作模板 - jdbcTemplate = new JdbcTemplate(dataSource); - } + this.transactionTemplate = baseConfig.getTransactionTemplate(); + this.sequencesDao = baseConfig.getSequencesDao(); + this.sequencesUnusedDao = baseConfig.getSequencesUnusedDao(); + this.sequencesUnlockDao = baseConfig.getSequencesUnlockDao(); + this.step = baseConfig.getStep(); + this.type = baseConfig.getType(); + this.minLength = baseConfig.getMinLength(); - if (generatorConfig.getTransactionTemplate() == null) { - //若没有配置事务操作模板,则从配置中取事务管理器 - DataSourceTransactionManager transactionManager = generatorConfig.getTransactionManager(); - if (transactionManager == null) { - //若未配置事务管理器,则通过数据源新建 - DataSource dataSource = jdbcTemplate.getDataSource(); - if (dataSource == null) - throw new NullPointerException("数据源不能为空"); - transactionManager = new DataSourceTransactionManager(dataSource); - } - //通过事务管理器创建事务操作模板 - transactionTemplate = new TransactionTemplate(transactionManager); - } else { - //获取事务操作模板 - transactionTemplate = generatorConfig.getTransactionTemplate(); - } - - this.sequencesDao = new SequencesDaoImpl(jdbcTemplate, generatorConfig.getTableConfig()); - this.sequencesUnusedDao = new SequencesUnusedDaoImpl(jdbcTemplate, generatorConfig.getTableConfig()); - this.sequencesUnlockDao = new SequencesUnlockDaoImpl(jdbcTemplate, generatorConfig.getTableConfig()); - this.step = generatorConfig.getStep(); - this.type = generatorConfig.getType(); - - autoCreateTable(generatorConfig.getAutoCreate()); + createTable(generatorConfig.getAutoCreate()); } /** - * 自动创建需要的表 + * 创建需要的表 + * + * @param autoCreate 是否自动创建 */ - private void autoCreateTable(Boolean autoCreate) { + private void createTable(Boolean autoCreate) { if (!autoCreate) return; this.sequencesDao.createTable(); @@ -83,6 +58,7 @@ public class SequencesGenerator implements Generator { this.sequencesUnlockDao.createTable(); } + @Override public synchronized Sequences generate(String key) { return generate(key, type); @@ -141,33 +117,48 @@ public class SequencesGenerator implements Generator { return sequences.format(minLength); } + @Override + public String format(Sequences sequences, String pattern) { + return format(sequences, minLength, pattern); + } + @Override public String format(Sequences sequences, Integer minLength, String pattern) { return format(sequences.getSeq(), minLength, pattern); } + @Override + public String format(Long seq, String pattern) { + return format(seq, minLength, pattern); + } + @Override public String format(Long seq, Integer minLength, String pattern) { return format(seq, null, minLength, pattern); } + @Override + public String format(Long seq, String start, String pattern) { + return format(seq, start, minLength, pattern); + } + @Override public String format(Long seq, String start, Integer minLength, String pattern) { if (start == null) start = ""; String seqString = start + new Sequences(seq).format(minLength); Calendar calendar = Calendar.getInstance(); - pattern = pattern.replaceAll(Generator.YEAR, String.valueOf(calendar.get(Calendar.YEAR))); - pattern = pattern.replaceAll(Generator.MONTH, String.format("%02d", calendar.get(Calendar.MONTH) + 1)); - pattern = pattern.replaceAll(Generator.DAY, String.valueOf(calendar.get(Calendar.DAY_OF_MONTH))); - pattern = pattern.replaceAll(Generator.SEQ, seqString); + pattern = pattern.replaceAll(YEAR.getPlaceholder(), String.valueOf(calendar.get(Calendar.YEAR))); + pattern = pattern.replaceAll(MONTH.getPlaceholder(), String.format("%02d", calendar.get(Calendar.MONTH) + 1)); + pattern = pattern.replaceAll(DAY.getPlaceholder(), String.valueOf(calendar.get(Calendar.DAY_OF_MONTH))); + pattern = pattern.replaceAll(SEQ.getPlaceholder(), seqString); return pattern; } @Override public Sequences parse(String formatted, String pattern) { //年、月、日、序号分隔特殊符号正则规则 - String splitRegString = "(" + YEAR + "|" + MONTH + "|" + DAY + "|" + SEQ + ")"; + String splitRegString = "(" + YEAR.getPlaceholder() + "|" + MONTH.getPlaceholder() + "|" + DAY.getPlaceholder() + "|" + SEQ.getPlaceholder() + ")"; //根据年、月、日、序号的特殊符号,对格式进行分隔,得到排除特殊符号后的字符串数组 String[] split = pattern.split(splitRegString); @@ -197,8 +188,11 @@ public class SequencesGenerator implements Generator { //根据序号匹配规则字符串查找字符串分组 while (matcher.find()) { String group = matcher.group(); - switch (group) { - case Generator.YEAR: + FormatPlaceholder formatPlaceholder = of(group); + if (formatPlaceholder == null) + continue; + switch (formatPlaceholder) { + case YEAR: //若分组为年份分组,则将年份正则匹配到的字符串赋值给year,同时把格式化后的序号字符串中,对应年的字符串替换为空字符串 Matcher yearMatcher = yearPattern.matcher(formatted); if (yearMatcher.find()) { @@ -206,7 +200,7 @@ public class SequencesGenerator implements Generator { } formatted = formatted.replaceFirst(yearRegStr, ""); break; - case Generator.MONTH: + case MONTH: //若分组为月份分组,则将月份正则匹配到的字符串赋值给month,同时把格式化后的序号字符串中,对应月的字符串替换为空字符串 Matcher monthMatcher = monthPattern.matcher(formatted); if (monthMatcher.find()) { @@ -214,7 +208,7 @@ public class SequencesGenerator implements Generator { } formatted = formatted.replaceFirst(monthRegStr, ""); break; - case Generator.DAY: + case DAY: //若分组为日期分组,则将日期正则匹配到的字符串赋值给day,同时把格式化后的序号字符串中,对应日期的字符串替换为空字符串 Matcher dayMatcher = dayPattern.matcher(formatted); if (dayMatcher.find()) { @@ -241,6 +235,8 @@ public class SequencesGenerator implements Generator { @Override public synchronized boolean lock(Sequences sequences) { + if (sequences == null) + return true; SequencesUnlock condition = new SequencesUnlock(sequences); //将使用中表的对应数据删除,空闲表中数据在生成时会删除,因此这里不需要处理该表 return sequencesUnlockDao.delete(condition); @@ -280,6 +276,8 @@ public class SequencesGenerator implements Generator { @Override public synchronized void release(Sequences sequences) { + if (sequences == null) + return; sequencesUnlockDao.delete(new SequencesUnlock(sequences)); sequencesUnusedDao.save(new SequencesUnused(sequences)); } diff --git a/src/main/java/com/yanghuanglin/seq/po/Sequences.java b/src/main/java/com/yanghuanglin/seq/po/Sequences.java index 9e7e0f8..58d1bdb 100644 --- a/src/main/java/com/yanghuanglin/seq/po/Sequences.java +++ b/src/main/java/com/yanghuanglin/seq/po/Sequences.java @@ -1,5 +1,6 @@ package com.yanghuanglin.seq.po; +import com.yanghuanglin.seq.config.BaseConfig; /** * 当前序号 @@ -125,7 +126,19 @@ public class Sequences { /** * 序号补零 * - * @param minLength 最小长度,低于此长度,会填充零 + * @return 补零后的序号,若未单独设置序号的长度,则最小长度为{@link BaseConfig#getMinLength()}长度;否则为修改后的长度,不足部分补零 + */ + public String format() { + BaseConfig baseConfig = BaseConfig.getInstance(); + if (baseConfig.getMinLength() != null) + return String.format("%0" + baseConfig.getMinLength() + "d", this.seq); + return String.valueOf(this.seq); + } + + /** + * 序号补零 + * + * @param minLength 最小长度,低于此长度,会补零 * @return 补零后的序号 */ public String format(Integer minLength) { diff --git a/src/test/java/SeqTest.java b/src/test/java/SeqTest.java index 1782075..360c1da 100644 --- a/src/test/java/SeqTest.java +++ b/src/test/java/SeqTest.java @@ -27,10 +27,10 @@ public class SeqTest { GeneratorConfig generatorConfig = new GeneratorConfig(dataSource); TableConfig tableConfig = new TableConfig(); -// tableConfig.setTable("sequences"); -// tableConfig.setKeyColumn("SEQUENCE_KEY"); -// tableConfig.setTypeColumn("SEQUENCE_TYPE"); -// tableConfig.setSeqColumn("SEQUENCE_NEXT_ID"); + tableConfig.setTable("sequences"); + tableConfig.setKeyColumn("SEQUENCE_KEY"); + tableConfig.setTypeColumn("SEQUENCE_TYPE"); + tableConfig.setSeqColumn("NEXT_ID"); generatorConfig.setTableConfig(tableConfig); generator = new SequencesGenerator(generatorConfig); @@ -47,7 +47,7 @@ public class SeqTest { int finalI = i; threadPoolExecutor.execute(() -> { Sequences sequences = generator.generate("SNT", "MISSION"); - String formattedSeq = generator.format(sequences.getSeq(), 5, "处〔#year#〕10801#seq#"); + String formattedSeq = generator.format(sequences.getSeq(), "处〔#year#〕10801#seq#"); // if (finalI % 2 == 0) // System.out.println(3 / 0); generator.lock(sequences);