init
This commit is contained in:
commit
cf399b316e
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
73
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
73
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,73 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="TOP_LEVEL_CLASS_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="INNER_CLASS_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="METHOD_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="FIELD_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="IGNORE_DEPRECATED" value="false" />
|
||||
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
|
||||
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
|
||||
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
|
||||
<option name="myAdditionalJavadocTags" value="description:,author:,date:,date" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="JavadocDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ADDITIONAL_TAGS" value="description:,author:,date:,date" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MissingJavadoc" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="PACKAGE_SETTINGS">
|
||||
<Options>
|
||||
<option name="ENABLED" value="false" />
|
||||
</Options>
|
||||
</option>
|
||||
<option name="MODULE_SETTINGS">
|
||||
<Options>
|
||||
<option name="ENABLED" value="false" />
|
||||
</Options>
|
||||
</option>
|
||||
<option name="TOP_LEVEL_CLASS_SETTINGS">
|
||||
<Options>
|
||||
<option name="ENABLED" value="false" />
|
||||
</Options>
|
||||
</option>
|
||||
<option name="INNER_CLASS_SETTINGS">
|
||||
<Options>
|
||||
<option name="ENABLED" value="false" />
|
||||
</Options>
|
||||
</option>
|
||||
<option name="METHOD_SETTINGS">
|
||||
<Options>
|
||||
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
|
||||
<option name="ENABLED" value="false" />
|
||||
</Options>
|
||||
</option>
|
||||
<option name="FIELD_SETTINGS">
|
||||
<Options>
|
||||
<option name="ENABLED" value="false" />
|
||||
</Options>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
20
.idea/misc.xml
generated
Normal file
20
.idea/misc.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ComposerSettings">
|
||||
<execution />
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="zulu-11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
124
.idea/uiDesigner.xml
generated
Normal file
124
.idea/uiDesigner.xml
generated
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
||||
130
pom.xml
Normal file
130
pom.xml
Normal file
@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baogutang.demo</groupId>
|
||||
<artifactId>baogutang-demo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.3.2.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.5.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.9.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.1-jre</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<excludes>
|
||||
<exclude>templates/fonts/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<includes>
|
||||
<include>templates/fonts/**</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.19</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,24 @@
|
||||
package top.baogutang.demo;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 14:48
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootApplication(scanBasePackages = {"top.baogutang.demo.*"})
|
||||
@EnableAsync
|
||||
public class BaoGuTangDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BaoGuTangDemoApplication.class, args);
|
||||
log.info("==============DEMO服务启动成功!!=================");
|
||||
}
|
||||
}
|
||||
70
src/main/java/top/baogutang/demo/config/RedisConfig.java
Normal file
70
src/main/java/top/baogutang/demo/config/RedisConfig.java
Normal file
@ -0,0 +1,70 @@
|
||||
package top.baogutang.demo.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 10:56
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class RedisConfig {
|
||||
|
||||
/**
|
||||
* 编写自定义的 redisTemplate
|
||||
* 这是一个比较固定的模板
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
|
||||
// 为了开发方便,直接使用<String, Object>
|
||||
RedisTemplate<String, Object> template = new RedisTemplate();
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
|
||||
// Json 配置序列化
|
||||
// 使用 jackson 解析任意的对象
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
// 使用 objectMapper 进行转义
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
objectMapper.setTimeZone(TimeZone.getDefault());
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
// String 的序列化
|
||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
|
||||
// key 采用 String 的序列化方式
|
||||
template.setKeySerializer(stringRedisSerializer);
|
||||
// Hash 的 key 采用 String 的序列化方式
|
||||
template.setHashKeySerializer(stringRedisSerializer);
|
||||
// value 采用 jackson 的序列化方式
|
||||
template.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
// Hash 的 value 采用 String 的序列化方式
|
||||
template.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
// 把所有的配置 set 进 template
|
||||
template.afterPropertiesSet();
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
21
src/main/java/top/baogutang/demo/constants/MsgConstant.java
Normal file
21
src/main/java/top/baogutang/demo/constants/MsgConstant.java
Normal file
@ -0,0 +1,21 @@
|
||||
package top.baogutang.demo.constants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 13:38
|
||||
*/
|
||||
public class MsgConstant {
|
||||
|
||||
/**
|
||||
* 消费端策略:异常时再次消费
|
||||
*/
|
||||
public static final String CONSUMER_STRATEGY_RECONSUME = "RECONSUME";
|
||||
|
||||
/**
|
||||
* 调整支持多topic订阅时,兼容旧的项目,未设置handler的topic时,使用默认值
|
||||
*/
|
||||
public static final String DEFAULT_TOPIC_NAME = "DEFAULT_TOPIC_NAME";
|
||||
}
|
||||
36
src/main/java/top/baogutang/demo/constants/RedisKey.java
Normal file
36
src/main/java/top/baogutang/demo/constants/RedisKey.java
Normal file
@ -0,0 +1,36 @@
|
||||
package top.baogutang.demo.constants;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import top.baogutang.demo.constants.enums.QueueType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 13:44
|
||||
*/
|
||||
public class RedisKey {
|
||||
|
||||
private RedisKey() {
|
||||
// empty private constructor
|
||||
}
|
||||
|
||||
private static final String MODULE = "baogutang-demo";
|
||||
|
||||
private static final String SEPARATOR = ":";
|
||||
|
||||
/**
|
||||
* 影像推送key
|
||||
*
|
||||
* @param queueType queueType
|
||||
* @param userId userId
|
||||
* @param messageKey messageKey
|
||||
* @return key
|
||||
*/
|
||||
public static String getImagePushMsgLockKey(QueueType queueType, Long userId, String messageKey) {
|
||||
return Joiner.on(SEPARATOR).join(Arrays.asList(MODULE, queueType.getTopicName(), userId, messageKey));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package top.baogutang.demo.constants.enums;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 11:42
|
||||
*/
|
||||
public enum QueuePlatform {
|
||||
|
||||
REDIS,
|
||||
|
||||
KAFKA,
|
||||
|
||||
;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package top.baogutang.demo.constants.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 10:56
|
||||
*/
|
||||
@Getter
|
||||
public enum QueueType {
|
||||
|
||||
/**
|
||||
* 影像推送
|
||||
*/
|
||||
IMAGE_PUSH("IMAGE_PUSH", "影像推送"),
|
||||
|
||||
;
|
||||
|
||||
private final String topicName;
|
||||
|
||||
private final String topicDesc;
|
||||
|
||||
QueueType(String topicName, String topicDesc) {
|
||||
this.topicName = topicName;
|
||||
this.topicDesc = topicDesc;
|
||||
}
|
||||
|
||||
public static QueueType[] allTypes() {
|
||||
|
||||
return values();
|
||||
}
|
||||
|
||||
public static QueueType get(String topicName) {
|
||||
for (QueueType value : values()) {
|
||||
if (value.getTopicName().equals(topicName)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
66
src/main/java/top/baogutang/demo/message/IQueueMsg.java
Normal file
66
src/main/java/top/baogutang/demo/message/IQueueMsg.java
Normal file
@ -0,0 +1,66 @@
|
||||
package top.baogutang.demo.message;
|
||||
|
||||
import top.baogutang.demo.constants.enums.QueueType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 10:56
|
||||
*/
|
||||
public interface IQueueMsg<T> extends Serializable {
|
||||
|
||||
/**
|
||||
* getMsgType
|
||||
*
|
||||
* @return QueueType
|
||||
*/
|
||||
QueueType getMsgType();
|
||||
|
||||
/**
|
||||
* body
|
||||
*
|
||||
* @return body
|
||||
*/
|
||||
T getMsgBody();
|
||||
|
||||
/**
|
||||
* getMsgBizKey
|
||||
*
|
||||
* @return getMsgBizKey
|
||||
*/
|
||||
String getMsgBizKey();
|
||||
|
||||
/**
|
||||
* getDelayTime
|
||||
*
|
||||
* @return getDelayTime
|
||||
*/
|
||||
long getDelayTime();
|
||||
|
||||
/**
|
||||
* setDelayTime
|
||||
*
|
||||
* @param delayTime delayTime
|
||||
*/
|
||||
void setDelayTime(long delayTime);
|
||||
|
||||
/**
|
||||
* getTimeUnit
|
||||
*
|
||||
* @return getTimeUnit
|
||||
*/
|
||||
TimeUnit getTimeUnit();
|
||||
|
||||
/**
|
||||
* setTimeUnit
|
||||
*
|
||||
* @param timeUnit timeUnit
|
||||
*/
|
||||
void setTimeUnit(TimeUnit timeUnit);
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package top.baogutang.demo.message;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 13:48
|
||||
*/
|
||||
@Data
|
||||
public class ImagePushMessage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -870177103586251908L;
|
||||
|
||||
private Long userId;
|
||||
|
||||
// 这个类就是具体的消息类,需要什么字段就加什么字段
|
||||
}
|
||||
101
src/main/java/top/baogutang/demo/message/QueueMsg.java
Normal file
101
src/main/java/top/baogutang/demo/message/QueueMsg.java
Normal file
@ -0,0 +1,101 @@
|
||||
package top.baogutang.demo.message;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import top.baogutang.demo.constants.enums.QueueType;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 10:56
|
||||
*/
|
||||
@Data
|
||||
public class QueueMsg<T> implements IQueueMsg<T> {
|
||||
|
||||
private static final long serialVersionUID = 8969365246492490122L;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private QueueType msgType;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private T msgBody;
|
||||
|
||||
/**
|
||||
* 消息业务key
|
||||
*/
|
||||
private String msgBizKey;
|
||||
|
||||
/**
|
||||
* 延迟时间
|
||||
*/
|
||||
private long delayTime = 0;
|
||||
|
||||
/**
|
||||
* 延迟时间单位
|
||||
*/
|
||||
private TimeUnit timeUnit = TimeUnit.SECONDS;
|
||||
|
||||
public QueueMsg() {
|
||||
|
||||
}
|
||||
|
||||
public QueueMsg(QueueType msgType, T msgBody, String msgBizKey) {
|
||||
this.msgType = msgType;
|
||||
this.msgBody = msgBody;
|
||||
this.msgBizKey = msgBizKey;
|
||||
}
|
||||
|
||||
|
||||
public QueueMsg(QueueType msgType, T msgBody) {
|
||||
this.msgType = msgType;
|
||||
this.msgBody = msgBody;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public QueueType getMsgType() {
|
||||
return msgType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T getMsgBody() {
|
||||
|
||||
return msgBody;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMsgBizKey() {
|
||||
return msgBizKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelayTime() {
|
||||
return delayTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDelayTime(long delayTime) {
|
||||
this.delayTime = delayTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeUnit getTimeUnit() {
|
||||
return timeUnit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeUnit(TimeUnit timeUnit) {
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
36
src/main/java/top/baogutang/demo/message/SendResult.java
Normal file
36
src/main/java/top/baogutang/demo/message/SendResult.java
Normal file
@ -0,0 +1,36 @@
|
||||
package top.baogutang.demo.message;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 10:56
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class SendResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3562968976733007349L;
|
||||
|
||||
/**
|
||||
* 发送结果
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 已发送消息的ID(如果有)
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 已发送消息的主题
|
||||
*/
|
||||
private String topic;
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package top.baogutang.demo.message.consumer;
|
||||
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 13:41
|
||||
*/
|
||||
public abstract class AbstractQueueMessageConsumer implements IQueueMessageConsumer {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 重复消息处理
|
||||
*
|
||||
* @param key key
|
||||
* @return res
|
||||
*/
|
||||
protected boolean duplicateMsg(String key) {
|
||||
Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, 1, 300, TimeUnit.SECONDS);
|
||||
return Boolean.FALSE.equals(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除lock
|
||||
*
|
||||
* @param key key
|
||||
*/
|
||||
protected void removeLock(String key) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package top.baogutang.demo.message.consumer;
|
||||
|
||||
|
||||
import top.baogutang.demo.constants.MsgConstant;
|
||||
import top.baogutang.demo.message.IQueueMsg;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 11:04
|
||||
*/
|
||||
public interface IQueueMessageConsumer {
|
||||
|
||||
/**
|
||||
* 消费消息
|
||||
* @param queueMsg 消息体
|
||||
*/
|
||||
<T> void consume(IQueueMsg<T> queueMsg);
|
||||
|
||||
/**
|
||||
* getTopicName
|
||||
*
|
||||
* @return topic
|
||||
*/
|
||||
default String getTopicName() {
|
||||
return MsgConstant.DEFAULT_TOPIC_NAME;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package top.baogutang.demo.message.consumer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 14:37
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MessageConsumerFactory implements ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
public final Map<String, IQueueMessageConsumer> consumerMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
|
||||
Map<String, IQueueMessageConsumer> beansOfType = applicationContext.getBeansOfType(IQueueMessageConsumer.class);
|
||||
beansOfType.forEach((key, value) -> consumerMap.put(value.getTopicName(), value));
|
||||
log.info(">>>>>>>>>>queue message consumer inject complete<<<<<<<<<<");
|
||||
}
|
||||
|
||||
public IQueueMessageConsumer getConsumer(String topicName) {
|
||||
return consumerMap.get(topicName);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package top.baogutang.demo.message.consumer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.baogutang.demo.constants.RedisKey;
|
||||
import top.baogutang.demo.constants.enums.QueueType;
|
||||
import top.baogutang.demo.message.IQueueMsg;
|
||||
import top.baogutang.demo.message.ImagePushMessage;
|
||||
import top.baogutang.demo.utils.JacksonUtil;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 13:47
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RedisImagePushQueueMessageConsumer extends AbstractQueueMessageConsumer {
|
||||
|
||||
|
||||
@Override
|
||||
public <T> void consume(IQueueMsg<T> queueMsg) {
|
||||
log.info("RedisImagePushQueueMessageConsumer received message:{}", JacksonUtil.toJson(queueMsg));
|
||||
ImagePushMessage imagePushMessage = (ImagePushMessage) queueMsg.getMsgBody();
|
||||
String lockKey = RedisKey.getImagePushMsgLockKey(queueMsg.getMsgType(), imagePushMessage.getUserId(), queueMsg.getMsgBizKey());
|
||||
if (duplicateMsg(lockKey)) {
|
||||
log.info("RedisImagePushQueueMessageConsumer received duplicate message:{}", lockKey);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// TODO: process message
|
||||
// ...
|
||||
} catch (Exception e) {
|
||||
log.error("RedisImagePushQueueMessageConsumer process message:{} error:{}", JacksonUtil.toJson(queueMsg), e.getMessage(), e);
|
||||
} finally {
|
||||
removeLock(lockKey);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTopicName() {
|
||||
return QueueType.IMAGE_PUSH.getTopicName();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package top.baogutang.demo.message.producer;
|
||||
|
||||
import top.baogutang.demo.constants.enums.QueuePlatform;
|
||||
import top.baogutang.demo.message.IQueueMsg;
|
||||
import top.baogutang.demo.message.SendResult;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 10:56
|
||||
*/
|
||||
public interface IQueueMessageProducer {
|
||||
|
||||
QueuePlatform getPlatform();
|
||||
|
||||
/**
|
||||
* 发送延迟消息
|
||||
* @param topic 队列
|
||||
* @param queueMsg 消息
|
||||
* @return 发送结果
|
||||
*/
|
||||
<T> SendResult sendDelayMessage(String topic, IQueueMsg<T> queueMsg);
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package top.baogutang.demo.message.producer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.baogutang.demo.constants.enums.QueuePlatform;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 14:27
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MessageProducerFactory implements ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
public final Map<QueuePlatform, IQueueMessageProducer> producerMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
|
||||
Map<String, IQueueMessageProducer> beansOfType = applicationContext.getBeansOfType(IQueueMessageProducer.class);
|
||||
beansOfType.forEach((key, value) -> producerMap.put(value.getPlatform(), value));
|
||||
log.info(">>>>>>>>>>queue message producer inject complete<<<<<<<<<<");
|
||||
}
|
||||
|
||||
public IQueueMessageProducer getProducer(QueuePlatform platform) {
|
||||
return producerMap.get(platform);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package top.baogutang.demo.message.producer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.baogutang.demo.constants.enums.QueuePlatform;
|
||||
import top.baogutang.demo.message.IQueueMsg;
|
||||
import top.baogutang.demo.message.SendResult;
|
||||
import top.baogutang.demo.utils.JacksonUtil;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 11:43
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RedisQueueMessageProducer implements IQueueMessageProducer {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Override
|
||||
public QueuePlatform getPlatform() {
|
||||
return QueuePlatform.REDIS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SendResult sendDelayMessage(String topic, IQueueMsg<T> queueMsg) {
|
||||
long delayTime = System.currentTimeMillis() + queueMsg.getTimeUnit().toMillis(queueMsg.getDelayTime());
|
||||
Boolean addResult = null;
|
||||
try {
|
||||
addResult = redisTemplate.opsForZSet().add(topic, queueMsg, delayTime);
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>send delay message error:{} topic:{},message:{}<<<<<<<<<<", e.getMessage(), topic, JacksonUtil.toJson(queueMsg), e);
|
||||
return SendResult.builder()
|
||||
.success(Boolean.FALSE)
|
||||
.topic(topic)
|
||||
.build();
|
||||
}
|
||||
return SendResult.builder()
|
||||
.success(Boolean.TRUE.equals(addResult))
|
||||
.topic(topic)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package top.baogutang.demo.service;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 15:00
|
||||
*/
|
||||
public interface IConsumeMessageService {
|
||||
|
||||
<T> void consumeRedisMessage(String messageTopic);
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package top.baogutang.demo.service;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 14:40
|
||||
*/
|
||||
public interface ISendMessageService {
|
||||
|
||||
<T> void sendMessage(T msgBody, Long delayTime, TimeUnit timeUnit, String messageTopic);
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package top.baogutang.demo.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import top.baogutang.demo.message.IQueueMsg;
|
||||
import top.baogutang.demo.message.consumer.MessageConsumerFactory;
|
||||
import top.baogutang.demo.service.IConsumeMessageService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 15:00
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ConsumeMessageServiceImpl implements IConsumeMessageService {
|
||||
|
||||
@Resource
|
||||
private MessageConsumerFactory messageConsumerFactory;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void consumeRedisMessage(String messageTopic) {
|
||||
while (true) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
// 拉取到期消息
|
||||
Set<Object> queueMsgSet = redisTemplate.opsForZSet().rangeByScore(messageTopic, 0, currentTime);
|
||||
if (CollectionUtils.isEmpty(queueMsgSet)) {
|
||||
return;
|
||||
}
|
||||
queueMsgSet.forEach(queueMsgObj -> {
|
||||
IQueueMsg<T> queueMsg = (IQueueMsg<T>) queueMsgObj;
|
||||
messageConsumerFactory.getConsumer(queueMsg.getMsgType().getTopicName())
|
||||
.consume(queueMsg);
|
||||
// 删除已处理消息
|
||||
redisTemplate.opsForZSet().remove(messageTopic, queueMsgObj);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package top.baogutang.demo.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.baogutang.demo.constants.enums.QueuePlatform;
|
||||
import top.baogutang.demo.constants.enums.QueueType;
|
||||
import top.baogutang.demo.message.IQueueMsg;
|
||||
import top.baogutang.demo.message.QueueMsg;
|
||||
import top.baogutang.demo.message.SendResult;
|
||||
import top.baogutang.demo.message.producer.IQueueMessageProducer;
|
||||
import top.baogutang.demo.message.producer.MessageProducerFactory;
|
||||
import top.baogutang.demo.service.ISendMessageService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 14:40
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SendMessageServiceImpl implements ISendMessageService {
|
||||
|
||||
@Resource
|
||||
private MessageProducerFactory messageProducerFactory;
|
||||
|
||||
public <T> void sendMessage(T msgBody, Long delayTime, TimeUnit timeUnit,String messageTopic) {
|
||||
// TODO 业务消息key,可自定义
|
||||
String msgKey = UUID.randomUUID().toString();
|
||||
IQueueMsg<T> queueMsg = new QueueMsg<>(QueueType.IMAGE_PUSH, msgBody, msgKey);
|
||||
queueMsg.setDelayTime(delayTime);
|
||||
queueMsg.setTimeUnit(timeUnit);
|
||||
IQueueMessageProducer producer = messageProducerFactory.getProducer(QueuePlatform.REDIS);
|
||||
SendResult sendResult = producer.sendDelayMessage(messageTopic, queueMsg);
|
||||
if (Objects.isNull(sendResult) || !Boolean.TRUE.equals(sendResult.isSuccess())) {
|
||||
// TODO 消息发送不成功,逻辑处理
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
191
src/main/java/top/baogutang/demo/utils/JacksonUtil.java
Normal file
191
src/main/java/top/baogutang/demo/utils/JacksonUtil.java
Normal file
@ -0,0 +1,191 @@
|
||||
package top.baogutang.demo.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 11:50
|
||||
*/
|
||||
@Slf4j
|
||||
public class JacksonUtil {
|
||||
|
||||
private JacksonUtil() {
|
||||
// empty private constructor
|
||||
}
|
||||
|
||||
private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
|
||||
static {
|
||||
|
||||
// yyyy-MM-dd HH:mm:ss
|
||||
OBJECT_MAPPER.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_FORMAT));
|
||||
// JavaTimeModule Java 8
|
||||
OBJECT_MAPPER.registerModule(new JavaTimeModule());
|
||||
//
|
||||
OBJECT_MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
// ObjectMapper null
|
||||
OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
// ObjectMapper Bean ()
|
||||
OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
// ObjectMapper JSON Java
|
||||
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* json
|
||||
*
|
||||
* @param content
|
||||
* @return json
|
||||
*/
|
||||
public static String toJson(Object content) {
|
||||
String result = StringUtils.EMPTY;
|
||||
if (Objects.isNull(content)) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = OBJECT_MAPPER.writeValueAsString(content);
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse object to json fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param content
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> T fromJson(String content, Class<T> clazz) {
|
||||
T result = null;
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = OBJECT_MAPPER.readValue(content, clazz);
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse json to object fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param content
|
||||
* @param type
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> T fromJson(String content, TypeReference<T> type) {
|
||||
T result = null;
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = OBJECT_MAPPER.readValue(content, type);
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse json to object fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* jsonList
|
||||
*
|
||||
* @param content
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> jsonToList(String content, Class<T> clazz) {
|
||||
List<T> list = new ArrayList<>();
|
||||
if (StringUtils.isBlank(content) || clazz == null) {
|
||||
return list;
|
||||
}
|
||||
try {
|
||||
list = OBJECT_MAPPER.readValue(content, new TypeReference<List<T>>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse json to list fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* jsonMap
|
||||
*
|
||||
* @param content
|
||||
* @param keyType key
|
||||
* @param valueType value
|
||||
* @param <K> Class<K>
|
||||
* @param <V> Class<V>
|
||||
* @return Map
|
||||
*/
|
||||
public static <K, V> Map<K, V> jsonToMap(String content, Class<K> keyType, Class<V> valueType) {
|
||||
Map<K, V> result = new HashMap<>();
|
||||
if (StringUtils.isBlank(content) || Objects.isNull(keyType) || Objects.isNull(valueType)) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = OBJECT_MAPPER.readValue(content, new TypeReference<>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse json to map fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> beanToMap(Object content, Class<K> keyType, Class<V> valueType) {
|
||||
Map<K, V> result = new HashMap<>();
|
||||
if (Objects.isNull(content) || Objects.isNull(keyType) || Objects.isNull(valueType)) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = OBJECT_MAPPER.convertValue(content, new TypeReference<>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse json to map fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* jsonJsonNode
|
||||
*
|
||||
* @param content
|
||||
* @return JsonNode
|
||||
*/
|
||||
public static JsonNode jsonToNode(String content) {
|
||||
JsonNode jsonNode = null;
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
jsonNode = OBJECT_MAPPER.readTree(content);
|
||||
} catch (Exception e) {
|
||||
log.error(">>>>>>>>>>parse json to node fail:{}<<<<<<<<<<", e.getMessage());
|
||||
}
|
||||
return jsonNode;
|
||||
}
|
||||
}
|
||||
36
src/main/resources/application.yml
Normal file
36
src/main/resources/application.yml
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
server:
|
||||
port: 8106
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: ${SPRING_ACTIVE_PROFILE:local}
|
||||
application:
|
||||
name: baogutang-demo
|
||||
datasource:
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://117.72.78.133:3306/baogutang-music?characterEncoding=UTF-8
|
||||
username: baogutang-music
|
||||
password: xCcFfY3zXh8sC28e
|
||||
hikari:
|
||||
max-lifetime: 60000
|
||||
redis:
|
||||
host: 117.72.78.133
|
||||
port: 6379
|
||||
password: admin@pwdpwd
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 2048MB
|
||||
max-request-size: 32MB
|
||||
resources:
|
||||
static-locations: classpath:/templates/
|
||||
|
||||
thread:
|
||||
pool:
|
||||
core: 10
|
||||
max: 10
|
||||
alive: 10
|
||||
capacity: 200
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package top.baogutang.demo.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 15:26
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
class ConsumerServiceTest {
|
||||
|
||||
@Resource
|
||||
private IConsumeMessageService consumeMessageService;
|
||||
|
||||
private static final String MESSAGE_TOPIC = "baogutang.demo.message";
|
||||
|
||||
|
||||
@Test
|
||||
void test_consume_message() throws InterruptedException {
|
||||
consumeMessageService.consumeRedisMessage(MESSAGE_TOPIC);
|
||||
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package top.baogutang.demo.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import top.baogutang.demo.message.ImagePushMessage;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @description:
|
||||
*
|
||||
* @author: N1KO
|
||||
* @date: 2024/12/13 : 15:28
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
class SendMessageServiceTest {
|
||||
|
||||
@Resource
|
||||
private ISendMessageService sendMessageService;
|
||||
|
||||
private static final String MESSAGE_TOPIC = "baogutang.demo.message";
|
||||
|
||||
@Test
|
||||
void test_send_message() {
|
||||
ImagePushMessage imagePushMessage = new ImagePushMessage();
|
||||
imagePushMessage.setUserId(1L);
|
||||
sendMessageService.sendMessage(imagePushMessage, 2L, TimeUnit.SECONDS, MESSAGE_TOPIC);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user