diff --git a/.bundle/config b/.bundle/config
deleted file mode 100644
index 2369228..0000000
--- a/.bundle/config
+++ /dev/null
@@ -1,2 +0,0 @@
----
-BUNDLE_PATH: "vendor/bundle"
diff --git a/pom.xml b/pom.xml
index 81ec7c3..f7acf82 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,6 +22,10 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
org.springframework.boot
spring-boot-starter-web
@@ -116,6 +120,50 @@
test
4.12
+
+ org.mockito
+ mockito-inline
+ test
+
+
+ org.ansj
+ ansj_seg
+ 5.1.1
+
+
+ com.baidu.aip
+ java-sdk
+ 4.16.2
+
+
+ org.apache.mahout
+ mahout-core
+ 0.9
+
+
+ org.apache.mahout
+ mahout-integration
+
+
+ jdk.tools
+ jdk.tools
+
+
+ 0.13.0
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+ 1.7.3
+
diff --git a/src/main/java/com/privateboat/forum/backend/BusinessBackendApplication.java b/src/main/java/com/privateboat/forum/backend/BusinessBackendApplication.java
index fbe2f4c..7edc49e 100644
--- a/src/main/java/com/privateboat/forum/backend/BusinessBackendApplication.java
+++ b/src/main/java/com/privateboat/forum/backend/BusinessBackendApplication.java
@@ -1,27 +1,31 @@
package com.privateboat.forum.backend;
-import org.modelmapper.ModelMapper;
+import com.privateboat.forum.backend.configuration.GeneralConfig;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Bean;
-
-import javax.annotation.PostConstruct;
-import java.util.TimeZone;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.scheduling.annotation.EnableScheduling;
+@Slf4j
+@EnableScheduling
+@EnableCaching
@SpringBootApplication
public class BusinessBackendApplication {
-
- @Bean
- public ModelMapper modelMapper(){
- return new ModelMapper();
- }
-
public static void main(String[] args) {
+ processArg(args);
SpringApplication.run(BusinessBackendApplication.class, args);
}
- @PostConstruct
- public void init(){
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+08:00"));
+ private static void processArg(String[] args) {
+ for (String arg: args) {
+ if (!arg.startsWith("--")) continue;
+
+ String processedArg = arg.substring(2);
+ if (processedArg.equals("disable-audition")) {
+ GeneralConfig.enableAudition = false;
+ break;
+ }
+ }
}
}
diff --git a/src/main/java/com/privateboat/forum/backend/cloudclient/BaiduClient.java b/src/main/java/com/privateboat/forum/backend/cloudclient/BaiduClient.java
new file mode 100644
index 0000000..903fb4e
--- /dev/null
+++ b/src/main/java/com/privateboat/forum/backend/cloudclient/BaiduClient.java
@@ -0,0 +1,20 @@
+package com.privateboat.forum.backend.cloudclient;
+
+import com.baidu.aip.contentcensor.AipContentCensor;
+
+public class BaiduClient {
+ private static final String APP_ID = "24640861";
+ private static final String API_KEY = "pSG1FAHhdoDskf02DKWgj6vW";
+ private static final String SECRET_KEY = "a2yexzd8XkAewoekLZd2y0nZnQAv0Nrm";
+
+ private static AipContentCensor client;
+
+ synchronized public static AipContentCensor getClient() {
+ if (client == null) {
+ client = new AipContentCensor(APP_ID, API_KEY, SECRET_KEY);
+ client.setConnectionTimeoutInMillis(2000);
+ client.setSocketTimeoutInMillis(60000);
+ }
+ return client;
+ }
+}
diff --git a/src/main/java/com/privateboat/forum/backend/cloudclient/TencentCOSClient.java b/src/main/java/com/privateboat/forum/backend/cloudclient/TencentCOSClient.java
new file mode 100644
index 0000000..7f52a3b
--- /dev/null
+++ b/src/main/java/com/privateboat/forum/backend/cloudclient/TencentCOSClient.java
@@ -0,0 +1,27 @@
+package com.privateboat.forum.backend.cloudclient;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.http.HttpProtocol;
+import com.qcloud.cos.region.Region;
+
+import static com.privateboat.forum.backend.util.Constant.SECRET_ID;
+import static com.privateboat.forum.backend.util.Constant.SECRET_KEY;
+
+public class TencentCOSClient {
+ private static COSClient client;
+
+ public static COSClient getClient() {
+ if (client == null) {
+ final COSCredentials cred = new BasicCOSCredentials(SECRET_ID, SECRET_KEY);
+ final Region region = new Region("ap-shanghai");
+ final ClientConfig clientConfig = new ClientConfig(region);
+ clientConfig.setHttpProtocol(HttpProtocol.https);
+
+ client = new COSClient(cred, clientConfig);
+ }
+ return client;
+ }
+}
diff --git a/src/main/java/com/privateboat/forum/backend/configuration/BeanConfig.java b/src/main/java/com/privateboat/forum/backend/configuration/BeanConfig.java
index ab92f1b..e5961f3 100644
--- a/src/main/java/com/privateboat/forum/backend/configuration/BeanConfig.java
+++ b/src/main/java/com/privateboat/forum/backend/configuration/BeanConfig.java
@@ -1,11 +1,11 @@
package com.privateboat.forum.backend.configuration;
+import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-
@Configuration
public class BeanConfig {
@Bean
@@ -17,5 +17,11 @@ public BCryptPasswordEncoder getEncoder() {
public SpelAwareProxyProjectionFactory projectionFactory() {
return new SpelAwareProxyProjectionFactory();
}
+
+ @Bean
+ public ModelMapper modelMapper(){
+ return new ModelMapper();
+ }
+
}
diff --git a/src/main/java/com/privateboat/forum/backend/configuration/BootConfig.java b/src/main/java/com/privateboat/forum/backend/configuration/BootConfig.java
new file mode 100644
index 0000000..d326acb
--- /dev/null
+++ b/src/main/java/com/privateboat/forum/backend/configuration/BootConfig.java
@@ -0,0 +1,27 @@
+package com.privateboat.forum.backend.configuration;
+
+import com.privateboat.forum.backend.util.RedisUtil;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+@AllArgsConstructor
+public class BootConfig implements ApplicationRunner {
+ final RedisUtil redisUtil;
+
+ @Override
+ public void run(ApplicationArguments args) {
+ log.info("有可奉告业务后端启动成功!");
+ log.info("检查Redis数据库初始化");
+ redisUtil.initializeRecord();
+ log.info("Redis数据库初始化检查完成");
+
+ if (!GeneralConfig.enableAudition) {
+ log.info("图片与文字审核已禁用");
+ }
+ }
+}
diff --git a/src/main/java/com/privateboat/forum/backend/configuration/GeneralConfig.java b/src/main/java/com/privateboat/forum/backend/configuration/GeneralConfig.java
new file mode 100644
index 0000000..4e3d8d2
--- /dev/null
+++ b/src/main/java/com/privateboat/forum/backend/configuration/GeneralConfig.java
@@ -0,0 +1,5 @@
+package com.privateboat.forum.backend.configuration;
+
+public class GeneralConfig {
+ public static Boolean enableAudition = true;
+}
diff --git a/src/main/java/com/privateboat/forum/backend/configuration/RabbitMQConfig.java b/src/main/java/com/privateboat/forum/backend/configuration/RabbitMQConfig.java
new file mode 100644
index 0000000..beff166
--- /dev/null
+++ b/src/main/java/com/privateboat/forum/backend/configuration/RabbitMQConfig.java
@@ -0,0 +1,119 @@
+package com.privateboat.forum.backend.configuration;
+
+import org.springframework.amqp.core.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RabbitMQConfig {
+
+ public static final String RECORD_EXCHANGE = "record-exchange";
+ public static final String CACHE_EXCHANGE = "cache-exchange";
+ public static final String STATISTIC_EXCHANGE = "statistic-exchange";
+ public static final String CHAT_EXCHANGE = "chat-exchange";
+
+ public static final String FOLLOW_QUEUE = "follow-queue";
+ public static final String APPROVAL_QUEUE = "approval-queue";
+ public static final String STAR_QUEUE = "star-queue";
+ public static final String REPLY_QUEUE = "reply-queue";
+ public static final String COMMENT_CACHE_UPDATE_QUEUE = "cache-queue";
+ public static final String STATISTIC_QUEUE = "statistic-queue";
+ public static final String CHAT_QUEUE = "chat-queue";
+
+ public static final String FOLLOW_KEY = "follow";
+ public static final String APPROVAL_KEY = "approval";
+ public static final String STAR_KEY = "star";
+ public static final String REPLY_KEY = "reply";
+ public static final String CACHE_KEY = "cache";
+ public static final String STATISTIC_KEY = "statistic";
+ public static final String CHAT_KEY = "chat";
+
+ @Bean
+ public Queue followQueue() {
+ return new Queue(FOLLOW_QUEUE, true);
+ }
+
+ @Bean
+ public Queue approvalQueue() {
+ return new Queue(APPROVAL_QUEUE, true);
+ }
+
+ @Bean
+ public Queue starQueue() {
+ return new Queue(STAR_QUEUE, true);
+ }
+
+ @Bean
+ public Queue replyQueue() {
+ return new Queue(REPLY_QUEUE, true);
+ }
+
+ @Bean
+ public Queue cacheQueue() {
+ return new Queue(COMMENT_CACHE_UPDATE_QUEUE, true);
+ }
+
+ @Bean
+ public Queue statisticQueue() {
+ return new Queue(STATISTIC_QUEUE, true);
+ }
+
+ @Bean Queue chatQueue() {
+ return new Queue(CHAT_QUEUE, true);
+ }
+
+ @Bean
+ public DirectExchange recordExchange() {
+ return new DirectExchange(RECORD_EXCHANGE);
+ }
+
+ @Bean
+ public DirectExchange cacheExchange() {
+ return new DirectExchange(CACHE_EXCHANGE);
+ }
+
+ @Bean
+ public DirectExchange statisticExchange() {
+ return new DirectExchange(STATISTIC_EXCHANGE);
+ }
+
+ @Bean
+ public DirectExchange chatExchange() {
+ return new DirectExchange(CHAT_EXCHANGE);
+ }
+
+ @Bean
+ public Binding followBinding() {
+ return BindingBuilder.bind(followQueue()).to(recordExchange()).with(FOLLOW_KEY);
+ }
+
+ @Bean
+ public Binding approvalBinding() {
+ return BindingBuilder.bind(approvalQueue()).to(recordExchange()).with(APPROVAL_KEY);
+ }
+
+ @Bean
+ public Binding starBinding() {
+ return BindingBuilder.bind(starQueue()).to(recordExchange()).with(STAR_KEY);
+ }
+
+ @Bean
+ public Binding replyBinding() {
+ return BindingBuilder.bind(replyQueue()).to(recordExchange()).with(REPLY_KEY);
+ }
+
+ @Bean
+ public Binding cacheBinding() {
+ return BindingBuilder.bind(cacheQueue()).to(cacheExchange()).with(CACHE_KEY);
+ }
+
+ @Bean
+ public Binding postBinding() {
+ return BindingBuilder.bind(statisticQueue()).to(statisticExchange()).with(STATISTIC_KEY);
+ }
+
+ @Bean
+ public Binding chatBinding() {
+ return BindingBuilder.bind(chatQueue()).to(chatExchange()).with(CHAT_KEY);
+ }
+}
diff --git a/src/main/java/com/privateboat/forum/backend/configuration/RedisConfig.java b/src/main/java/com/privateboat/forum/backend/configuration/RedisConfig.java
new file mode 100644
index 0000000..bebd8fe
--- /dev/null
+++ b/src/main/java/com/privateboat/forum/backend/configuration/RedisConfig.java
@@ -0,0 +1,114 @@
+package com.privateboat.forum.backend.configuration;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.Cache;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.interceptor.CacheErrorHandler;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.*;
+
+import java.time.Duration;
+import java.util.Objects;
+
+@Slf4j
+@Configuration
+@AllArgsConstructor
+public class RedisConfig extends CachingConfigurerSupport {
+ Environment env;
+
+ @Bean
+ public LettuceConnectionFactory connectionFactory() {
+ RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
+ configuration.setHostName(Objects.requireNonNull(env.getProperty("spring.redis.host")));
+ configuration.setPort(Integer.parseInt(Objects.requireNonNull(env.getProperty("spring.redis.port"))));
+ configuration.setPassword("comment_overflow123");
+ return new LettuceConnectionFactory(configuration);
+ }
+
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(connectionFactory);
+
+ StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+ Jackson2JsonRedisSerializer