Skip to content

Commit 526ebd1

Browse files
author
zihluwang
committed
feat: serial service
1 parent 952a329 commit 526ebd1

File tree

8 files changed

+374
-0
lines changed

8 files changed

+374
-0
lines changed

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ include(
2929
"simple-jwt-spring-boot-starter",
3030
"property-guard-spring-boot-starter"
3131
)
32+
include("simple-serial")

simple-serial/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Simple Serial
2+
3+
> Thanks to [@siujamo](https://github.com/siujamo)'s donation.
4+
5+
Simple Serial reuses the configuration of Redis connections to provide am easy-to-use serial
6+
service.
7+
8+
## Configuration
9+
10+
Simple Serial reused the redis configuration of Spring Boot to provide redis support for the
11+
service.
12+
13+
Besides, **Simple Serial** provides a configuration property `onixbyte.serial.start-serial` to
14+
specify the start value of a serial, and default to `0`.

simple-serial/build.gradle.kts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import java.net.URI
2+
3+
plugins {
4+
id("java")
5+
}
6+
7+
val artefactVersion: String by project
8+
val projectUrl: String by project
9+
val projectGithubUrl: String by project
10+
val licenseName: String by project
11+
val licenseUrl: String by project
12+
13+
val jacksonVersion: String by project
14+
val springBootVersion: String by project
15+
16+
group = "com.onixbyte"
17+
version = artefactVersion
18+
19+
repositories {
20+
mavenCentral()
21+
}
22+
23+
dependencies {
24+
implementation("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion")
25+
implementation("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion")
26+
implementation("org.springframework.boot:spring-boot-starter-logging:$springBootVersion")
27+
implementation("org.springframework.boot:spring-boot-configuration-processor:$springBootVersion")
28+
implementation("org.springframework.boot:spring-boot-starter-data-redis:$springBootVersion")
29+
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor:$springBootVersion")
30+
testImplementation("org.springframework.boot:spring-boot-starter-test:$springBootVersion")
31+
testImplementation(platform("org.junit:junit-bom:5.10.0"))
32+
testImplementation("org.junit.jupiter:junit-jupiter")
33+
}
34+
35+
java {
36+
sourceCompatibility = JavaVersion.VERSION_17
37+
targetCompatibility = JavaVersion.VERSION_17
38+
withSourcesJar()
39+
withJavadocJar()
40+
}
41+
42+
tasks.test {
43+
useJUnitPlatform()
44+
}
45+
46+
publishing {
47+
publications {
48+
create<MavenPublication>("simpleSerialSpringBootStarter") {
49+
groupId = group.toString()
50+
artifactId = "simple-serial-spring-boot-starter"
51+
version = artefactVersion
52+
53+
pom {
54+
name = "Simple Serial :: Spring Boot Starter"
55+
description = "A Redis based easy-to-use serial service."
56+
url = projectUrl
57+
58+
licenses {
59+
license {
60+
name = licenseName
61+
url = licenseUrl
62+
}
63+
}
64+
65+
scm {
66+
connection = "scm:git:git://github.com:OnixByte/JDevKit.git"
67+
developerConnection = "scm:git:git://github.com:OnixByte/JDevKit.git"
68+
url = projectGithubUrl
69+
}
70+
71+
developers {
72+
developer {
73+
id = "zihluwang"
74+
name = "Zihlu Wang"
75+
email = "really@zihlu.wang"
76+
timezone = "Asia/Hong_Kong"
77+
}
78+
}
79+
}
80+
81+
from(components["java"])
82+
83+
signing {
84+
sign(publishing.publications["simpleSerialSpringBootStarter"])
85+
}
86+
}
87+
88+
repositories {
89+
maven {
90+
name = "sonatypeNexus"
91+
url = URI(providers.gradleProperty("repo.maven-central.host").get())
92+
credentials {
93+
username = providers.gradleProperty("repo.maven-central.username").get()
94+
password = providers.gradleProperty("repo.maven-central.password").get()
95+
}
96+
}
97+
}
98+
}
99+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) 2024-2025 OnixByte.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
*
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package com.onixbyte.serial;
19+
20+
import org.springframework.boot.autoconfigure.AutoConfiguration;
21+
import org.springframework.context.annotation.Bean;
22+
import org.springframework.data.redis.connection.RedisConnectionFactory;
23+
import org.springframework.data.redis.core.RedisTemplate;
24+
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
25+
import org.springframework.data.redis.serializer.RedisSerializer;
26+
27+
/**
28+
* Redis Configuration provides redis templates for operations to serial.
29+
*
30+
* @author siujamo
31+
*/
32+
@AutoConfiguration
33+
public class RedisConfig {
34+
35+
/**
36+
* RedisTemplate for serial service.
37+
*
38+
* @param redisConnectionFactory redis connection factory
39+
* @return a configured redis template for serial service
40+
*/
41+
@Bean
42+
public RedisTemplate<String, Long> serialRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
43+
var redisTemplate = new RedisTemplate<String, Long>();
44+
redisTemplate.setConnectionFactory(redisConnectionFactory);
45+
redisTemplate.setKeySerializer(RedisSerializer.string());
46+
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Long.class));
47+
redisTemplate.afterPropertiesSet();
48+
return redisTemplate;
49+
}
50+
51+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (C) 2024-2025 OnixByte.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
*
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package com.onixbyte.serial;
19+
20+
import com.onixbyte.serial.properties.SerialProperties;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
import org.springframework.beans.factory.annotation.Value;
24+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
25+
import org.springframework.data.redis.core.RedisTemplate;
26+
import org.springframework.stereotype.Service;
27+
28+
import java.util.Optional;
29+
30+
/**
31+
* {@code SerialService} provides simple serial operations.
32+
*
33+
* @author siujamo
34+
*/
35+
@Service
36+
@EnableConfigurationProperties(SerialProperties.class)
37+
public class SerialService {
38+
39+
private static final Logger log = LoggerFactory.getLogger(SerialService.class);
40+
41+
private final String appName;
42+
private final RedisTemplate<String, Long> serialRedisTemplate;
43+
private final SerialProperties serialProperties;
44+
45+
/**
46+
* Default constructor.
47+
*
48+
* @param appName the name of this application
49+
* @param serialRedisTemplate serial redis template
50+
* @param serialProperties serial properties
51+
*/
52+
public SerialService(@Value("${spring.application.name}") String appName,
53+
RedisTemplate<String, Long> serialRedisTemplate,
54+
SerialProperties serialProperties) {
55+
this.appName = appName;
56+
this.serialRedisTemplate = serialRedisTemplate;
57+
this.serialProperties = serialProperties;
58+
}
59+
60+
/**
61+
* Build a serial key.
62+
*
63+
* @param tag tag of the serial
64+
* @return key of a serial
65+
*/
66+
public String buildKey(String tag) {
67+
return appName + ":serial:" + tag;
68+
}
69+
70+
/**
71+
* Get the next available serial for specific tag.
72+
*
73+
* @param tag tag of the serial
74+
* @return next available serial
75+
*/
76+
public Long nextSerial(String tag) {
77+
var key = buildKey(tag);
78+
var next = Optional.ofNullable(serialRedisTemplate.opsForValue().get(key))
79+
.orElse(serialProperties.getStartSerial());
80+
serialRedisTemplate.opsForValue().set(key, next + 1);
81+
return next;
82+
}
83+
84+
/**
85+
* Reset all serial values.
86+
*/
87+
public void reset() {
88+
var keys = serialRedisTemplate.keys(buildKey("*"));
89+
var startSerial = serialProperties.getStartSerial();
90+
91+
if (!keys.isEmpty()) {
92+
for (var key : keys) {
93+
serialRedisTemplate.opsForValue().set(key, startSerial);
94+
log.debug("Serial {} has been reset to {}", key, startSerial);
95+
}
96+
}
97+
}
98+
99+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (C) 2024-2025 OnixByte.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
*
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package com.onixbyte.serial.properties;
19+
20+
import org.springframework.boot.context.properties.ConfigurationProperties;
21+
22+
/**
23+
* SerialProperties can modify the start value of a serial.
24+
*
25+
* @author siujamo
26+
*/
27+
@ConfigurationProperties(prefix = "onixbyte.serial")
28+
public class SerialProperties {
29+
30+
/**
31+
* The start of the serial, default to 0.
32+
*/
33+
private Long startSerial = 0L;
34+
35+
/**
36+
* Get the start of the serial.
37+
*
38+
* @return start of the serial
39+
*/
40+
public Long getStartSerial() {
41+
return startSerial;
42+
}
43+
44+
/**
45+
* Set the start of the serial.
46+
*
47+
* @param startSerial start of the serial
48+
*/
49+
public void setStartSerial(Long startSerial) {
50+
this.startSerial = startSerial;
51+
}
52+
53+
/**
54+
* Default constructor.
55+
*/
56+
public SerialProperties() {
57+
}
58+
59+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# Copyright (C) 2024-2025 OnixByte.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
#
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
com.onixbyte.serial.RedisConfig
19+
com.onixbyte.serial.SerialService
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright (C) 2024-2025 OnixByte.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
19+
<configuration>
20+
<property name="COLOURFUL_OUTPUT" value="%black(%date{'dd MMM, yyyy HH:mm:ss', Asia/Hong_Kong, en-UK}) %highlight(%-5level) %black(---) %black([%10.10t]) %cyan(%-20.20logger{20}) %black(:) %msg%n"/>
21+
<property name="STANDARD_OUTPUT" value="%date{'dd MMM, yyyy HH:mm:ss', Asia/Hong_Kong, en-UK} %-5level %black(---) [%10.10t] %-20.20logger{20} : %msg%n"/>
22+
23+
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
24+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
25+
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
26+
<pattern>${COLOURFUL_OUTPUT}</pattern>
27+
</encoder>
28+
</appender>
29+
<root level="INFO">
30+
<appender-ref ref="STDOUT"/>
31+
</root>
32+
</configuration>

0 commit comments

Comments
 (0)