代码初始化

This commit is contained in:
wangxiangshun
2025-10-02 17:19:01 +08:00
commit 5cc31cfbbe
474 changed files with 53553 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
package com.vetti.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author ID
* @date 2025/9/1 15:54
*/
@Component
@ConfigurationProperties(prefix = "here-map") // 配置前缀
@Data
public class HereMapsProperties {
private String apiKey;
private String geocodingApiUrl;
private String reverseGeocodingApiUrl;
private String routerApiUrl;
}

View File

@@ -0,0 +1,41 @@
package com.vetti.common.config;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.http.HttpClient;
import java.time.Duration;
import java.util.concurrent.Executors;
/**
* @author ID
* @date 2025/9/1 16:21
*/
@Configuration
public class HttpClientConfig {
@Value("${http.client.connect-timeout-seconds:10}")
private Integer connectTimeoutSeconds;
/**
* 创建并配置 HttpClient Bean.
* 该实例线程安全,建议在整个应用中复用。
*
* @return 配置好的 HttpClient 实例
*/
@Bean
public HttpClient httpClient() {
return HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) // 优先使用 HTTP/2若服务器不支持则降级至 HTTP/1.1
.connectTimeout(Duration.ofSeconds(connectTimeoutSeconds)) // 建立连接的超时时间
.followRedirects(HttpClient.Redirect.NORMAL) // 处理重定向策略 (NORMAL: 同协议重定向)
.executor(Executors.newVirtualThreadPerTaskExecutor()) // 使用虚拟线程执行器Java 21+,可选)
.build();
}
}

View File

@@ -0,0 +1,84 @@
package com.vetti.common.config;
import cn.hutool.core.util.StrUtil;
import com.vetti.common.enums.InternationalLangTypeEnum;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 国际化配置属性
*
* @author wangxiangshun
*/
@Data
@Component
@ConfigurationProperties(prefix = "vetti.international")
public class InternationalProperties {
/**
* 是否启用默认为False
*/
private boolean enable = true;
/**
* 请求语言参数位置HEADER/PARAM默认为HEADER
*/
private RequestLangParamPosition paramPosition = RequestLangParamPosition.HEADER;
/**
* 请求语言参数名称默认为lang
*/
private String paramName = "lang";
/**
* 获取请求语言
*
* @return 请求语言
*/
public String getLang() {
HttpServletRequest request = null;
try {
request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
} catch (Exception ex) {
// ignore
}
if (null == request) {
return null;
}
String lang;
if (paramPosition == RequestLangParamPosition.HEADER) {
lang = request.getHeader(paramName);
} else {
lang = request.getParameter(paramName);
}
//语言类型特殊转换
if(StrUtil.isNotEmpty(lang)){
lang = lang.replaceAll("-Hans-","_").replaceAll("-Hant-","_").
replaceAll("_Hans_","_").replaceAll("_Hant_","_").replaceAll("-","_");
if(lang.contains("en") || lang.contains("EN")){
lang = InternationalLangTypeEnum.INTERNATIONAL_LANG_TYPE_ENUM_EN.getCode();
}else if(lang.contains("zh") || lang.contains("ZH")){
lang = InternationalLangTypeEnum.INTERNATIONAL_LANG_TYPE_ENUM_ZH.getCode();
}
}else {
lang = InternationalLangTypeEnum.INTERNATIONAL_LANG_TYPE_ENUM_EN.getCode();
}
return lang;
}
/**
* 请求语言参数位置
*/
public enum RequestLangParamPosition {
HEADER, PARAM
}
}

View File

@@ -0,0 +1,46 @@
package com.vetti.common.config;
import io.minio.MinioClient;
import lombok.Data;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Data
@Configuration
public class MinioConfig {
@Value("${fs.minio.endpoint}")
private String endpoint;
@Value("${fs.minio.access-key}")
private String accessKey;
@Value("${fs.minio.secret-key}")
private String secretKey;
// 1. 配置 OkHttp 客户端(设置超时参数)
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(300, TimeUnit.SECONDS) // 连接超时
.readTimeout(600, TimeUnit.SECONDS) // 读取超时
.writeTimeout(600, TimeUnit.SECONDS) // 写入超时
.retryOnConnectionFailure(true) // 连接失败重试
.build();
/**
* 创建 MinIO 客户端实例
*/
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.httpClient(okHttpClient)
.build();
}
}

View File

@@ -0,0 +1,122 @@
package com.vetti.common.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* @author ruoyi
*/
@Component
@ConfigurationProperties(prefix = "vetti")
public class RuoYiConfig
{
/** 项目名称 */
private String name;
/** 版本 */
private String version;
/** 版权年份 */
private String copyrightYear;
/** 上传路径 */
private static String profile;
/** 获取地址开关 */
private static boolean addressEnabled;
/** 验证码类型 */
private static String captchaType;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
public String getCopyrightYear()
{
return copyrightYear;
}
public void setCopyrightYear(String copyrightYear)
{
this.copyrightYear = copyrightYear;
}
public static String getProfile()
{
return profile;
}
public void setProfile(String profile)
{
RuoYiConfig.profile = profile;
}
public static boolean isAddressEnabled()
{
return addressEnabled;
}
public void setAddressEnabled(boolean addressEnabled)
{
RuoYiConfig.addressEnabled = addressEnabled;
}
public static String getCaptchaType() {
return captchaType;
}
public void setCaptchaType(String captchaType) {
RuoYiConfig.captchaType = captchaType;
}
/**
* 获取导入上传路径
*/
public static String getImportPath()
{
return getProfile() + "/import";
}
/**
* 获取头像上传路径
*/
public static String getAvatarPath()
{
return getProfile() + "/avatar";
}
/**
* 获取下载路径
*/
public static String getDownloadPath()
{
return getProfile() + "/download/";
}
/**
* 获取上传路径
*/
public static String getUploadPath()
{
return getProfile() + "/upload";
}
}

View File

@@ -0,0 +1,27 @@
package com.vetti.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author ID
* @date 2025/8/28 14:00
*/
@Data
@Component
@ConfigurationProperties(prefix = "twilio.sendgrid")
public class TwilioConfig {
private String apiKey;
private String fromEmail;
private String fromName;
private TemplateIds templateIds;
@Data
public static class TemplateIds {
private String routezVerificationCode;
}
}

View File

@@ -0,0 +1,17 @@
package com.vetti.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author ID
* @date 2025/8/28 14:01
*/
@Data
@Component
@ConfigurationProperties(prefix = "verification.code.email")
public class VerificationEmailConfig {
private int length;
private int expirationMinutes;
}

View File

@@ -0,0 +1,67 @@
package com.vetti.common.config.serializer;
import java.io.IOException;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.vetti.common.annotation.Sensitive;
import com.vetti.common.core.domain.model.LoginUser;
import com.vetti.common.enums.DesensitizedType;
import com.vetti.common.utils.SecurityUtils;
/**
* 数据脱敏序列化过滤
*
* @author ruoyi
*/
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
{
private DesensitizedType desensitizedType;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException
{
if (desensitization())
{
gen.writeString(desensitizedType.desensitizer().apply(value));
}
else
{
gen.writeString(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException
{
Sensitive annotation = property.getAnnotation(Sensitive.class);
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
{
this.desensitizedType = annotation.desensitizedType();
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
/**
* 是否需要脱敏处理
*/
private boolean desensitization()
{
try
{
LoginUser securityUser = SecurityUtils.getLoginUser();
// 管理员不脱敏
return !securityUser.getUser().isAdmin();
}
catch (Exception e)
{
return true;
}
}
}