add export config

This commit is contained in:
Timi
2026-04-08 11:56:07 +08:00
parent 8947269351
commit ef192daa93
10 changed files with 95 additions and 194 deletions

View File

@@ -1,10 +1,6 @@
package com.imyeyu.api; package com.imyeyu.api;
import com.imyeyu.io.IO; import com.imyeyu.io.IO;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.Language;
import com.imyeyu.java.ref.Ref;
import com.imyeyu.spring.TimiSpring;
import com.imyeyu.utils.OS; import com.imyeyu.utils.OS;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -13,7 +9,6 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.io.File; import java.io.File;
@@ -31,8 +26,6 @@ import java.io.File;
@EnableTransactionManagement @EnableTransactionManagement
public class TimiServerAPI implements OS.FileSystem, ApplicationContextAware { public class TimiServerAPI implements OS.FileSystem, ApplicationContextAware {
private static final String DEV_LANG_CONFIG = "dev.lang";
public static ApplicationContext applicationContext; public static ApplicationContext applicationContext;
@Override @Override
@@ -40,32 +33,18 @@ public class TimiServerAPI implements OS.FileSystem, ApplicationContextAware {
TimiServerAPI.applicationContext = applicationContext; TimiServerAPI.applicationContext = applicationContext;
} }
public static Language.Enum getUserLanguage() {
Language.Enum userLanguage = TimiSpring.getLanguage();
Environment env = applicationContext.getBean(Environment.class);
if (env.containsProperty(DEV_LANG_CONFIG)) {
String property = env.getProperty(DEV_LANG_CONFIG);
if (TimiJava.isNotEmpty(property)) {
userLanguage = Ref.toType(Language.Enum.class, property);
}
}
return userLanguage;
}
public static void main(String[] args) { public static void main(String[] args) {
try { try {
{ {
// 导出配置 File application = new File("config" + SEP + "application.yml");
String[] files = {"application.yml", "logback.xml"}; if (!application.exists()) {
for (int i = 0; i < files.length; i++) { IO.resourceToDisk(TimiServerAPI.class, "application_export.yml", application.getAbsolutePath());
File file = new File("config" + SEP + files[i]); }
if (!file.exists() || !file.isFile()) { File logback = new File("config" + SEP + "logback.xml");
log.info("exporting default config at {}", file.getAbsolutePath()); if (!logback.exists()) {
IO.resourceToDisk(TimiServerAPI.class, files[i], file.getAbsolutePath()); IO.resourceToDisk(TimiServerAPI.class, "logback.xml", logback.getAbsolutePath());
}
} }
} }
// 启动 SpringBoot // 启动 SpringBoot
SpringApplication.run(TimiServerAPI.class, args); SpringApplication.run(TimiServerAPI.class, args);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -29,21 +29,12 @@ public class CORSConfig {
/** 允许跨域的地址 */ /** 允许跨域的地址 */
private String[] allowOrigin; private String[] allowOrigin;
/** 是否允许请求带有验证信息 */
private boolean allowCredentials;
/** 允许请求的方法 */
private String allowMethods;
/** 允许服务端访问的客户端请求头 */
private String allowHeaders;
@Bean @Bean
public FilterRegistrationBean<Filter> corsFilter() { public FilterRegistrationBean<Filter> corsFilter() {
CorsConfiguration config = new CorsConfiguration(); CorsConfiguration config = new CorsConfiguration();
config.addAllowedHeader(allowHeaders); config.addAllowedHeader("*");
config.addAllowedMethod(allowMethods); config.addAllowedMethod("*");
config.setAllowCredentials(allowCredentials); config.setAllowCredentials(true);
config.setAllowedOriginPatterns(Arrays.asList(allowOrigin)); config.setAllowedOriginPatterns(Arrays.asList(allowOrigin));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

View File

@@ -1,14 +1,17 @@
package com.imyeyu.api.config; package com.imyeyu.api.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imyeyu.api.modules.blog.entity.ArticleRanking; import com.imyeyu.api.modules.blog.entity.ArticleRanking;
import com.imyeyu.api.modules.common.entity.Multilingual; import com.imyeyu.api.modules.common.entity.Multilingual;
import com.imyeyu.spring.bean.RedisConfigParams; import com.imyeyu.spring.bean.RedisConfigParams;
import com.imyeyu.spring.config.AbstractRedisConfig; import com.imyeyu.spring.config.AbstractRedisConfig;
import com.imyeyu.spring.util.Redis; import com.imyeyu.spring.util.Redis;
import com.imyeyu.spring.util.RedisSerializers; import com.imyeyu.spring.util.RedisSerializers;
import com.imyeyu.utils.Time;
import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.api.StatefulConnection;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -33,9 +36,12 @@ import java.time.Duration;
@Configuration @Configuration
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@EnableAutoConfiguration @EnableAutoConfiguration
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "spring.redis") @ConfigurationProperties(prefix = "spring.redis")
public class RedisConfig extends AbstractRedisConfig { public class RedisConfig extends AbstractRedisConfig {
private final ObjectMapper jackson;
// ---------- 连接配置 ---------- // ---------- 连接配置 ----------
/** 地址 */ /** 地址 */
@@ -47,50 +53,9 @@ public class RedisConfig extends AbstractRedisConfig {
/** 密码 */ /** 密码 */
private String password; private String password;
/** 超时(毫秒) */
private int timeout;
/** 连接池 */
private Lettuce lettuce;
/** 数据库 */ /** 数据库 */
private Database database; private Database database;
/**
* 连接池
*
* @author 夜雨
* @since 2023-08-21 16:23
*/
@Data
public static class Lettuce {
/** 配置 */
private Pool pool;
/**
* 配置
*
* @author 夜雨
* @since 2023-08-21 16:23
*/
@Data
public static class Pool {
/** 最大活跃连接 */
private int maxActive;
/** 最小空闲连接 */
private int minIdle;
/** 最大空闲连接 */
private int maxIdle;
/** 最大等待时间(秒) */
private int maxWait;
}
}
/** /**
* 数据库 * 数据库
* *
@@ -146,10 +111,10 @@ public class RedisConfig extends AbstractRedisConfig {
setHost(host); setHost(host);
setPort(port); setPort(port);
setPassword(password); setPassword(password);
setTimeout(timeout); setTimeout(Time.SI * 8);
setMaxActive(lettuce.pool.maxActive); setMaxActive(8);
setMinIdle(lettuce.pool.minIdle); setMinIdle(1);
setMaxIdle(lettuce.pool.maxIdle); setMaxIdle(8);
}}; }};
} }
@@ -226,7 +191,7 @@ public class RedisConfig extends AbstractRedisConfig {
/** @return 文章访问统计,文章 ID: {@link ArticleRanking}(JSON) */ /** @return 文章访问统计,文章 ID: {@link ArticleRanking}(JSON) */
@Bean("redisArticleRanking") @Bean("redisArticleRanking")
public Redis<Long, ArticleRanking> getArticleRankingRedisTemplate() { public Redis<Long, ArticleRanking> getArticleRankingRedisTemplate() {
return getRedis(database.articleRanking, RedisSerializers.LONG, RedisSerializers.jacksonSerializer(ArticleRanking.class)); return getRedis(database.articleRanking, RedisSerializers.LONG, RedisSerializers.jacksonSerializer(jackson, ArticleRanking.class));
} }
/** @return 文章访问记录IP: [文章 ID] */ /** @return 文章访问记录IP: [文章 ID] */

View File

@@ -2,8 +2,6 @@ package com.imyeyu.api.config;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -19,37 +17,17 @@ import java.util.concurrent.ThreadPoolExecutor;
@Data @Data
@Slf4j @Slf4j
@Configuration @Configuration
@EnableAutoConfiguration
@ConfigurationProperties(prefix = "spring.async.thread-pool")
public class ThreadPoolConfig { public class ThreadPoolConfig {
/** 核心数量 */
private int corePoolSize;
/** 最大数量 */
private int maxPoolSize;
/** 等待区容量 */
private int queueCapacity;
/** 最大保持活跃时间(秒) */
private int keepAliveSeconds;
/** 最大等待时间(秒) */
private int awaitTerminationSeconds;
/** 线程名称前缀 */
private String threadNamePrefix;
@Bean(name = "threadPoolTaskExecutor") @Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() { public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize); executor.setCorePoolSize(16);
executor.setMaxPoolSize(maxPoolSize); executor.setMaxPoolSize(32);
executor.setQueueCapacity(queueCapacity); executor.setQueueCapacity(16);
executor.setKeepAliveSeconds(keepAliveSeconds); executor.setKeepAliveSeconds(60);
executor.setAwaitTerminationSeconds(awaitTerminationSeconds); executor.setAwaitTerminationSeconds(60);
executor.setThreadNamePrefix(threadNamePrefix); executor.setThreadNamePrefix("thread-pool-task-executor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize(); executor.initialize();
return executor; return executor;

View File

@@ -70,8 +70,8 @@ public class GiteaDBConfig {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<String> mapperLocations = new ArrayList<>(); List<String> mapperLocations = new ArrayList<>();
mapperLocations.add("classpath:mapper/gitea/**/*.xml"); mapperLocations.add("classpath:mapper/gitea/**/*.xml");
for (int i = 0; i < mapperLocations.size(); i++) { for (String mapperLocation : mapperLocations) {
resources.addAll(List.of(resourceResolver.getResources(mapperLocations.get(i)))); resources.addAll(List.of(resourceResolver.getResources(mapperLocation)));
} }
} }
String[] typeAliases = { String[] typeAliases = {

View File

@@ -83,8 +83,8 @@ public class TimiServerDBConfig {
mapperLocations.add("classpath:mapper/system/**/*.xml"); mapperLocations.add("classpath:mapper/system/**/*.xml");
mapperLocations.add("classpath:mapper/journal/**/*.xml"); mapperLocations.add("classpath:mapper/journal/**/*.xml");
mapperLocations.add("classpath:mapper/minecraft/**/*.xml"); mapperLocations.add("classpath:mapper/minecraft/**/*.xml");
for (int i = 0; i < mapperLocations.size(); i++) { for (String mapperLocation : mapperLocations) {
resources.addAll(List.of(resourceResolver.getResources(mapperLocations.get(i)))); resources.addAll(List.of(resourceResolver.getResources(mapperLocation)));
} }
} }
String[] typeAliases = { String[] typeAliases = {

View File

@@ -1,8 +1,9 @@
package com.imyeyu.api.modules.blog.entity; package com.imyeyu.api.modules.blog.entity;
import com.imyeyu.spring.entity.Entity;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import com.imyeyu.spring.entity.Entity; import lombok.NoArgsConstructor;
/** /**
* 访问排行(每周) * 访问排行(每周)
@@ -12,6 +13,7 @@ import com.imyeyu.spring.entity.Entity;
* @since 2021-03-01 17:10 * @since 2021-03-01 17:10
*/ */
@Data @Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class ArticleRanking extends Entity { public class ArticleRanking extends Entity {

View File

@@ -3,7 +3,6 @@ package com.imyeyu.api.util;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.imyeyu.api.TimiServerAPI;
import com.imyeyu.api.modules.common.bean.SettingKey; import com.imyeyu.api.modules.common.bean.SettingKey;
import com.imyeyu.api.modules.common.entity.Multilingual; import com.imyeyu.api.modules.common.entity.Multilingual;
import com.imyeyu.api.modules.common.entity.Setting; import com.imyeyu.api.modules.common.entity.Setting;
@@ -11,6 +10,7 @@ import com.imyeyu.api.modules.common.service.SettingService;
import com.imyeyu.api.modules.system.bean.ServerFile; import com.imyeyu.api.modules.system.bean.ServerFile;
import com.imyeyu.java.ref.Ref; import com.imyeyu.java.ref.Ref;
import com.imyeyu.lang.mapper.AbstractLanguageMapper; import com.imyeyu.lang.mapper.AbstractLanguageMapper;
import com.imyeyu.spring.TimiSpring;
import com.imyeyu.spring.util.GlobalReturnHandler; import com.imyeyu.spring.util.GlobalReturnHandler;
import com.imyeyu.spring.util.Redis; import com.imyeyu.spring.util.Redis;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -80,9 +80,8 @@ public class InitApplication implements ApplicationRunner {
} }
private void initMultilingual() { private void initMultilingual() {
// redisLanguage.flushAll();
globalReturnHandler.setMultilingualHeader(mapping -> { globalReturnHandler.setMultilingualHeader(mapping -> {
AbstractLanguageMapper map = redisMultilingual.map(TimiServerAPI.getUserLanguage()); AbstractLanguageMapper map = redisMultilingual.map(TimiSpring.getLanguage());
return map.textArgs(mapping.getMsgKey(), mapping.getMsgArgs()); return map.textArgs(mapping.getMsgKey(), mapping.getMsgArgs());
}); });
} }

View File

@@ -1,5 +1,4 @@
server: server:
port: 8091
shutdown: graceful shutdown: graceful
# 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境 # 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境
@@ -12,26 +11,13 @@ logging:
# Spring # Spring
spring: spring:
profiles:
active: prod
servlet: servlet:
multipart: multipart:
max-file-size: 4GB max-file-size: 4GB
max-request-size: 4GB max-request-size: 4GB
lifecycle: lifecycle:
timeout-per-shutdown-phase: 32s timeout-per-shutdown-phase: 32s
async: mail:
thread-pool:
core-pool-size: 16
max-pool-size: 32
queueCapacity: 16
keep-alive-seconds: 60
thread-name-prefix: thread-pool-task-executor-
await-termination-seconds: 60
mail: # 邮件配置
host: smtp.qq.com
username: imyeyu@qq.com
password: saodifhaposjfoas
properties: properties:
mail: mail:
smtp: smtp:
@@ -40,60 +26,3 @@ spring:
enable: true enable: true
required: true required: true
default-encoding: UTF-8 default-encoding: UTF-8
redis: # Redis 数据库
host: dev.vm.imyeyu.test
port: 6379
password:
timeout: 8000
database:
locker: 0 # ID: Integer 全局锁ID 规范:应用:模块:业务:方法
multilingual: 1 # ID: Multilingual 多语言缓存
multilingual-map: 2 # Key: ID 多语言键缓存
article-ranking: 3 # AID: ArticleRanking(JSON) 热门文章排位
article-read: 4 # IP: [AID..] IP 阅读文章记录
user-token: 5 # TOKEN: LONG 用户登录令牌
user-exp-flag: 6 # UID: NULL 用户登录经验标记,暂时没有值,数据死亡时间为次日零时
user-email-verify: 7 # AES_KEY: UID 邮箱验证密钥缓存
user-reset-pw-verify: 8 # AES_KEY: UID 重置密码密钥缓存
qps-limit: 9 # APP.IP.method: COUNT_IN_LIFE_CYCLE 接口访问频率控制(多个系统公用,需要 App 标记)
setting: 10 # Setting: SettingValue 系统配置
fmc-player-token: 11 # TOKEN: USER_ID|PLAYER_ID MC 登录缓存
clipboard: 12 # ID: CONTENT 共享剪切板
lettuce: # 连接池配置
pool:
max-wait: -1
max-idle: 8
min-idle: 0
max-active: 8
datasource: # 数据库配置
timiserver:
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/timi_server?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123123
driver-class-name: com.mysql.cj.jdbc.Driver
forevermc:
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/authme?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123123
driver-class-name: com.mysql.cj.jdbc.Driver
gitea:
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/authme?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123123
driver-class-name: com.mysql.cj.jdbc.Driver
data:
mongodb:
host: dev.vm.imyeyu.test
port: 27017
database: db
username: root
password: qweqwe123
# CORS 跨域
cors:
# 允许访问的客户端域名http://web.xxx.com* 表示不做任何限制(不做任何限制时 allow-credentials 无效)
allow-origin:
- "http://localhost:8080"
allow-methods: "*" # 允许请求的方法名多个方法名逗号分割GET, POST, PUT, DELETE, OPTIONS
allow-credentials: true # 是否允许请求带有验证信息,若要获取客户端域下的 Cookie 或 Session 时,设置为 true
allow-headers: "*" # 允许服务端访问的客户端请求头多个请求头逗号分割Content-BizType

View File

@@ -0,0 +1,58 @@
server:
port: 8091
# Spring
spring:
profiles:
active: prod
mail: # 邮件配置
host: smtp.qq.com
username: imyeyu@qq.com
password: saodifhaposjfoas
redis: # Redis 数据库
host: dev.vm.imyeyu.test
port: 6379
password:
database:
locker: 0 # ID: Integer 全局锁ID 规范:应用:模块:业务:方法
multilingual: 1 # ID: Multilingual 多语言缓存
multilingual-map: 2 # Key: ID 多语言键缓存
article-ranking: 3 # AID: ArticleRanking(JSON) 热门文章排位
article-read: 4 # IP: [AID..] IP 阅读文章记录
user-token: 5 # TOKEN: LONG 用户登录令牌
user-exp-flag: 6 # UID: NULL 用户登录经验标记,暂时没有值,数据死亡时间为次日零时
user-email-verify: 7 # AES_KEY: UID 邮箱验证密钥缓存
user-reset-pw-verify: 8 # AES_KEY: UID 重置密码密钥缓存
qps-limit: 9 # APP.IP.method: COUNT_IN_LIFE_CYCLE 接口访问频率控制(多个系统公用,需要 App 标记)
setting: 10 # Setting: SettingValue 系统配置
fmc-player-token: 11 # TOKEN: USER_ID|PLAYER_ID MC 登录缓存
clipboard: 12 # ID: CONTENT 共享剪切板
datasource: # 数据库配置
timiserver:
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/timi_server?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123123
driver-class-name: com.mysql.cj.jdbc.Driver
forevermc:
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/authme?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123123
driver-class-name: com.mysql.cj.jdbc.Driver
gitea:
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/authme?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123123
driver-class-name: com.mysql.cj.jdbc.Driver
data:
mongodb:
host: dev.vm.imyeyu.test
port: 27017
database: db
username: root
password: qweqwe123
# CORS 跨域
cors:
# 允许访问的客户端域名http://web.xxx.com* 表示不做任何限制(不做任何限制时 allow-credentials 无效)
allow-origin:
- "http://localhost:8080"