代码初始化
This commit is contained in:
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user