Compare commits
27 Commits
dev/dev_xp
...
23716984cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23716984cc | ||
|
|
d0b8b8d674 | ||
|
|
92e7dbf258 | ||
|
|
32a228485b | ||
|
|
560e47747a | ||
|
|
c8dc38575a | ||
|
|
c00d906083 | ||
| 4df3f9cc53 | |||
|
|
b0343be544 | ||
|
|
d33cb9f0bf | ||
|
|
40f2735831 | ||
| 01d3806d5f | |||
| 107e4e9771 | |||
|
|
716d720782 | ||
|
|
6b5bacc49b | ||
|
|
409bc7b1fd | ||
|
|
ec6a5df8af | ||
|
|
029b96ae99 | ||
|
|
14002e7331 | ||
| 14dfe2806c | |||
| 798c7b0592 | |||
| 9bd10581f4 | |||
| 1f288fe5e3 | |||
| 72602eb245 | |||
| 983d53268d | |||
| f3aeeb3584 | |||
| 5d3692a204 |
59
pom.xml
59
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>3.1.6</version>
|
<version>3.2.5</version>
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.aida</groupId>
|
<groupId>com.aida</groupId>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<description>ai da</description>
|
<description>ai da</description>
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
<mybatis.plus.version>3.5.5</mybatis.plus.version>
|
<mybatis.plus.version>3.5.7</mybatis.plus.version>
|
||||||
<hutool.version>5.8.23</hutool.version>
|
<hutool.version>5.8.23</hutool.version>
|
||||||
<wx.java.version>4.2.7.B</wx.java.version>
|
<wx.java.version>4.2.7.B</wx.java.version>
|
||||||
<fastjson.version>2.0.43</fastjson.version>
|
<fastjson.version>2.0.43</fastjson.version>
|
||||||
@@ -28,6 +28,11 @@
|
|||||||
<javacv.version>1.5.5</javacv.version>
|
<javacv.version>1.5.5</javacv.version>
|
||||||
<system.windowsx64>windows-x86_64</system.windowsx64>
|
<system.windowsx64>windows-x86_64</system.windowsx64>
|
||||||
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
|
||||||
|
|
||||||
|
<!-- Spring Cloud Alibaba 版本 -->
|
||||||
|
<spring-cloud-alibaba.version>2023.0.3.4</spring-cloud-alibaba.version>
|
||||||
|
<!-- Spring Cloud 版本 -->
|
||||||
|
<spring-cloud.version>2023.0.4</spring-cloud.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -38,6 +43,22 @@
|
|||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Spring Cloud 依赖版本管理 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring Cloud Alibaba 依赖版本管理 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud-alibaba.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -74,9 +95,14 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
<version>${mybatis.plus.version}</version>
|
<version>${mybatis.plus.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis</groupId>
|
||||||
|
<artifactId>mybatis-spring</artifactId>
|
||||||
|
<version>3.0.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@@ -432,6 +458,33 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- ==================== Spring Cloud Alibaba 微服务相关 ==================== -->
|
||||||
|
<!-- 启用 bootstrap.yml 加载 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Nacos 服务注册与发现 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Nacos 配置中心 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- OpenFeign 服务调用 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring Cloud LoadBalancer 负载均衡 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.ai.da;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@@ -10,6 +12,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
|
@EnableFeignClients
|
||||||
|
@EnableDiscoveryClient
|
||||||
public class AiDaApplication {
|
public class AiDaApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
34
src/main/java/com/ai/da/common/config/SecurityConfig.java
Normal file
34
src/main/java/com/ai/da/common/config/SecurityConfig.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package com.ai.da.common.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security 配置。
|
||||||
|
* 由于鉴权逻辑已迁移至 Gateway(GlobalAuthWebFilter),
|
||||||
|
* 后端服务 (aida-back) 默认放行所有请求,仅依赖网关传递的用户信息。
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
// 禁用 CSRF(微服务通常不需要)
|
||||||
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
|
// 允许所有请求,具体鉴权在网关层完成
|
||||||
|
.authorizeHttpRequests(auth -> auth
|
||||||
|
.anyRequest().permitAll()
|
||||||
|
)
|
||||||
|
// 禁用默认的表单登录和 HTTP Basic 认证,防止 302 重定向
|
||||||
|
.formLogin(AbstractHttpConfigurer::disable)
|
||||||
|
.httpBasic(AbstractHttpConfigurer::disable);
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
package com.ai.da.common.config;
|
package com.ai.da.common.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.ai.da.common.interceptor.UserContextInterceptor;
|
||||||
import org.hibernate.validator.HibernateValidator;
|
import org.hibernate.validator.HibernateValidator;
|
||||||
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.validation.beanvalidation.MethodValidationPostProcessor;
|
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Validation;
|
import jakarta.validation.Validation;
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
import jakarta.validation.ValidatorFactory;
|
import jakarta.validation.ValidatorFactory;
|
||||||
@@ -17,11 +20,20 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};
|
static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserContextInterceptor userContextInterceptor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**").allowedOriginPatterns("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
|
registry.addMapping("/**").allowedOriginPatterns("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(userContextInterceptor)
|
||||||
|
.addPathPatterns("/**");
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Validator validator() {
|
public Validator validator() {
|
||||||
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
|
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.ai.da.common.config.exception;
|
|
||||||
|
|
||||||
public class TokenMissingOrExpiredException extends RuntimeException {
|
|
||||||
public TokenMissingOrExpiredException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Throwable fillInStackTrace() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.ai.da.common.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author yanglei
|
|
||||||
* 异常类常量
|
|
||||||
*/
|
|
||||||
public class TokenConstant {
|
|
||||||
/**
|
|
||||||
* 固定session
|
|
||||||
*/
|
|
||||||
public static final String FIX_SESSION = "qrLS_003af9d8c1363fc4_6c97e932665c4460a1fdbfbf47ce3490";
|
|
||||||
|
|
||||||
public static final String PERMISSIONS = "9672233956";
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.ai.da.common.httpdata.token;
|
|
||||||
|
|
||||||
public enum TokenApis {
|
|
||||||
/**
|
|
||||||
* token
|
|
||||||
*/
|
|
||||||
GET_TOKEN("POST", "/api/openApi/v2/Weixin/QrCodeLoginCheck?session="),
|
|
||||||
GENERATE_USER("POST", "/api/openApi/v2/Welink/TopicGetjson");
|
|
||||||
|
|
||||||
private String method;
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
TokenApis(String method, String url) {
|
|
||||||
this.method = method;
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMethod() {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMethod(String method) {
|
|
||||||
this.method = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package com.ai.da.common.httpdata.token;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
|
||||||
import cn.hutool.http.HttpUtil;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class TokenQuery {
|
|
||||||
|
|
||||||
private static final String GET_TOKEN_DOMAIN = "https://www.szsige.com";
|
|
||||||
private static final String GENERATE_USER_DOMAIN = "https://www.szsige.com";
|
|
||||||
|
|
||||||
public static JSONObject getToken(String session) {
|
|
||||||
String url = GET_TOKEN_DOMAIN + TokenApis.GET_TOKEN.getUrl() + session;
|
|
||||||
log.info("获取用户token接口请求url:" + url);
|
|
||||||
HttpResponse httpResponse = HttpUtil.createPost(url).execute();
|
|
||||||
log.info("获取用户token接口响应:" + httpResponse);
|
|
||||||
if (httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())) {
|
|
||||||
return JSONObject.parseObject(httpResponse.body());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSONObject generateUser(Map<String, Object> param, String token) {
|
|
||||||
HttpResponse httpResponse = HttpUtil.createPost(GENERATE_USER_DOMAIN + TokenApis.GENERATE_USER.getUrl())
|
|
||||||
.body(JSONObject.toJSONString(param != null ? param : new HashMap<>()))
|
|
||||||
.header("Authorization", "Bearer " + token)
|
|
||||||
.header("X-Promiss", "9672233956")
|
|
||||||
.execute();
|
|
||||||
log.info("生成用户信息接口响应:" + httpResponse);
|
|
||||||
if (httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())) {
|
|
||||||
return JSONObject.parseObject(httpResponse.body());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.ai.da.common.interceptor;
|
||||||
|
|
||||||
|
import com.ai.da.common.context.UserContext;
|
||||||
|
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 Gateway 转发的请求头中读取已鉴权的用户身份,写入 UserContext。
|
||||||
|
* <p>
|
||||||
|
* Gateway 验证 JWT 后将 X-User-Id 和 X-User-Info 写入请求头,
|
||||||
|
* 此拦截器负责将信息填充到 ThreadLocal,供业务代码使用。
|
||||||
|
* 不需要 Gateway 鉴权路径(如 login、静态资源)不会有这两个头,
|
||||||
|
* 此时 UserContext 保持为空,业务代码应自行处理。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserContextInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private static final String USER_ID_HEADER = "X-User-Id";
|
||||||
|
private static final String USER_INFO_HEADER = "X-User-Info";
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||||
|
String userInfoJson = request.getHeader(USER_INFO_HEADER);
|
||||||
|
if (userInfoJson != null && !userInfoJson.isBlank()) {
|
||||||
|
try {
|
||||||
|
AuthPrincipalVo principal = objectMapper.readValue(userInfoJson, AuthPrincipalVo.class);
|
||||||
|
UserContext.setUserHolder(principal);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to parse X-User-Info header: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
Object handler, Exception ex) {
|
||||||
|
UserContext.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import com.ai.da.common.response.Response;
|
|
||||||
import com.ai.da.common.response.ResultEnum;
|
|
||||||
import com.ai.da.common.utils.JSONResponseUtils;
|
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ClassName UserAuthAccessDeniedHandler
|
|
||||||
* @Description 无权限处理类
|
|
||||||
* @Author dwjian
|
|
||||||
* @Date 2020/7/9 20:30
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class UserAuthAccessDeniedHandler implements AccessDeniedHandler {
|
|
||||||
@Override
|
|
||||||
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException exception) throws IOException {
|
|
||||||
Response<String> response = Response.error(ResultEnum.NO_PERMISSION.getCode(), ResultEnum.NO_PERMISSION.getMsg());
|
|
||||||
JSONResponseUtils.build(httpServletResponse, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import com.ai.da.common.response.Response;
|
|
||||||
import com.ai.da.common.response.ResultEnum;
|
|
||||||
import com.ai.da.common.utils.JSONResponseUtils;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ClassName UserAuthenticationEntryPointHandler
|
|
||||||
* @Description 未登录处理类
|
|
||||||
* @Author dwjian
|
|
||||||
* @Date 2020/7/9 20:13
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class UserAuthenticationEntryPointHandler implements AuthenticationEntryPoint {
|
|
||||||
@Override
|
|
||||||
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
|
|
||||||
Response<String> response = Response.error(ResultEnum.NO_LOGIN.getCode(), ResultEnum.NO_LOGIN.getMsg());
|
|
||||||
httpServletResponse.setStatus(401);
|
|
||||||
JSONResponseUtils.build(httpServletResponse, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: 认证管理器
|
|
||||||
* @create: 2020-07-10 15:58
|
|
||||||
**/
|
|
||||||
@Component
|
|
||||||
public class UserAuthenticationManager implements AuthenticationManager {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private UserAuthenticationProvider userAuthenticationProvider;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
return userAuthenticationProvider.authenticate(authentication);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import com.ai.da.common.config.RsaProperties;
|
|
||||||
import com.ai.da.common.utils.RsaDecryptUtils;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: 登录校验处理类
|
|
||||||
* @create: 2020-07-09 14:39
|
|
||||||
**/
|
|
||||||
@Component
|
|
||||||
public class UserAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
String userName = (String) authentication.getPrincipal();
|
|
||||||
String password = (String) authentication.getCredentials();
|
|
||||||
try {
|
|
||||||
password = RsaDecryptUtils.decrypt(password, RsaProperties.privateKey);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new BadCredentialsException("用户名或密码错误");
|
|
||||||
}
|
|
||||||
// User user = userService.getByUsername(userName);
|
|
||||||
// if (user == null) {
|
|
||||||
// throw new UsernameNotFoundException("用户名或密码错误");
|
|
||||||
// }
|
|
||||||
// //账号已冻结
|
|
||||||
// if(user.getStatus() == 1){
|
|
||||||
// throw new LockedException("账号已冻结");
|
|
||||||
// }
|
|
||||||
// if(!passwordEncoder.matches(password, user.getPassword())){
|
|
||||||
// throw new BadCredentialsException("用户名或密码错误");
|
|
||||||
// }
|
|
||||||
// //超级管理员
|
|
||||||
// Set<SimpleGrantedAuthority> authorities = new HashSet<>();
|
|
||||||
// if(user.getIsAdmin()) {
|
|
||||||
// authorities.add(new SimpleGrantedAuthority("admin"));
|
|
||||||
// return new UsernamePasswordAuthenticationToken(user, password, authorities);
|
|
||||||
// }else {
|
|
||||||
// List<RoleMenuDto> userMenus = menuService.getRoleMenusByUserId(user.getId(), null);
|
|
||||||
// if(CollUtil.isNotEmpty(userMenus)){
|
|
||||||
// authorities.addAll(userMenus.stream().map(RoleMenuDto::getPermission).filter(StringUtils::isNotEmpty).map(SimpleGrantedAuthority::new).collect(Collectors.toSet()));
|
|
||||||
// }
|
|
||||||
// return new UsernamePasswordAuthenticationToken(user, password, authorities);
|
|
||||||
// }
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> aClass) {
|
|
||||||
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import com.ai.da.common.response.Response;
|
|
||||||
import com.ai.da.common.response.ResultEnum;
|
|
||||||
import com.ai.da.common.utils.JSONResponseUtils;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.authentication.*;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
||||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ClassName UserLoginFailureHandler
|
|
||||||
* @Description 登录失败处理类
|
|
||||||
* @Author dwjian
|
|
||||||
* @Date 2020/7/9 20:17
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class UserLoginFailureHandler implements AuthenticationFailureHandler {
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
|
|
||||||
Response<String> response;
|
|
||||||
if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
|
|
||||||
response = Response.fail(e.getMessage());
|
|
||||||
} else if (e instanceof LockedException) {
|
|
||||||
response = Response.fail(ResultEnum.ACCOUNT_LOCK);
|
|
||||||
} else if (e instanceof CredentialsExpiredException) {
|
|
||||||
response = Response.fail("证书过期,请联系管理员!");
|
|
||||||
} else if (e instanceof AccountExpiredException) {
|
|
||||||
response = Response.fail("账户过期,请联系管理员!");
|
|
||||||
} else if (e instanceof DisabledException) {
|
|
||||||
response = Response.fail("账户被禁用,请联系管理员!");
|
|
||||||
} else if (e instanceof AuthenticationServiceException) {
|
|
||||||
response = Response.fail(e.getMessage());
|
|
||||||
} else {
|
|
||||||
log.error("登录失败:", e);
|
|
||||||
response = Response.fail("登录失败!");
|
|
||||||
}
|
|
||||||
JSONResponseUtils.build(httpServletResponse, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import com.ai.da.common.response.ResultEnum;
|
|
||||||
import com.ai.da.common.utils.JSONResponseUtils;
|
|
||||||
import com.ai.da.common.response.Response;
|
|
||||||
import com.ai.da.common.security.jwt.JWTTokenHelper;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: 登录成功处理类
|
|
||||||
* @create: 2020-07-09 14:58
|
|
||||||
**/
|
|
||||||
@Component
|
|
||||||
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private JWTTokenHelper jwtTokenHelper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
|
||||||
// User user = (User) authentication.getPrincipal();
|
|
||||||
// AuthPrincipalVo principal = new AuthPrincipalVo();
|
|
||||||
// BeanUtils.copyProperties(user, principal);
|
|
||||||
// // 获取用户角色
|
|
||||||
// List<UserRoleDto> userRoles = roleService.getUserRoles(user.getId(), 0);
|
|
||||||
// principal.setRoles(userRoles);
|
|
||||||
// // 获取角色部门
|
|
||||||
// if(CollUtil.isNotEmpty(userRoles)){
|
|
||||||
// principal.setDepts(deptService.getDeptByRoleIds(userRoles.stream().map(UserRoleDto::getRoleId).collect(Collectors.toList())));
|
|
||||||
// }
|
|
||||||
// // 用户角色权限
|
|
||||||
// List<String> authorities = new ArrayList<>(authentication.getAuthorities()).stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
|
|
||||||
// principal.setAuthorities(authorities);
|
|
||||||
// AuthVo authVo = new AuthVo();
|
|
||||||
// authVo.setAuthorities(authorities);
|
|
||||||
// authVo.setToken(jwtTokenHelper.createToken(principal));
|
|
||||||
// authVo.setPrincipal(principal);
|
|
||||||
// user.setLastLoginTime(new Date());
|
|
||||||
// userService.updateById(user);
|
|
||||||
JSONResponseUtils.build(response, Response.success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package com.ai.da.common.security;
|
|
||||||
|
|
||||||
import org.springframework.security.access.PermissionEvaluator;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ClassName UserPermissionEvaluator
|
|
||||||
* @Description 权限校验处理器
|
|
||||||
* @Author dwjian
|
|
||||||
* @Date 2020/7/12 10:16
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class UserPermissionEvaluator implements PermissionEvaluator {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) {
|
|
||||||
System.out.println(authentication);
|
|
||||||
System.out.println(targetUrl);
|
|
||||||
System.out.println(permission);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
|
|
||||||
System.out.println(authentication);
|
|
||||||
System.out.println(targetId);
|
|
||||||
System.out.println(targetType);
|
|
||||||
System.out.println(permission);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
package com.ai.da.common.security.config;
|
|
||||||
|
|
||||||
import com.ai.da.common.security.*;
|
|
||||||
import com.ai.da.common.security.filter.AuthenticationFilter;
|
|
||||||
import com.ai.da.common.security.filter.UserAuthenticationProcessingFilter;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.Customizer;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
@EnableMethodSecurity(prePostEnabled = true)
|
|
||||||
@EnableConfigurationProperties(SecurityProperties.class)
|
|
||||||
public class SecurityConfig {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SecurityProperties securityProperties;
|
|
||||||
@Resource
|
|
||||||
private UserLoginSuccessHandler userLoginSuccessHandler;
|
|
||||||
@Resource
|
|
||||||
private UserLoginFailureHandler userLoginFailureHandler;
|
|
||||||
@Resource
|
|
||||||
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
|
|
||||||
@Resource
|
|
||||||
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
|
|
||||||
@Resource
|
|
||||||
private UserAuthenticationManager userAuthenticationManager;
|
|
||||||
@Resource
|
|
||||||
private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不通过注入spring管理 让Security来管理 这样自定义的Filter就不会走,.permitAll()才能起作用
|
|
||||||
*/
|
|
||||||
@Resource
|
|
||||||
private AuthenticationFilter authenticationFilter;
|
|
||||||
@Resource
|
|
||||||
private UserPermissionEvaluator userPermissionEvaluator;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public AuthenticationManager authenticationManager() throws Exception {
|
|
||||||
return this.userAuthenticationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
|
|
||||||
httpSecurity
|
|
||||||
.cors(Customizer.withDefaults())
|
|
||||||
.authorizeHttpRequests(auth -> auth
|
|
||||||
.requestMatchers(
|
|
||||||
new AntPathRequestMatcher("/doc.html"),
|
|
||||||
new AntPathRequestMatcher("/swagger-ui.html"),
|
|
||||||
new AntPathRequestMatcher("/swagger-ui/**"),
|
|
||||||
new AntPathRequestMatcher("/swagger-resources/**"),
|
|
||||||
new AntPathRequestMatcher("/v2/api-docs"),
|
|
||||||
new AntPathRequestMatcher("/v3/api-docs/**"),
|
|
||||||
new AntPathRequestMatcher("/webjars/**")
|
|
||||||
).permitAll()
|
|
||||||
.requestMatchers(securityProperties.getIgnorePaths()).permitAll()
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
)
|
|
||||||
.headers(headers -> headers
|
|
||||||
.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)
|
|
||||||
.cacheControl(cache -> cache.disable())
|
|
||||||
)
|
|
||||||
.exceptionHandling(exception -> exception
|
|
||||||
.authenticationEntryPoint(userAuthenticationEntryPointHandler)
|
|
||||||
.accessDeniedHandler(userAuthAccessDeniedHandler)
|
|
||||||
)
|
|
||||||
.formLogin(form -> form
|
|
||||||
.loginProcessingUrl(securityProperties.getAuthApi())
|
|
||||||
.successHandler(userLoginSuccessHandler)
|
|
||||||
.failureHandler(userLoginFailureHandler)
|
|
||||||
)
|
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
|
||||||
.sessionManagement(session -> session
|
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
||||||
);
|
|
||||||
|
|
||||||
//自定义过滤器在登录时认证用户名、密码
|
|
||||||
httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
|
|
||||||
.addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
|
|
||||||
|
|
||||||
return httpSecurity.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
|
|
||||||
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
|
|
||||||
handler.setPermissionEvaluator(userPermissionEvaluator);
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.ai.da.common.security.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: JWT配置类
|
|
||||||
* @create: 2020-07-09 09:38
|
|
||||||
**/
|
|
||||||
@Data
|
|
||||||
@ConfigurationProperties(prefix = "spring.security")
|
|
||||||
public class SecurityProperties {
|
|
||||||
|
|
||||||
private String jwtSecret;
|
|
||||||
|
|
||||||
private String jwtTokenHeader;
|
|
||||||
|
|
||||||
private String jwtTokenPrefix;
|
|
||||||
|
|
||||||
private long jwtExpiration;
|
|
||||||
|
|
||||||
private String[] ignorePaths;
|
|
||||||
|
|
||||||
private String authApi;
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
package com.ai.da.common.security.filter;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.ai.da.common.config.exception.TokenMissingOrExpiredException;
|
|
||||||
import com.ai.da.common.context.UserContext;
|
|
||||||
import com.ai.da.common.security.config.SecurityProperties;
|
|
||||||
import com.ai.da.common.security.jwt.JWTTokenHelper;
|
|
||||||
import com.ai.da.common.utils.LocalCacheUtils;
|
|
||||||
import com.ai.da.common.utils.RedisUtil;
|
|
||||||
import com.ai.da.common.utils.MultiReadHttpServletRequest;
|
|
||||||
import com.ai.da.common.utils.MultiReadHttpServletResponse;
|
|
||||||
import com.ai.da.common.utils.RequestInfoUtil;
|
|
||||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.util.StopWatch;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: 认证拦截器
|
|
||||||
* @create: 2020-07-10 16:50
|
|
||||||
**/
|
|
||||||
@Slf4j
|
|
||||||
@Configuration
|
|
||||||
public class AuthenticationFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private JWTTokenHelper jwtTokenHelper;
|
|
||||||
@Resource
|
|
||||||
private SecurityProperties properties;
|
|
||||||
@Resource
|
|
||||||
private RedisUtil redisUtil;
|
|
||||||
|
|
||||||
private static final List<String> FILTER_URL =
|
|
||||||
Arrays.asList("/favicon.ico", "/doc.html", "/swagger-ui.html",
|
|
||||||
"/swagger-resources", "/swagger-resources/", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security",
|
|
||||||
"/webjars/", "/v2/api-docs", "/v3/api-docs", "/v3/api-docs/swagger-config",
|
|
||||||
"/api/account/login", "/api/account/preLogin", "api/account/sendEmail","api/account/noLoginRequired",
|
|
||||||
"/api/account/resetPwd",
|
|
||||||
"/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId",
|
|
||||||
"/api/third/party/addUser","/api/third/party/addTrialUser", "/api/third/party/editUser", "/api/element/initDefaultSysFile",
|
|
||||||
"/api/third/party/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew","/api/third/party/updateNoLoginRequiredNew",
|
|
||||||
"/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl",
|
|
||||||
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
|
|
||||||
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
|
|
||||||
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify",
|
|
||||||
"/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode","/api/third/party/receiveDesignParams"
|
|
||||||
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
|
|
||||||
"/api/llm/stream",
|
|
||||||
//GlobalAwardController
|
|
||||||
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
|
|
||||||
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
|
|
||||||
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export",
|
|
||||||
"/api/global-award/contestants/export/files"
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
String requestURI = httpServletRequest.getRequestURI();
|
|
||||||
|
|
||||||
if (calculateUrl(requestURI)/* || hasAuthorizationToken(httpServletRequest)*/) {
|
|
||||||
StopWatch stopWatch = new StopWatch();
|
|
||||||
HttpServletRequest wrappedRequest = httpServletRequest;
|
|
||||||
HttpServletResponse wrappedResponse = httpServletResponse;
|
|
||||||
try {
|
|
||||||
stopWatch.start();
|
|
||||||
if ((httpServletRequest.getContentType() == null && httpServletRequest.getContentLength() > 0) || (httpServletRequest.getContentType() != null && !httpServletRequest.getContentType().contains("application/json"))) {
|
|
||||||
extracted(wrappedRequest);
|
|
||||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
|
||||||
} else {
|
|
||||||
wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest);
|
|
||||||
wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse);
|
|
||||||
extracted(wrappedRequest);
|
|
||||||
// excel导出使用原始response,不对响应做包装
|
|
||||||
if (requestURI.equals("/api/account/exportAccountsToExcel")) {
|
|
||||||
filterChain.doFilter(httpServletRequest, httpServletResponse); // 不包装
|
|
||||||
} else {
|
|
||||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
SecurityContextHolder.clearContext();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
stopWatch.stop();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//先清空当前线程变量,防止上一个线程遗留
|
|
||||||
UserContext.delete();
|
|
||||||
filterChain.doFilter(httpServletRequest, httpServletResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean calculateUrl(String requestURI) {
|
|
||||||
String filterUrl = FILTER_URL.stream().filter(url -> requestURI.contains(url)).findFirst().orElse(null);
|
|
||||||
return null == filterUrl ? Boolean.TRUE : Boolean.FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasAuthorizationToken(HttpServletRequest request) {
|
|
||||||
String authorizationHeader = request.getHeader("Authorization");
|
|
||||||
return authorizationHeader != null && authorizationHeader.startsWith("Bearer");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extracted(HttpServletRequest request) {
|
|
||||||
String jwtToken = request.getHeader(properties.getJwtTokenHeader());
|
|
||||||
// log.debug("后台检查令牌:{}", jwtToken);
|
|
||||||
|
|
||||||
if (StrUtil.isBlank(jwtToken)) {
|
|
||||||
String ipAddress = RequestInfoUtil.getIpAddress(request);
|
|
||||||
log.info("本次请求的ip为 : " + ipAddress);
|
|
||||||
// throw new RuntimeException("请传入token!");
|
|
||||||
throw new TokenMissingOrExpiredException("请传入token!");
|
|
||||||
}
|
|
||||||
if(jwtToken.equals("Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA")){
|
|
||||||
//写死 暂时放行
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 检查token
|
|
||||||
boolean validate = jwtTokenHelper.validateToken(jwtToken);
|
|
||||||
if (validate) {
|
|
||||||
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(jwtToken);
|
|
||||||
if (principal == null) {
|
|
||||||
// throw new RuntimeException("TOKEN已过期,请重新登录!");
|
|
||||||
throw new TokenMissingOrExpiredException("TOKEN已过期,请重新登录!(token without userInfo)");
|
|
||||||
}
|
|
||||||
//先清空当前线程变量,防止上一个线程遗留
|
|
||||||
UserContext.delete();
|
|
||||||
//存取用户信息到缓存
|
|
||||||
UserContext.setUserHolder(principal);
|
|
||||||
// 校验 token:先查本地缓存,再查 Redis,保证服务重启后仍然有效
|
|
||||||
String userIdStr = String.valueOf(principal.getId());
|
|
||||||
String cacheToken = LocalCacheUtils.getTokenCache(userIdStr);
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(cacheToken)) {
|
|
||||||
// 本地缓存为空时,尝试从 Redis 读取
|
|
||||||
cacheToken = redisUtil.getLoginToken(principal.getId());
|
|
||||||
if (StringUtils.isEmpty(cacheToken)) {
|
|
||||||
// throw new RuntimeException("TOKEN已过期,请重新登录!");
|
|
||||||
throw new TokenMissingOrExpiredException("TOKEN已过期,请重新登录!(cache & redis empty)");
|
|
||||||
}
|
|
||||||
// 将 Redis 中的 token 回填到本地缓存,减少后续 Redis 访问
|
|
||||||
LocalCacheUtils.setTokenCache(userIdStr, cacheToken);
|
|
||||||
}
|
|
||||||
if(!cacheToken.equals(jwtToken) ){
|
|
||||||
// throw new RuntimeException("TOKEN已过期,请重新登录!");
|
|
||||||
throw new TokenMissingOrExpiredException("TOKEN已过期,请重新登录!(token not match local cache)");
|
|
||||||
}
|
|
||||||
// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(null, null);
|
|
||||||
// SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package com.ai.da.common.security.filter;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.ai.da.common.security.UserLoginSuccessHandler;
|
|
||||||
import com.ai.da.common.security.config.SecurityProperties;
|
|
||||||
import com.ai.da.common.utils.RedisCacheUtils;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.ai.da.common.security.UserAuthenticationManager;
|
|
||||||
import com.ai.da.common.security.UserLoginFailureHandler;
|
|
||||||
import com.ai.da.common.utils.MultiReadHttpServletRequest;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: 用户认证过滤器
|
|
||||||
* @create: 2020-07-10 15:58
|
|
||||||
**/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param securityProperties 配置(从配置中读取登录url)
|
|
||||||
* @param authenticationManager 认证管理器
|
|
||||||
* @param adminAuthenticationSuccessHandler 认证成功处理器
|
|
||||||
* @param adminAuthenticationFailureHandler 认证失败处理器
|
|
||||||
*/
|
|
||||||
public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) {
|
|
||||||
super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name()));
|
|
||||||
this.setAuthenticationManager(authenticationManager);
|
|
||||||
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
|
|
||||||
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
|
||||||
if (request.getContentType() == null || !request.getContentType().contains("application/json")) {
|
|
||||||
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
|
|
||||||
}
|
|
||||||
UsernamePasswordAuthenticationToken authRequest;
|
|
||||||
try {
|
|
||||||
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
|
|
||||||
// 将前端传递的数据转换成jsonBean数据格式
|
|
||||||
JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest));
|
|
||||||
String code = jsonObject.getString("code");
|
|
||||||
String uuid = jsonObject.getString("uuid");
|
|
||||||
if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) {
|
|
||||||
throw new AuthenticationServiceException("验证码错误");
|
|
||||||
}
|
|
||||||
RedisCacheUtils.delete("code-key-" + uuid);
|
|
||||||
authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null);
|
|
||||||
authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new AuthenticationServiceException(e.getMessage());
|
|
||||||
}
|
|
||||||
return this.getAuthenticationManager().authenticate(authRequest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
package com.ai.da.common.security.jwt;
|
|
||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
|
||||||
import com.ai.da.common.constant.CommonConstant;
|
|
||||||
import com.ai.da.common.security.config.SecurityProperties;
|
|
||||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: dangweijian
|
|
||||||
* @description: JWT工具
|
|
||||||
* @create: 2020-07-09 09:27
|
|
||||||
**/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class JWTTokenHelper {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SecurityProperties securityProperties;
|
|
||||||
|
|
||||||
private static final String ISSUER = "DWJ";
|
|
||||||
private static final String AUTHORITIES = "authorities";
|
|
||||||
private static final String CHANGE_MAILBOX = "changeMailbox";
|
|
||||||
|
|
||||||
public String createToken(AuthPrincipalVo principal) {
|
|
||||||
SecretKey key = buildSigningKey();
|
|
||||||
String token = Jwts.builder()
|
|
||||||
.id(String.valueOf(principal.getId()))
|
|
||||||
.subject(JSONObject.toJSONString(principal))
|
|
||||||
.issuedAt(new Date())
|
|
||||||
.issuer(ISSUER)
|
|
||||||
.claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
|
|
||||||
.expiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration()))
|
|
||||||
.signWith(key)
|
|
||||||
.compact();
|
|
||||||
token = securityProperties.getJwtTokenPrefix() + token;
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean validateToken(String token) {
|
|
||||||
Claims claims = parser(token);
|
|
||||||
if (MapUtil.isEmpty(claims)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthPrincipalVo parserToUser(String token) {
|
|
||||||
String subject = parser(token).getSubject();
|
|
||||||
if (StrUtil.isNotEmpty(subject)) {
|
|
||||||
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Claims parser(String token) {
|
|
||||||
token = token.replaceAll(securityProperties.getJwtTokenPrefix(), "");
|
|
||||||
SecretKey key = buildSigningKey();
|
|
||||||
return Jwts.parser()
|
|
||||||
.verifyWith(key)
|
|
||||||
.build()
|
|
||||||
.parseSignedClaims(token)
|
|
||||||
.getPayload();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String createToken(Long userId, String userEmail){
|
|
||||||
SecretKey key = buildSigningKey();
|
|
||||||
String token = Jwts.builder()
|
|
||||||
.id(String.valueOf(userId))
|
|
||||||
.subject(userEmail + "_" + userId)
|
|
||||||
.issuedAt(new Date())
|
|
||||||
.issuer(ISSUER)
|
|
||||||
.claim(CHANGE_MAILBOX, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
|
|
||||||
.expiration(new Date(System.currentTimeMillis() + CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY))
|
|
||||||
.signWith(key)
|
|
||||||
.compact();
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String parseToEmailAndId(String token) {
|
|
||||||
return parser(token).getSubject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT 要求 HMAC-SHA 的密钥至少 256 bit,这里统一扩展/哈希密钥长度避免 WeakKeyException。
|
|
||||||
*/
|
|
||||||
private SecretKey buildSigningKey() {
|
|
||||||
byte[] raw = securityProperties.getJwtSecret().getBytes(StandardCharsets.UTF_8);
|
|
||||||
if (raw.length < 32) {
|
|
||||||
raw = DigestUtil.sha256(raw);
|
|
||||||
}
|
|
||||||
return Keys.hmacShaKeyFor(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package com.ai.da.common.utils;
|
|||||||
import com.ai.da.common.constant.CommonConstant;
|
import com.ai.da.common.constant.CommonConstant;
|
||||||
import com.ai.da.model.dto.BasicEmailParamDTO;
|
import com.ai.da.model.dto.BasicEmailParamDTO;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.sun.mail.smtp.SMTPTransport;
|
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.io.InputStreamSource;
|
import org.springframework.core.io.InputStreamSource;
|
||||||
@@ -35,6 +34,7 @@ public class MailUtil {
|
|||||||
* 发送邮件 - 默认发件人
|
* 发送邮件 - 默认发件人
|
||||||
*
|
*
|
||||||
* @param basicEmailParamDTO 发送邮件所需参数
|
* @param basicEmailParamDTO 发送邮件所需参数
|
||||||
|
* @param fileName 附件名(如果有)
|
||||||
* @param inputStreamSource 附件(如果有)
|
* @param inputStreamSource 附件(如果有)
|
||||||
*/
|
*/
|
||||||
public int sendMail(BasicEmailParamDTO basicEmailParamDTO, String fileName, InputStreamSource inputStreamSource) throws MessagingException {
|
public int sendMail(BasicEmailParamDTO basicEmailParamDTO, String fileName, InputStreamSource inputStreamSource) throws MessagingException {
|
||||||
@@ -62,30 +62,23 @@ public class MailUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int sendMail(MimeMessage mimeMessage, String host, String username, String password) throws MessagingException {
|
private int sendMail(MimeMessage mimeMessage, String host, String username, String password) throws MessagingException {
|
||||||
SMTPTransport transport = null;
|
|
||||||
try {
|
try {
|
||||||
// 获取 SMTPTransport
|
// 配置连接属性
|
||||||
transport = (SMTPTransport) mimeMessage.getSession().getTransport("smtp");
|
java.util.Properties props = mimeMessage.getSession().getProperties();
|
||||||
// 连接到 SMTP 服务器
|
props.put("mail.smtp.auth", "true");
|
||||||
transport.connect(host, username, password);
|
props.put("mail.smtp.host", host);
|
||||||
// 发送邮件
|
props.put("mail.user", username);
|
||||||
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
|
props.put("mail.password", password);
|
||||||
// 获取 SMTP 服务器的响应
|
|
||||||
String lastServerResponse = transport.getLastServerResponse();
|
|
||||||
int lastReturnCode = transport.getLastReturnCode();
|
|
||||||
|
|
||||||
log.info("SMTP 状态码: {}, SMTP 服务器响应: {}", lastReturnCode, lastServerResponse);
|
// 使用 JavaMailSender 发送邮件(Spring Boot 3.x 标准方式)
|
||||||
return lastReturnCode;
|
javaMailSender.send(mimeMessage);
|
||||||
} catch (MailException | MessagingException e) {
|
log.info("邮件发送成功至: {}", host);
|
||||||
// 记录日志或执行其他补偿逻辑
|
return 1;
|
||||||
|
} catch (MailException e) {
|
||||||
log.info("邮件发送失败:{}", e.getMessage());
|
log.info("邮件发送失败:{}", e.getMessage());
|
||||||
} finally {
|
|
||||||
// 关闭连接
|
|
||||||
assert transport != null;
|
|
||||||
transport.close();
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建一封邮件
|
* 创建一封邮件
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.ai.da.common.utils;
|
|
||||||
|
|
||||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
|
|
||||||
public class SecurityContextUtils {
|
|
||||||
|
|
||||||
public static AuthPrincipalVo getCurrentUser() {
|
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
if (authentication != null && authentication.getPrincipal() != null) {
|
|
||||||
return (AuthPrincipalVo) authentication.getPrincipal();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Long getCurrentUserId() {
|
|
||||||
AuthPrincipalVo currentUser = getCurrentUser();
|
|
||||||
if (currentUser != null) {
|
|
||||||
return currentUser.getId();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getCurrentUsername() {
|
|
||||||
AuthPrincipalVo currentUser = getCurrentUser();
|
|
||||||
if (currentUser != null) {
|
|
||||||
return currentUser.getUsername();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1030,25 +1030,15 @@ public class SendEmailUtil {
|
|||||||
|
|
||||||
private final static Long CN_2025_618 = 141425L;
|
private final static Long CN_2025_618 = 141425L;
|
||||||
private final static Long EN_2025_618 = 141424L;
|
private final static Long EN_2025_618 = 141424L;
|
||||||
|
public static void send618PromotionEmailTemp(String receiver, String language){
|
||||||
private final static Long CN_GLOBAL_AWARDS = 166716L;
|
try {
|
||||||
private final static Long EN_GLOBAL_AWARDS = 166715L;
|
// 实例化一个认证对象
|
||||||
private final static Long GLOBAL_AWARDS_2 = 173919L;
|
|
||||||
|
|
||||||
// 复用 SesClient,避免每次发送都创建新连接
|
|
||||||
private static SesClient getSesClient() {
|
|
||||||
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
|
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
|
||||||
HttpProfile httpProfile = new HttpProfile();
|
HttpProfile httpProfile = new HttpProfile();
|
||||||
httpProfile.setEndpoint("ses.tencentcloudapi.com");
|
httpProfile.setEndpoint("ses.tencentcloudapi.com");
|
||||||
ClientProfile clientProfile = new ClientProfile();
|
ClientProfile clientProfile = new ClientProfile();
|
||||||
clientProfile.setHttpProfile(httpProfile);
|
clientProfile.setHttpProfile(httpProfile);
|
||||||
return new SesClient(cred, "ap-hongkong", clientProfile);
|
SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
|
||||||
}
|
|
||||||
|
|
||||||
public static void send618PromotionEmailTemp(String receiver, String language){
|
|
||||||
SesClient client = null;
|
|
||||||
try {
|
|
||||||
client = getSesClient();
|
|
||||||
SendEmailRequest req = new SendEmailRequest();
|
SendEmailRequest req = new SendEmailRequest();
|
||||||
req.setFromEmailAddress(CODE_CREATE_SEND_ADDRESS);
|
req.setFromEmailAddress(CODE_CREATE_SEND_ADDRESS);
|
||||||
req.setDestination(new String[]{receiver});
|
req.setDestination(new String[]{receiver});
|
||||||
@@ -1056,15 +1046,20 @@ public class SendEmailUtil {
|
|||||||
// 根据邮件类型设置不同的主题和模板
|
// 根据邮件类型设置不同的主题和模板
|
||||||
String subject = "";
|
String subject = "";
|
||||||
Template template = new Template();
|
Template template = new Template();
|
||||||
subject = "AiDA Global Design Awards 2026 | The Journey Starts Now ! \nAiDA 全球设计大奖 2026 | 从现在开始你的创作之旅 !";
|
// if (type == 1) {
|
||||||
template.setTemplateID(GLOBAL_AWARDS_2);
|
// subject = "Upcoming System Upgrade for AiDA 3.0";
|
||||||
/*if (language.equals("ENGLISH")) {
|
// template.setTemplateID(UPGRADE_NOTIFICATION_ID);
|
||||||
subject = "From Idea to Wow. \uD83D\uDD25 | AiDA Demo & Global Awards";
|
// }else {
|
||||||
template.setTemplateID(EN_GLOBAL_AWARDS);
|
// subject = "即将到来的AiDA 3.0系统升级";
|
||||||
|
// template.setTemplateID(UPGRADE_NOTIFICATION_ID_CHINESE);
|
||||||
|
// }
|
||||||
|
if (language.equals("ENGLISH")) {
|
||||||
|
subject = "Welcome back !Subscribe AiDA with the discount code to enjoy 50% OFF!";
|
||||||
|
template.setTemplateID(EN_2025_618);
|
||||||
}else {
|
}else {
|
||||||
subject = "灵感开挂,创作起飞 \uD83D\uDD25 | AiDA Demo & 全球设计大奖";
|
subject = "设计时速狂飙!AiDA 618半价让灵感永不限流!";
|
||||||
template.setTemplateID(CN_GLOBAL_AWARDS);
|
template.setTemplateID(CN_2025_618);
|
||||||
}*/
|
}
|
||||||
|
|
||||||
req.setSubject(subject);
|
req.setSubject(subject);
|
||||||
req.setTemplate(template);
|
req.setTemplate(template);
|
||||||
@@ -1074,7 +1069,9 @@ public class SendEmailUtil {
|
|||||||
log.info("邮件发送成功,收件人地址:{}", receiver);
|
log.info("邮件发送成功,收件人地址:{}", receiver);
|
||||||
log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp));
|
log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp));
|
||||||
} catch (TencentCloudSDKException e) {
|
} catch (TencentCloudSDKException e) {
|
||||||
log.error("邮件发送失败,收件人地址:{},错误信息:{}", receiver, e.toString());
|
log.info(receiver);
|
||||||
|
log.error("邮件发送失败###{},收件人地址:{}", e.toString(), receiver);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,93 +20,73 @@ public class SendRequestUtil {
|
|||||||
@Value("${FREEPIK_API_KEY}")
|
@Value("${FREEPIK_API_KEY}")
|
||||||
private String FREEPIK_API_KEY;
|
private String FREEPIK_API_KEY;
|
||||||
|
|
||||||
public String sendAliYunPostAsync(String apiUrl, String requestBody) {
|
public String sendAliYunPostAsync(String apiUrl, String requestBody){
|
||||||
// 发送POST请求
|
// 发送POST请求 todo 异常处理
|
||||||
try (HttpResponse execute = HttpRequest.post(apiUrl)
|
HttpResponse execute = HttpRequest.post(apiUrl)
|
||||||
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
|
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
|
||||||
.header("X-DashScope-Async", "enable")
|
.header("X-DashScope-Async", "enable")
|
||||||
.header(Header.CONTENT_TYPE, "application/json")
|
.header(Header.CONTENT_TYPE, "application/json")
|
||||||
.body(requestBody)
|
.body(requestBody)
|
||||||
.timeout(20000) // 设置超时时间20秒
|
.timeout(20000) // 设置超时时间20秒
|
||||||
.execute()) {
|
.execute();
|
||||||
|
|
||||||
int status = execute.getStatus();
|
int status = execute.getStatus();
|
||||||
if (status == 200) {
|
if (status == 200){
|
||||||
String body = execute.body();
|
String body = execute.body();
|
||||||
JSONObject bodyJson = JSONUtil.parseObj(body);
|
JSONObject bodyJson = JSONUtil.parseObj(body);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
log.warn("请求失败,状态码为:{},响应内容:{}", status, execute.body());
|
log.warn("请求失败,状态码为 : {}", status);
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("请求阿里云API时发生异常,URL:{},请求体:{},异常信息:{}",
|
|
||||||
apiUrl, requestBody, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendAliYunPost(String apiUrl, String requestBody) {
|
public String sendAliYunPost(String apiUrl, String requestBody){
|
||||||
// 发送POST请求
|
// 发送POST请求 todo 异常处理
|
||||||
try (HttpResponse execute = HttpRequest.post(apiUrl)
|
HttpResponse execute = HttpRequest.post(apiUrl)
|
||||||
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
|
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
|
||||||
.header(Header.CONTENT_TYPE, "application/json")
|
.header(Header.CONTENT_TYPE, "application/json")
|
||||||
.body(requestBody)
|
.body(requestBody)
|
||||||
.timeout(20000) // 设置超时时间20秒
|
.timeout(20000) // 设置超时时间20秒
|
||||||
.execute()) {
|
.execute();
|
||||||
|
|
||||||
int status = execute.getStatus();
|
int status = execute.getStatus();
|
||||||
if (status == 200) {
|
if (status == 200){
|
||||||
String body = execute.body();
|
String body = execute.body();
|
||||||
JSONObject bodyJson = JSONUtil.parseObj(body);
|
JSONObject bodyJson = JSONUtil.parseObj(body);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
log.warn("请求失败,状态码为:{},响应内容:{}", status, execute.body());
|
log.warn("请求失败,状态码为 : {}", status);
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("请求阿里云API时发生异常,URL:{},请求体:{},异常信息:{}",
|
|
||||||
apiUrl, requestBody, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String FREE_PIK = "https://api.freepik.com/v1/ai/beta/text-to-image/reimagine-flux";
|
public static final String FREE_PIK = "https://api.freepik.com/v1/ai/beta/text-to-image/reimagine-flux";
|
||||||
public String sendFreepikPost(String requestBody) {
|
public String sendFreepikPost( String requestBody){
|
||||||
// 发送POST请求
|
// 发送POST请求 todo 异常处理
|
||||||
try (HttpResponse execute = HttpRequest.post(FREE_PIK)
|
HttpResponse execute = HttpRequest.post(FREE_PIK)
|
||||||
.header(Header.CONTENT_TYPE, "application/json")
|
.header(Header.CONTENT_TYPE, "application/json")
|
||||||
.header("x-freepik-api-key", FREEPIK_API_KEY)
|
.header("x-freepik-api-key", FREEPIK_API_KEY)
|
||||||
.body(requestBody)
|
.body(requestBody)
|
||||||
.timeout(20000) // 设置超时时间20秒
|
.timeout(20000) // 设置超时时间20秒
|
||||||
.execute()) {
|
.execute();
|
||||||
|
|
||||||
int status = execute.getStatus();
|
int status = execute.getStatus();
|
||||||
if (status == 200) {
|
if (status == 200){
|
||||||
return execute.body();
|
return execute.body();
|
||||||
}
|
}
|
||||||
log.warn("请求失败,状态码为:{},响应内容:{}", status, execute.body());
|
log.warn("请求失败,状态码为 : {}", status);
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("请求Freepik API时发生异常,请求体:{},异常信息:{}",
|
|
||||||
requestBody, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendAliYunGet(String fullUrl) {
|
public String sendAliYunGet(String fullUrl){
|
||||||
// 发送GET请求
|
// 发送GET请求 todo 异常处理
|
||||||
try (HttpResponse httpResponse = HttpRequest.get(fullUrl)
|
HttpResponse httpResponse = HttpRequest.get(fullUrl)
|
||||||
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
|
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
|
||||||
.timeout(20000) // 设置超时时间20秒
|
.timeout(20000) // 设置超时时间20秒
|
||||||
.execute()) {
|
.execute();
|
||||||
|
|
||||||
int status = httpResponse.getStatus();
|
int status = httpResponse.getStatus();
|
||||||
if (status == 200) {
|
if (status == 200){
|
||||||
return httpResponse.body();
|
return httpResponse.body();
|
||||||
}
|
}else {
|
||||||
log.warn("请求失败,状态码为:{},响应内容:{}", status, httpResponse.body());
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("请求阿里云API时发生异常,URL:{},异常信息:{}",
|
|
||||||
fullUrl, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*public String sendFluxPost(String url, String requestBodyStr){
|
/*public String sendFluxPost(String url, String requestBodyStr){
|
||||||
int status;
|
int status;
|
||||||
|
|||||||
131
src/main/java/com/ai/da/common/utils/TokenGenerateUtils.java
Normal file
131
src/main/java/com/ai/da/common/utils/TokenGenerateUtils.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package com.ai.da.common.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import com.ai.da.common.constant.CommonConstant;
|
||||||
|
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token 生成工具类(仅负责生成,不负责鉴权)。
|
||||||
|
* 鉴权逻辑已迁移至 Gateway(GlobalAuthWebFilter)。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class TokenGenerateUtils {
|
||||||
|
|
||||||
|
private static final String ISSUER = "DWJ";
|
||||||
|
|
||||||
|
@Value("${spring.security.jwtSecret:JWTSECRET}")
|
||||||
|
private String jwtSecret;
|
||||||
|
|
||||||
|
@Value("${spring.security.jwtExpiration:8640000000}")
|
||||||
|
private long jwtExpiration;
|
||||||
|
|
||||||
|
@Value("${spring.security.jwtTokenPrefix:Bearer-}")
|
||||||
|
private String jwtTokenPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 JWT Token。
|
||||||
|
* @param principal 用户信息
|
||||||
|
* @return 完整的 token(含 prefix)
|
||||||
|
*/
|
||||||
|
public String createToken(AuthPrincipalVo principal) {
|
||||||
|
SecretKey key = buildSigningKey();
|
||||||
|
String token = Jwts.builder()
|
||||||
|
.id(String.valueOf(principal.getId()))
|
||||||
|
.subject(JSONObject.toJSONString(principal))
|
||||||
|
.issuedAt(new Date())
|
||||||
|
.issuer(ISSUER)
|
||||||
|
.expiration(new Date(System.currentTimeMillis() + jwtExpiration))
|
||||||
|
.signWith(key)
|
||||||
|
.compact();
|
||||||
|
return jwtTokenPrefix + token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 Token 过期时间(毫秒)。
|
||||||
|
*/
|
||||||
|
public long getJwtExpiration() {
|
||||||
|
return jwtExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成用于邮箱变更的简化 Token。
|
||||||
|
* @param userId 用户 ID
|
||||||
|
* @param mailbox 新邮箱
|
||||||
|
* @return token(不含 prefix)
|
||||||
|
*/
|
||||||
|
public String createMailboxToken(Long userId, String mailbox) {
|
||||||
|
SecretKey key = buildSigningKey();
|
||||||
|
return Jwts.builder()
|
||||||
|
.id(String.valueOf(userId))
|
||||||
|
.subject(mailbox + "_" + userId)
|
||||||
|
.issuedAt(new Date())
|
||||||
|
.issuer(ISSUER)
|
||||||
|
.expiration(new Date(System.currentTimeMillis() + CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY))
|
||||||
|
.signWith(key)
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证 Token 是否有效(签名和有效期)。
|
||||||
|
*/
|
||||||
|
public boolean validateToken(String token) {
|
||||||
|
try {
|
||||||
|
Claims claims = parseTokenBody(token);
|
||||||
|
return claims != null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 Token 中解析用户信息。
|
||||||
|
*/
|
||||||
|
public AuthPrincipalVo parserToUser(String token) {
|
||||||
|
try {
|
||||||
|
String subject = parseTokenBody(token).getSubject();
|
||||||
|
if (StrUtil.isNotEmpty(subject)) {
|
||||||
|
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("JWT解析用户信息失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析邮箱变更 Token,返回 "email_id" 格式字符串。
|
||||||
|
*/
|
||||||
|
public String parseMailboxToken(String token) {
|
||||||
|
return parseTokenBody(token).getSubject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Claims parseTokenBody(String token) {
|
||||||
|
SecretKey key = buildSigningKey();
|
||||||
|
return Jwts.parser()
|
||||||
|
.verifyWith(key)
|
||||||
|
.build()
|
||||||
|
.parseSignedClaims(token)
|
||||||
|
.getPayload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey buildSigningKey() {
|
||||||
|
byte[] raw = jwtSecret.getBytes(StandardCharsets.UTF_8);
|
||||||
|
if (raw.length < 32) {
|
||||||
|
raw = DigestUtil.sha256(raw);
|
||||||
|
}
|
||||||
|
return Keys.hmacShaKeyFor(raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -380,12 +380,12 @@ public class AccountController {
|
|||||||
return Response.success(accountService.subAccountImport(file));
|
return Response.success(accountService.subAccountImport(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/send618Email")
|
/*@GetMapping("/send618Email")
|
||||||
@Operation(summary = "618邮件发送")
|
@Operation(summary = "618邮件发送")
|
||||||
public Response<String> send618PromotionEmailTemp() {
|
public Response<String> send618PromotionEmailTemp() {
|
||||||
accountService.send618PromotionEmailTemp();
|
accountService.send618PromotionEmailTemp();
|
||||||
return Response.success("success");
|
return Response.success("success");
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*@GetMapping("/refreshCreditsMonthly")
|
/*@GetMapping("/refreshCreditsMonthly")
|
||||||
@Operation(summary = "刷新子账号积分")
|
@Operation(summary = "刷新子账号积分")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.ai.da.common.response.Response;
|
|||||||
import com.ai.da.model.dto.*;
|
import com.ai.da.model.dto.*;
|
||||||
import com.ai.da.model.dto.ContestantDTO;
|
import com.ai.da.model.dto.ContestantDTO;
|
||||||
import com.ai.da.model.vo.CheckOTPVO;
|
import com.ai.da.model.vo.CheckOTPVO;
|
||||||
|
import com.ai.da.model.vo.ContestantCountVO;
|
||||||
import com.ai.da.service.GlobalAwardService;
|
import com.ai.da.service.GlobalAwardService;
|
||||||
import com.ai.da.service.upload.UploadService;
|
import com.ai.da.service.upload.UploadService;
|
||||||
import com.ai.da.service.upload.UploadTask;
|
import com.ai.da.service.upload.UploadTask;
|
||||||
@@ -176,10 +177,25 @@ public class GlobalAwardController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/contestants/export/files")
|
@PostMapping("/contestants/export/files")
|
||||||
@ApiOperation(value = "导出参赛者文件到本地", notes = "根据参赛者编号范围导出PDF和视频文件到本地temp/uploads/contestants目录")
|
@ApiOperation(value = "导出参赛者文件为ZIP", notes = "根据参赛者编号范围导出PDF、视频和信息文件为ZIP,直接响应给浏览器")
|
||||||
public Response<Integer> exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request) throws Exception {
|
public void exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request, HttpServletResponse response) throws Exception {
|
||||||
int exportedCount = globalAwardService.exportContestantFiles(request.getMinContestantNumber(), request.getMaxContestantNumber());
|
byte[] zipData = globalAwardService.exportContestantFilesAsZip(request.getMinContestantNumber(), request.getMaxContestantNumber());
|
||||||
return Response.success(exportedCount);
|
if (zipData.length == 0) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
response.getWriter().write("No contestants found in the specified range.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setContentType("application/zip");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=\"contestants.zip\"");
|
||||||
|
response.setContentLength(zipData.length);
|
||||||
|
response.getOutputStream().write(zipData);
|
||||||
|
response.getOutputStream().flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/contestants/count")
|
||||||
|
@ApiOperation(value = "查询参赛者总数", notes = "查询数据库中参赛者的总数量和最大参赛者编号")
|
||||||
|
public Response<ContestantCountVO> getContestantCount() {
|
||||||
|
return Response.success(globalAwardService.getContestantCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.ai.da.feign.gateway;
|
||||||
|
|
||||||
|
import com.ai.da.common.response.Response;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 Gateway 黑名单接口,将指定用户的 token 加入黑名单。
|
||||||
|
* 替代原来的 SellerFeignClient.clearTokenCache。
|
||||||
|
*/
|
||||||
|
@FeignClient(name = "aida-gateway", path = "/internal")
|
||||||
|
public interface GatewayFeignClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将用户 token 加入黑名单。
|
||||||
|
* 后续 Gateway 会拒绝携带该用户 token 的请求。
|
||||||
|
*/
|
||||||
|
@PostMapping("/logout")
|
||||||
|
Response<Void> logout(@RequestParam("userId") Long userId);
|
||||||
|
}
|
||||||
20
src/main/java/com/ai/da/feign/seller/SellerFeignClient.java
Normal file
20
src/main/java/com/ai/da/feign/seller/SellerFeignClient.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ai.da.feign.seller;
|
||||||
|
|
||||||
|
import com.ai.da.common.response.Response;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 aida-seller 设计师相关接口的 Feign 客户端
|
||||||
|
*/
|
||||||
|
@FeignClient(name = "aida-seller", path = "/api/designer")
|
||||||
|
public interface SellerFeignClient {
|
||||||
|
|
||||||
|
@GetMapping("/check")
|
||||||
|
Response<Boolean> checkDesignerQualification(@RequestParam("userId") Long userId);
|
||||||
|
|
||||||
|
@PostMapping("/cache/clear")
|
||||||
|
Response<Void> clearTokenCache(@RequestParam("userId") Long userId);
|
||||||
|
}
|
||||||
@@ -68,6 +68,9 @@ public class Contestant {
|
|||||||
@TableField("pdf_size")
|
@TableField("pdf_size")
|
||||||
private Long pdfSize;
|
private Long pdfSize;
|
||||||
|
|
||||||
|
@TableField("portfolio_url")
|
||||||
|
private String portfolioUrl;
|
||||||
|
|
||||||
@TableField("created_at")
|
@TableField("created_at")
|
||||||
private LocalDateTime createdAt;
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
|||||||
17
src/main/java/com/ai/da/model/vo/ContestantCountVO.java
Normal file
17
src/main/java/com/ai/da/model/vo/ContestantCountVO.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ai.da.model.vo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ContestantCountVO {
|
||||||
|
|
||||||
|
private Long count;
|
||||||
|
|
||||||
|
private Integer maxContestantNumber;
|
||||||
|
}
|
||||||
@@ -239,7 +239,7 @@ public interface AccountService extends IService<Account> {
|
|||||||
|
|
||||||
Set<String> organizationNameSearch(String type, String name);
|
Set<String> organizationNameSearch(String type, String name);
|
||||||
|
|
||||||
void send618PromotionEmailTemp();
|
/*void send618PromotionEmailTemp();*/
|
||||||
|
|
||||||
void checkEduAdminExpireStatus();
|
void checkEduAdminExpireStatus();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ai.da.service;
|
|||||||
|
|
||||||
import com.ai.da.model.dto.ContestantDTO;
|
import com.ai.da.model.dto.ContestantDTO;
|
||||||
import com.ai.da.model.vo.CheckOTPVO;
|
import com.ai.da.model.vo.CheckOTPVO;
|
||||||
|
import com.ai.da.model.vo.ContestantCountVO;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -33,12 +34,18 @@ public interface GlobalAwardService {
|
|||||||
void saveContestantsToLocal() throws Exception;
|
void saveContestantsToLocal() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据参赛者编号范围导出参赛者文件到本地目录
|
* 将参赛者文件打包为 ZIP 并返回字节数组(不落盘,直接响应给浏览器)
|
||||||
* @param minContestantNumber 最小参赛者编号
|
* @param minContestantNumber 最小参赛者编号
|
||||||
* @param maxContestantNumber 最大参赛者编号
|
* @param maxContestantNumber 最大参赛者编号
|
||||||
* @return 导出的参赛者数量
|
* @return ZIP 文件的字节数组
|
||||||
*/
|
*/
|
||||||
int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception;
|
byte[] exportContestantFilesAsZip(Integer minContestantNumber, Integer maxContestantNumber) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询参赛者总数和最大参赛者编号
|
||||||
|
* @return 参赛者数量和最大参赛者编号
|
||||||
|
*/
|
||||||
|
ContestantCountVO getContestantCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import com.ai.da.common.enums.LoginTypeEnum;
|
|||||||
import com.ai.da.common.enums.ProductEnum;
|
import com.ai.da.common.enums.ProductEnum;
|
||||||
import com.ai.da.common.response.PageBaseResponse;
|
import com.ai.da.common.response.PageBaseResponse;
|
||||||
import com.ai.da.common.response.ResultEnum;
|
import com.ai.da.common.response.ResultEnum;
|
||||||
import com.ai.da.common.security.jwt.JWTTokenHelper;
|
import com.ai.da.common.utils.TokenGenerateUtils;
|
||||||
|
import com.ai.da.feign.gateway.GatewayFeignClient;
|
||||||
|
import com.ai.da.feign.seller.SellerFeignClient;
|
||||||
import com.ai.da.common.utils.*;
|
import com.ai.da.common.utils.*;
|
||||||
import com.ai.da.mapper.primary.*;
|
import com.ai.da.mapper.primary.*;
|
||||||
import com.ai.da.mapper.primary.entity.*;
|
import com.ai.da.mapper.primary.entity.*;
|
||||||
@@ -94,7 +96,13 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
private AccountExtendMapper accountExtendMapper;
|
private AccountExtendMapper accountExtendMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private JWTTokenHelper jwtTokenHelper;
|
private TokenGenerateUtils tokenGenerateUtils;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SellerFeignClient sellerFeignClient;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GatewayFeignClient gatewayFeignClient;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AccountLoginLogService accountLoginLogService;
|
private AccountLoginLogService accountLoginLogService;
|
||||||
@@ -136,9 +144,6 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
@Resource
|
@Resource
|
||||||
private RedisUtil redisUtil;
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private com.ai.da.common.security.config.SecurityProperties securityProperties;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserFollowService userFollowService;
|
private UserFollowService userFollowService;
|
||||||
|
|
||||||
@@ -353,11 +358,11 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
principal.setUsername(account.getUserName());
|
principal.setUsername(account.getUserName());
|
||||||
principal.setLanguage(account.getLanguage());
|
principal.setLanguage(account.getLanguage());
|
||||||
principal.setCountry(account.getCountry());
|
principal.setCountry(account.getCountry());
|
||||||
String token2 = jwtTokenHelper.createToken(principal);
|
String token2 = tokenGenerateUtils.createToken(principal);
|
||||||
// 本地 JVM 缓存(适配旧逻辑)
|
// 本地 JVM 缓存(适配旧逻辑)
|
||||||
LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2);
|
LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2);
|
||||||
// 同步写入 Redis,重启后仍然可用
|
// 同步写入 Redis,重启后仍然可用
|
||||||
long jwtExpiration = securityProperties.getJwtExpiration();
|
long jwtExpiration = tokenGenerateUtils.getJwtExpiration();
|
||||||
redisUtil.setLoginToken(account.getId(), token2, jwtExpiration);
|
redisUtil.setLoginToken(account.getId(), token2, jwtExpiration);
|
||||||
return token2;
|
return token2;
|
||||||
}
|
}
|
||||||
@@ -614,11 +619,23 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean logout(AccountLogoutDTO accountLogoutDTO) {
|
public Boolean logout(AccountLogoutDTO accountLogoutDTO) {
|
||||||
// jwt 本身失效比较难做,统一用缓存实现:删除缓存即失效
|
// 1. 删除本地缓存(保留,防止 Gateway 未启动时还能本地验证)
|
||||||
String userIdStr = String.valueOf(accountLogoutDTO.getUserId());
|
String userIdStr = String.valueOf(accountLogoutDTO.getUserId());
|
||||||
LocalCacheUtils.delTokenCache(userIdStr);
|
LocalCacheUtils.delTokenCache(userIdStr);
|
||||||
// 同时删除 Redis 中的 token,防止服务重启后仍然有效
|
// 2. 删除 Redis 中的 token(Gateway 黑名单会接力生效)
|
||||||
redisUtil.deleteLoginToken(accountLogoutDTO.getUserId());
|
redisUtil.deleteLoginToken(accountLogoutDTO.getUserId());
|
||||||
|
// 3. 调用 Gateway 黑名单接口,将 token 加入 Redis 黑名单
|
||||||
|
try {
|
||||||
|
gatewayFeignClient.logout(accountLogoutDTO.getUserId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("调用 Gateway 黑名单接口失败,userId={}, error={}", accountLogoutDTO.getUserId(), e.getMessage());
|
||||||
|
}
|
||||||
|
// 4. 同步调用 seller 清除本地缓存(兼容未接入 Gateway 的节点)
|
||||||
|
try {
|
||||||
|
sellerFeignClient.clearTokenCache(accountLogoutDTO.getUserId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("调用 seller 清理缓存失败,userId={}, error={}", accountLogoutDTO.getUserId(), e.getMessage());
|
||||||
|
}
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2153,7 +2170,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
redisUtil.addToString(key, newMailbox, CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY / 1000);
|
redisUtil.addToString(key, newMailbox, CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY / 1000);
|
||||||
|
|
||||||
String username = userHolder.getUsername();
|
String username = userHolder.getUsername();
|
||||||
String token = jwtTokenHelper.createToken(accountId, newMailbox);
|
String token = tokenGenerateUtils.createMailboxToken(accountId, newMailbox);
|
||||||
// 准备激活链接,链接应该要有有效期
|
// 准备激活链接,链接应该要有有效期
|
||||||
String link = "?" + token;
|
String link = "?" + token;
|
||||||
// 向新邮箱发送邮件,邮件附带激活链接,点击链接进行验证
|
// 向新邮箱发送邮件,邮件附带激活链接,点击链接进行验证
|
||||||
@@ -2163,7 +2180,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
// 验证激活链接
|
// 验证激活链接
|
||||||
public void activateNewEmail(String token){
|
public void activateNewEmail(String token){
|
||||||
// 获取链接地址信息,更新指定用户邮箱
|
// 获取链接地址信息,更新指定用户邮箱
|
||||||
String emailAndId = jwtTokenHelper.parseToEmailAndId(token);
|
String emailAndId = tokenGenerateUtils.parseMailboxToken(token);
|
||||||
String newMailbox = emailAndId.substring(0, emailAndId.lastIndexOf("_"));
|
String newMailbox = emailAndId.substring(0, emailAndId.lastIndexOf("_"));
|
||||||
String accountId = emailAndId.substring(emailAndId.lastIndexOf("_") + 1);
|
String accountId = emailAndId.substring(emailAndId.lastIndexOf("_") + 1);
|
||||||
|
|
||||||
@@ -3670,66 +3687,33 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/* @Override
|
||||||
public void send618PromotionEmailTemp() {
|
public void send618PromotionEmailTemp() {
|
||||||
QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<TrialOrder> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("is_deleted", 0);
|
||||||
|
|
||||||
queryWrapper.lambda()
|
List<TrialOrder> trialOrders = trialOrderMapper.selectList(queryWrapper);
|
||||||
.isNotNull(Account::getUserEmail)
|
|
||||||
.in(Account::getUserEmail, "xupei3360@163.com", "kimwong@code-create.com.hk", "kaicpang.pang@connect.polyu.hk", "chelseayu@code-create.com.hk")
|
|
||||||
.apply("LENGTH(TRIM(user_email)) > 0");
|
|
||||||
|
|
||||||
List<Account> accounts = baseMapper.selectList(queryWrapper);
|
|
||||||
|
|
||||||
// 按邮箱去重,保留每个邮箱的第一条记录
|
|
||||||
Map<String, Account> emailToAccountMap = new LinkedHashMap<>();
|
|
||||||
for (Account account : accounts) {
|
|
||||||
String email = account.getUserEmail();
|
|
||||||
if (!StringUtil.isNullOrEmpty(email)) {
|
|
||||||
email = email.trim().toLowerCase();
|
|
||||||
// 保留第一次出现的记录
|
|
||||||
emailToAccountMap.putIfAbsent(email, account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> uniqueEmails = new ArrayList<>(emailToAccountMap.keySet());
|
|
||||||
int total = uniqueEmails.size();
|
|
||||||
log.info("AiDA用户去重后邮件发送总量:{}", total);
|
|
||||||
|
|
||||||
// 控制发送速率:每发送20封后等待1秒,控制QPS在20以内
|
|
||||||
int batchSize = 20;
|
|
||||||
long sleepMillis = 1000;
|
|
||||||
int successCount = 0;
|
|
||||||
int failCount = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < uniqueEmails.size(); i++) {
|
|
||||||
String email = uniqueEmails.get(i);
|
|
||||||
log.info("邮件发送进度 {}/{}", i + 1, total);
|
|
||||||
|
|
||||||
|
// List<Account> accountList = accountMapper.selectList(queryWrapper);
|
||||||
|
System.out.println(trialOrders);
|
||||||
|
int total = trialOrders.size();
|
||||||
|
log.info("试用用户总量:{}", total);
|
||||||
|
int current = 1;
|
||||||
|
for (TrialOrder trialOrder : trialOrders) {
|
||||||
|
log.info("邮件发送进度 {}/{}", current, total);
|
||||||
try {
|
try {
|
||||||
// 统一发送英文版本
|
if (!StringUtil.isNullOrEmpty(trialOrder.getCountry()) && trialOrder.getCountry().equals("China")) {
|
||||||
// log.info("邮件地址 {}", email);
|
SendEmailUtil.send618PromotionEmailTemp(trialOrder.getEmail(), "CHINESE_SIMPLIFIED");
|
||||||
SendEmailUtil.send618PromotionEmailTemp(email, "ENGLISH");
|
} else {
|
||||||
successCount++;
|
// 英文
|
||||||
} catch (Exception e) {
|
SendEmailUtil.send618PromotionEmailTemp(trialOrder.getEmail(), "ENGLISH");
|
||||||
failCount++;
|
|
||||||
log.error("邮件发送失败,收件人:{},错误信息:{}", email, e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
}catch (Exception e) {
|
||||||
// 控制发送速率,每发送 batchSize 封后等待
|
log.info(e.getMessage());
|
||||||
if ((i + 1) % batchSize == 0 && (i + 1) < uniqueEmails.size()) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(sleepMillis);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
log.warn("邮件发送被中断");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
current ++;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
log.info("邮件发送完成,成功:{},失败:{}", successCount, failCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkEduAdminExpireStatus() {
|
public void checkEduAdminExpireStatus() {
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
|
|||||||
elementVO.setPrintBoardElements(printBoardElements);
|
elementVO.setPrintBoardElements(printBoardElements);
|
||||||
if (!CollectionUtils.isEmpty(printBoardIds)) {
|
if (!CollectionUtils.isEmpty(printBoardIds)) {
|
||||||
// 从数据库批量查询printBoard元素
|
// 从数据库批量查询printBoard元素
|
||||||
printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds);
|
printBoardElements.addAll(collectionElementMapper.selectBatchIds(printBoardIds));
|
||||||
// 验证查询结果的完整性
|
// 验证查询结果的完整性
|
||||||
if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) {
|
if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) {
|
||||||
throw new BusinessException("get.printBoards.data.is.mismatch");
|
throw new BusinessException("get.printBoards.data.is.mismatch");
|
||||||
|
|||||||
@@ -756,7 +756,7 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
|||||||
print.setPosition("[0.0,0.0]");
|
print.setPosition("[0.0,0.0]");
|
||||||
// print.setScale(1d);
|
// print.setScale(1d);
|
||||||
// todo mark 将print默认scale置为0.3
|
// todo mark 将print默认scale置为0.3
|
||||||
print.setScale(Arrays.toString(new Float[]{0.3f, 0.3f}));
|
print.setScale(Arrays.toString(new Float[]{1.0f, 1.0f}));
|
||||||
print.setAngle(0.0);
|
print.setAngle(0.0);
|
||||||
print.setPriority(1);
|
print.setPriority(1);
|
||||||
QueryWrapper<CollectionElement> getPrintboardLevel2TypeQw = new QueryWrapper<>();
|
QueryWrapper<CollectionElement> getPrintboardLevel2TypeQw = new QueryWrapper<>();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.ai.da.mapper.primary.entity.Notification;
|
|||||||
import com.ai.da.model.dto.ContestantDTO;
|
import com.ai.da.model.dto.ContestantDTO;
|
||||||
import com.ai.da.model.dto.PublishSysNotificationDTO;
|
import com.ai.da.model.dto.PublishSysNotificationDTO;
|
||||||
import com.ai.da.model.vo.CheckOTPVO;
|
import com.ai.da.model.vo.CheckOTPVO;
|
||||||
|
import com.ai.da.model.vo.ContestantCountVO;
|
||||||
import com.ai.da.service.GlobalAwardService;
|
import com.ai.da.service.GlobalAwardService;
|
||||||
import com.ai.da.service.MessageCenterService;
|
import com.ai.da.service.MessageCenterService;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
@@ -26,24 +27,22 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.util.zip.ZipEntry;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -187,6 +186,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
.videoSize(request.getVideoSize())
|
.videoSize(request.getVideoSize())
|
||||||
.pdfSize(request.getPdfSize())
|
.pdfSize(request.getPdfSize())
|
||||||
.contestantNumber(nextNumber)
|
.contestantNumber(nextNumber)
|
||||||
|
.portfolioUrl(request.getPortfolioUrl())
|
||||||
.createdAt(now)
|
.createdAt(now)
|
||||||
.updatedAt(now)
|
.updatedAt(now)
|
||||||
.build();
|
.build();
|
||||||
@@ -227,6 +227,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
existing.setVideoDuration(request.getVideoDuration());
|
existing.setVideoDuration(request.getVideoDuration());
|
||||||
existing.setVideoSize(request.getVideoSize());
|
existing.setVideoSize(request.getVideoSize());
|
||||||
existing.setPdfSize(request.getPdfSize());
|
existing.setPdfSize(request.getPdfSize());
|
||||||
|
existing.setPortfolioUrl(request.getPortfolioUrl());
|
||||||
existing.setUpdatedAt(now);
|
existing.setUpdatedAt(now);
|
||||||
contestantMapper.updateById(existing);
|
contestantMapper.updateById(existing);
|
||||||
resp.put("success", true);
|
resp.put("success", true);
|
||||||
@@ -244,7 +245,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
String[] headers = new String[] {
|
String[] headers = new String[] {
|
||||||
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||||
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
||||||
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "createdAt", "updatedAt"
|
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "portfolioUrl", "createdAt", "updatedAt"
|
||||||
};
|
};
|
||||||
for (int i = 0; i < headers.length; i++) {
|
for (int i = 0; i < headers.length; i++) {
|
||||||
Cell c = header.createCell(i);
|
Cell c = header.createCell(i);
|
||||||
@@ -265,11 +266,9 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||||
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||||
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||||
// 视频时长(秒)
|
|
||||||
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
||||||
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
|
|
||||||
if (cst.getVideoSize() == null) {
|
if (cst.getVideoSize() == null) {
|
||||||
r.createCell(ci++).setCellValue("");
|
r.createCell(ci++).setCellValue("");
|
||||||
} else {
|
} else {
|
||||||
@@ -282,6 +281,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
||||||
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
||||||
}
|
}
|
||||||
|
r.createCell(ci++).setCellValue(cst.getPortfolioUrl() == null ? "" : cst.getPortfolioUrl());
|
||||||
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||||
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
String[] headers = new String[] {
|
String[] headers = new String[] {
|
||||||
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||||
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
||||||
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "createdAt", "updatedAt"
|
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "portfolioUrl", "createdAt", "updatedAt"
|
||||||
};
|
};
|
||||||
for (int i = 0; i < headers.length; i++) {
|
for (int i = 0; i < headers.length; i++) {
|
||||||
Cell c = header.createCell(i);
|
Cell c = header.createCell(i);
|
||||||
@@ -332,11 +332,9 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||||
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||||
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||||
// 视频时长(秒)
|
|
||||||
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
||||||
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
|
|
||||||
if (cst.getVideoSize() == null) {
|
if (cst.getVideoSize() == null) {
|
||||||
r.createCell(ci++).setCellValue("");
|
r.createCell(ci++).setCellValue("");
|
||||||
} else {
|
} else {
|
||||||
@@ -349,6 +347,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
||||||
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
||||||
}
|
}
|
||||||
|
r.createCell(ci++).setCellValue(cst.getPortfolioUrl() == null ? "" : cst.getPortfolioUrl());
|
||||||
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||||
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||||
}
|
}
|
||||||
@@ -387,6 +386,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
dto.setVideoDuration(existing.getVideoDuration());
|
dto.setVideoDuration(existing.getVideoDuration());
|
||||||
dto.setPdfSize(existing.getPdfSize());
|
dto.setPdfSize(existing.getPdfSize());
|
||||||
dto.setVideoSize(existing.getVideoSize());
|
dto.setVideoSize(existing.getVideoSize());
|
||||||
|
dto.setPortfolioUrl(existing.getPortfolioUrl());
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +480,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
|
public byte[] exportContestantFilesAsZip(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
|
||||||
if (minContestantNumber == null || maxContestantNumber == null) {
|
if (minContestantNumber == null || maxContestantNumber == null) {
|
||||||
throw new BusinessException("minContestantNumber and maxContestantNumber are required.");
|
throw new BusinessException("minContestantNumber and maxContestantNumber are required.");
|
||||||
}
|
}
|
||||||
@@ -488,7 +488,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
throw new BusinessException("minContestantNumber cannot be greater than maxContestantNumber.");
|
throw new BusinessException("minContestantNumber cannot be greater than maxContestantNumber.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 根据contestantNumber范围查询参赛者
|
// 1. 根据 contestantNumber 范围查询参赛者
|
||||||
QueryWrapper<Contestant> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<Contestant> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.lambda()
|
queryWrapper.lambda()
|
||||||
.ge(Contestant::getContestantNumber, minContestantNumber)
|
.ge(Contestant::getContestantNumber, minContestantNumber)
|
||||||
@@ -498,18 +498,13 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
|
|
||||||
if (contestants.isEmpty()) {
|
if (contestants.isEmpty()) {
|
||||||
log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber);
|
log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber);
|
||||||
return 0;
|
return new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 创建基础目录
|
// 2. 在内存中构建 ZIP
|
||||||
String baseDir = uploadDir + "/contestants";
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
Path basePath = Paths.get(baseDir).toAbsolutePath();
|
java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(baos)) {
|
||||||
Files.createDirectories(basePath);
|
|
||||||
log.info("Base directory created: {}", basePath);
|
|
||||||
|
|
||||||
int exportedCount = 0;
|
|
||||||
|
|
||||||
// 3. 遍历每个参赛者,下载文件
|
|
||||||
for (Contestant contestant : contestants) {
|
for (Contestant contestant : contestants) {
|
||||||
Integer contestantNumber = contestant.getContestantNumber();
|
Integer contestantNumber = contestant.getContestantNumber();
|
||||||
if (contestantNumber == null) {
|
if (contestantNumber == null) {
|
||||||
@@ -517,71 +512,112 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建参赛者文件夹
|
String dirPrefix = contestantNumber + "/";
|
||||||
String contestantDir = baseDir + "/" + contestantNumber;
|
|
||||||
Path contestantPath = Paths.get(contestantDir);
|
|
||||||
Files.createDirectories(contestantPath);
|
|
||||||
|
|
||||||
// 下载PDF文件
|
// 添加 PDF 文件
|
||||||
String pdfPath = contestant.getPdfPath();
|
String pdfPath = contestant.getPdfPath();
|
||||||
if (StringUtils.isNotBlank(pdfPath)) {
|
if (StringUtils.isNotBlank(pdfPath)) {
|
||||||
try {
|
addMinioFileToZip(zos, pdfPath, dirPrefix + "design.pdf");
|
||||||
String fileName = pdfPath.contains("/") ?
|
|
||||||
pdfPath.substring(pdfPath.lastIndexOf("/") + 1) : "design.pdf";
|
|
||||||
downloadFileFromMinio(pdfPath, contestantPath.toString(), "design.pdf");
|
|
||||||
log.info("Downloaded PDF for contestant {}", fileName);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to download PDF for contestant {}: {}", contestantNumber, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载视频文件
|
// 添加视频文件
|
||||||
String videoPath = contestant.getVideoPath();
|
String videoPath = contestant.getVideoPath();
|
||||||
if (StringUtils.isNotBlank(videoPath)) {
|
if (StringUtils.isNotBlank(videoPath)) {
|
||||||
try {
|
|
||||||
// 根据路径判断视频格式
|
|
||||||
String fileName = videoPath.contains("/") ?
|
String fileName = videoPath.contains("/") ?
|
||||||
videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4";
|
videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4";
|
||||||
downloadFileFromMinio(videoPath, contestantPath.toString(), fileName);
|
addMinioFileToZip(zos, videoPath, dirPrefix + fileName);
|
||||||
log.info("Downloaded video for contestant {}", contestantNumber);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to download video for contestant {}: {}", contestantNumber, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exportedCount++;
|
// 添加参赛者信息 txt 文件
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("=== Contestant Information ===\n\n");
|
||||||
|
sb.append("ID: ").append(nullSafe(contestant.getId())).append("\n");
|
||||||
|
sb.append("Email: ").append(nullSafe(contestant.getEmail())).append("\n");
|
||||||
|
sb.append("Contestant Number: ").append(contestantNumber).append("\n");
|
||||||
|
sb.append("First Name: ").append(nullSafe(contestant.getFirstName())).append("\n");
|
||||||
|
sb.append("Last Name: ").append(nullSafe(contestant.getLastName())).append("\n");
|
||||||
|
sb.append("Gender: ").append(nullSafe(contestant.getGender())).append("\n");
|
||||||
|
sb.append("Occupation: ").append(nullSafe(contestant.getOccupation())).append("\n");
|
||||||
|
sb.append("Age: ").append(contestant.getAge() != null ? contestant.getAge() : "N/A").append("\n");
|
||||||
|
sb.append("Country/Region/City: ").append(nullSafe(contestant.getCountryRegionCity())).append("\n");
|
||||||
|
sb.append("Phone Number: ").append(nullSafe(contestant.getPhoneNumber())).append("\n");
|
||||||
|
sb.append("Design Title: ").append(nullSafe(contestant.getDesignTitle())).append("\n");
|
||||||
|
sb.append("Design Description: ").append(nullSafe(contestant.getDesignDescription())).append("\n");
|
||||||
|
sb.append("PDF Path: ").append(nullSafe(pdfPath)).append("\n");
|
||||||
|
sb.append("PDF Size (bytes): ").append(contestant.getPdfSize() != null ? contestant.getPdfSize() : "N/A").append("\n");
|
||||||
|
sb.append("Video Path: ").append(nullSafe(videoPath)).append("\n");
|
||||||
|
sb.append("Video Duration (seconds): ").append(contestant.getVideoDuration() != null ? contestant.getVideoDuration() : "N/A").append("\n");
|
||||||
|
sb.append("Video Size (bytes): ").append(contestant.getVideoSize() != null ? contestant.getVideoSize() : "N/A").append("\n");
|
||||||
|
sb.append("Portfolio URL: ").append(nullSafe(contestant.getPortfolioUrl())).append("\n");
|
||||||
|
sb.append("Created At: ").append(contestant.getCreatedAt() != null ? contestant.getCreatedAt() : "N/A").append("\n");
|
||||||
|
sb.append("Updated At: ").append(contestant.getUpdatedAt() != null ? contestant.getUpdatedAt() : "N/A").append("\n");
|
||||||
|
|
||||||
|
ZipEntry infoEntry = new ZipEntry(dirPrefix + "contestant_info.txt");
|
||||||
|
zos.putNextEntry(infoEntry);
|
||||||
|
zos.write(sb.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||||
|
zos.closeEntry();
|
||||||
|
log.info("Added contestant {} info to zip", contestantNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Exported {} contestants' files to {}", exportedCount, basePath);
|
zos.finish();
|
||||||
return exportedCount;
|
log.info("ZIP built for {} contestants, size: {} bytes", contestants.size(), baos.size());
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从MinIO下载文件到本地
|
* 将 MinIO 文件流式写入 ZIP,不落盘
|
||||||
* @param minioPath MinIO路径 (格式: bucketName/objectPath)
|
* @param zos ZIP 输出流
|
||||||
* @param localDir 本地目录
|
* @param minioPath MinIO 路径(格式: bucketName/objectPath)
|
||||||
* @param fileName 本地文件名
|
* @param entryName ZIP 条目名称
|
||||||
*/
|
*/
|
||||||
private void downloadFileFromMinio(String minioPath, String localDir, String fileName) {
|
private void addMinioFileToZip(java.util.zip.ZipOutputStream zos, String minioPath, String entryName) {
|
||||||
if (StringUtils.isBlank(minioPath)) {
|
if (StringUtils.isBlank(minioPath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从路径中提取bucket名称和对象名称
|
|
||||||
int index = minioPath.indexOf("/");
|
int index = minioPath.indexOf("/");
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
log.warn("Invalid MinIO path: {}", minioPath);
|
log.warn("Invalid MinIO path: {}", minioPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String bucketName = minioPath.substring(0, index);
|
String bucketName = minioPath.substring(0, index);
|
||||||
String objectName = minioPath.substring(index + 1);
|
String objectName = minioPath.substring(index + 1);
|
||||||
|
|
||||||
// 构建本地文件完整路径
|
try (InputStream in = minioUtil.download(bucketName, objectName)) {
|
||||||
Path localFilePath = Paths.get(localDir, fileName);
|
ZipEntry entry = new ZipEntry(entryName);
|
||||||
|
zos.putNextEntry(entry);
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = in.read(buffer)) != -1) {
|
||||||
|
zos.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
zos.closeEntry();
|
||||||
|
log.info("Added {} to zip ({} bytes)", entryName, entry.getSize());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to add {} to zip: {}", entryName, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 下载文件
|
@Override
|
||||||
minioUtil.downloadMinioObjectToLocal(bucketName, objectName, localFilePath.toString());
|
public ContestantCountVO getContestantCount() {
|
||||||
|
long count = contestantMapper.selectCount(null);
|
||||||
|
Integer maxContestantNumber = null;
|
||||||
|
QueryWrapper<Contestant> qMax = new QueryWrapper<>();
|
||||||
|
qMax.isNotNull("contestant_number");
|
||||||
|
qMax.orderByDesc("contestant_number");
|
||||||
|
qMax.last("LIMIT 1");
|
||||||
|
Contestant last = contestantMapper.selectOne(qMax);
|
||||||
|
if (last != null) {
|
||||||
|
maxContestantNumber = last.getContestantNumber();
|
||||||
|
}
|
||||||
|
return ContestantCountVO.builder()
|
||||||
|
.count(count)
|
||||||
|
.maxContestantNumber(maxContestantNumber)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nullSafe(String value) {
|
||||||
|
return value != null ? value : "N/A";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import com.ai.da.common.enums.CollectionLevel1TypeEnum;
|
|||||||
import com.ai.da.common.response.PageBaseResponse;
|
import com.ai.da.common.response.PageBaseResponse;
|
||||||
import com.ai.da.common.response.PageResponse;
|
import com.ai.da.common.response.PageResponse;
|
||||||
import com.ai.da.common.response.Response;
|
import com.ai.da.common.response.Response;
|
||||||
import com.ai.da.common.security.jwt.JWTTokenHelper;
|
import com.ai.da.common.utils.TokenGenerateUtils;
|
||||||
import com.ai.da.common.utils.MinioUtil;
|
import com.ai.da.common.utils.MinioUtil;
|
||||||
import com.ai.da.mapper.primary.*;
|
import com.ai.da.mapper.primary.*;
|
||||||
import com.ai.da.mapper.primary.entity.*;
|
import com.ai.da.mapper.primary.entity.*;
|
||||||
@@ -70,7 +70,7 @@ public class LLMServiceImpl implements LLMService {
|
|||||||
@Resource
|
@Resource
|
||||||
private WorkspaceRelStyleMapper workspaceRelStyleMapper;
|
private WorkspaceRelStyleMapper workspaceRelStyleMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private JWTTokenHelper jwtTokenHelper;
|
private TokenGenerateUtils tokenGenerateUtils;
|
||||||
@Resource
|
@Resource
|
||||||
private DesignService designService;
|
private DesignService designService;
|
||||||
private final ExecutorService executor = Executors.newCachedThreadPool();
|
private final ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
@@ -89,9 +89,9 @@ public class LLMServiceImpl implements LLMService {
|
|||||||
|
|
||||||
executor.submit(() -> {
|
executor.submit(() -> {
|
||||||
try {
|
try {
|
||||||
boolean validate = jwtTokenHelper.validateToken(token); //
|
boolean validate = tokenGenerateUtils.validateToken(token); //
|
||||||
if (validate) {
|
if (validate) {
|
||||||
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(token);
|
AuthPrincipalVo principal = tokenGenerateUtils.parserToUser(token);
|
||||||
Long accountId = principal.getId();
|
Long accountId = principal.getId();
|
||||||
// String url = "http://18.167.251.121:10002/chat-stream";
|
// String url = "http://18.167.251.121:10002/chat-stream";
|
||||||
String url = "http://10.1.1.240:1013/chat-stream";
|
String url = "http://10.1.1.240:1013/chat-stream";
|
||||||
@@ -237,10 +237,10 @@ public class LLMServiceImpl implements LLMService {
|
|||||||
|
|
||||||
executor.submit(() -> {
|
executor.submit(() -> {
|
||||||
try {
|
try {
|
||||||
boolean validate = jwtTokenHelper.validateToken(token);
|
boolean validate = tokenGenerateUtils.validateToken(token);
|
||||||
// boolean validate = true;
|
// boolean validate = true;
|
||||||
if (validate) {
|
if (validate) {
|
||||||
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(token);
|
AuthPrincipalVo principal = tokenGenerateUtils.parserToUser(token);
|
||||||
Long accountId = principal.getId();
|
Long accountId = principal.getId();
|
||||||
// String url = "http://18.167.251.121:10002/api/chat_stream";
|
// String url = "http://18.167.251.121:10002/api/chat_stream";
|
||||||
String url = "http://18.167.251.121:2011/api/chat_stream";
|
String url = "http://18.167.251.121:2011/api/chat_stream";
|
||||||
|
|||||||
@@ -1060,11 +1060,12 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
String periodEnd = DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
String periodEnd = DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||||
|
|
||||||
qwPI.lambda().eq(PaymentInfo::getOrderNo, subscriptionInfo.getOrderNo())
|
qwPI.lambda().eq(PaymentInfo::getOrderNo, subscriptionInfo.getOrderNo())
|
||||||
|
.eq(PaymentInfo::getTradeState, "paid")
|
||||||
.between(PaymentInfo::getCreateTime, periodStart, periodEnd)
|
.between(PaymentInfo::getCreateTime, periodStart, periodEnd)
|
||||||
.orderByDesc(PaymentInfo::getId);
|
.orderByDesc(PaymentInfo::getId);
|
||||||
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
|
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
|
||||||
if (paymentInfos.isEmpty()) {
|
if (paymentInfos.isEmpty()) {
|
||||||
log.info("不发送邮件,原因:【根据order_no:{},查询到的paymentInfos为空】", orderNo);
|
log.info("不发送邮件,原因:【根据order_no:{},查询到的成功的paymentInfos为空】", orderNo);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PaymentInfo paymentInfo = paymentInfos.get(0);
|
PaymentInfo paymentInfo = paymentInfos.get(0);
|
||||||
|
|||||||
@@ -905,15 +905,15 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 将构建好的结果对象添加到返回列表
|
// 将构建好的结果对象添加到返回列表
|
||||||
results.add(magicToolResultVO);
|
// results.add(magicToolResultVO);
|
||||||
} else if (Objects.isNull(magicToolResultVO)) {
|
} else if (Objects.isNull(magicToolResultVO)) {
|
||||||
// 如果Redis中没有结果对象,创建执行中状态的结果对象
|
// 如果Redis中没有结果对象,创建执行中状态的结果对象
|
||||||
magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
|
magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
|
||||||
results.add(magicToolResultVO);
|
// results.add(magicToolResultVO);
|
||||||
} else {
|
}/* else {
|
||||||
// 如果Redis中有结果对象但URL为空,直接添加到返回列表
|
// 如果Redis中有结果对象但URL为空,直接添加到返回列表
|
||||||
results.add(magicToolResultVO);
|
results.add(magicToolResultVO);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// 收集任务状态用于统计
|
// 收集任务状态用于统计
|
||||||
if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
|
if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
|
||||||
@@ -1461,12 +1461,16 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
if (StringUtil.isNullOrEmpty(fluxResult)) {
|
if (StringUtil.isNullOrEmpty(fluxResult)) {
|
||||||
toProductImageResult.setStatus("Fail");
|
toProductImageResult.setStatus("Fail");
|
||||||
toProductImageResultMapper.updateById(toProductImageResult);
|
toProductImageResultMapper.updateById(toProductImageResult);
|
||||||
|
if (toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
|
||||||
sortRank(toProductImageResult);
|
sortRank(toProductImageResult);
|
||||||
|
}
|
||||||
results.add(new MagicToolResultVO(taskId, "Fail"));
|
results.add(new MagicToolResultVO(taskId, "Fail"));
|
||||||
} else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
|
} else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
|
||||||
toProductImageResult.setStatus(fluxResult);
|
toProductImageResult.setStatus(fluxResult);
|
||||||
toProductImageResultMapper.updateById(toProductImageResult);
|
toProductImageResultMapper.updateById(toProductImageResult);
|
||||||
|
if (fluxResult.equals("Fail") && toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
|
||||||
sortRank(toProductImageResult);
|
sortRank(toProductImageResult);
|
||||||
|
}
|
||||||
results.add(new MagicToolResultVO(taskId, fluxResult));
|
results.add(new MagicToolResultVO(taskId, fluxResult));
|
||||||
} else {
|
} else {
|
||||||
results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
|
results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
|
||||||
@@ -2203,10 +2207,14 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
|
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
|
||||||
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
|
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
|
||||||
List<AllCollectionVO> childList = new ArrayList<>();
|
List<AllCollectionVO> childList = new ArrayList<>();
|
||||||
|
// 收集需要删除的失败记录ID,用于后续统一清理并重新排序
|
||||||
|
List<Long> failedSortIds = new ArrayList<>();
|
||||||
for (CollectionSort userLikeSort : childSortList) {
|
for (CollectionSort userLikeSort : childSortList) {
|
||||||
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
||||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
failedSortIds.add(userLikeSort.getId());
|
||||||
|
log.info("【获取内容】TO_PRODUCT_IMAGE结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||||
@@ -2238,6 +2246,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
||||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
failedSortIds.add(userLikeSort.getId());
|
||||||
|
log.info("【获取内容】RELIGHT结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||||
@@ -2250,6 +2260,114 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
}
|
}
|
||||||
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
|
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
|
||||||
|
|
||||||
|
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
|
||||||
|
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
|
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
|
||||||
|
} else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
|
||||||
|
TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
|
toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
|
||||||
|
} else {
|
||||||
|
ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
|
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
|
||||||
|
}
|
||||||
|
toProductImageResultVO.setCollectionType(CollectionType.RELIGHT.getValue());
|
||||||
|
toProductImageResultVO.setSort(userLikeSort.getSort());
|
||||||
|
toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
|
||||||
|
toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
|
||||||
|
toProductImageResultVO.setParentId(userLikeSort.getParentId());
|
||||||
|
childList.add(toProductImageResultVO);
|
||||||
|
} else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
|
||||||
|
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
|
||||||
|
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
|
||||||
|
failedSortIds.add(userLikeSort.getId());
|
||||||
|
log.info("【获取内容】POSE_TRANSFORM结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
|
||||||
|
poseTransformationVO.setId(item.getId());
|
||||||
|
poseTransformationVO.setTaskId(item.getUniqueId());
|
||||||
|
poseTransformationVO.setProductImage(getMinioUrl(item.getProductImage()));
|
||||||
|
poseTransformationVO.setLastFrameProductImage(getMinioUrl(item.getLastFrameProductImage()));
|
||||||
|
poseTransformationVO.setPrompt(item.getPrompt());
|
||||||
|
poseTransformationVO.setGifUrl(getMinioUrl(item.getGifUrl()));
|
||||||
|
poseTransformationVO.setVideoUrl(getMinioUrl(item.getVideoUrl()));
|
||||||
|
poseTransformationVO.setFirstFrameUrl(getMinioUrl(item.getFirstFrameUrl()));
|
||||||
|
poseTransformationVO.setIsLiked(item.getIsLiked());
|
||||||
|
poseTransformationVO.setCollectionType(CollectionType.POSE_TRANSFORM.getValue());
|
||||||
|
poseTransformationVO.setSort(userLikeSort.getSort());
|
||||||
|
poseTransformationVO.setUserLikeSortId(userLikeSort.getId());
|
||||||
|
poseTransformationVO.setRelationType(userLikeSort.getRelationType());
|
||||||
|
poseTransformationVO.setResultType(CollectionType.POSE_TRANSFORM.getValue());
|
||||||
|
poseTransformationVO.setParentId(userLikeSort.getParentId());
|
||||||
|
poseTransformationVO.setModelName(item.getModelName());
|
||||||
|
poseTransformationVO.setPoseId(item.getPoseId());
|
||||||
|
poseTransformationVO.setStatus(item.getTaskStatus());
|
||||||
|
childList.add(poseTransformationVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 统一处理失败的记录:从collection_sort表中删除失败的记录,并重新排序
|
||||||
|
if (CollectionUtil.isNotEmpty(failedSortIds)) {
|
||||||
|
Long parentId = collectionSort.getId();
|
||||||
|
Long projectId = projectDTO.getId();
|
||||||
|
log.info("【获取内容】检测到{}条失败记录需要清理,parentId={}, projectId={}", failedSortIds.size(), parentId, projectId);
|
||||||
|
for (Long failedSortId : failedSortIds) {
|
||||||
|
CollectionSort failedRecord = collectionSortMapper.selectById(failedSortId);
|
||||||
|
if (failedRecord != null) {
|
||||||
|
String relationType = failedRecord.getRelationType();
|
||||||
|
Long relationId = failedRecord.getRelationId();
|
||||||
|
collectionSortService.deleteCollectionSort(relationId, relationType, projectId, parentId);
|
||||||
|
log.info("【获取内容】已删除失败记录,relationId={}, relationType={}", relationId, relationType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 重新查询子列表,获取更新后的排序
|
||||||
|
childSortList = collectionSortMapper.selectList(childCollectionQw);
|
||||||
|
// 重新构建childList,使用更新后的sort值
|
||||||
|
childList = new ArrayList<>();
|
||||||
|
for (CollectionSort userLikeSort : childSortList) {
|
||||||
|
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
||||||
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
|
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||||
|
ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);
|
||||||
|
|
||||||
|
ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
|
||||||
|
if (Objects.isNull(toProductImageRecord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
|
||||||
|
|
||||||
|
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
|
||||||
|
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
|
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
|
||||||
|
} else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
|
||||||
|
TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
|
toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
|
||||||
|
} else {
|
||||||
|
ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
|
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
|
||||||
|
}
|
||||||
|
toProductImageResultVO.setCollectionType(CollectionType.TO_PRODUCT_IMAGE.getValue());
|
||||||
|
toProductImageResultVO.setSort(userLikeSort.getSort());
|
||||||
|
toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
|
||||||
|
toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
|
||||||
|
toProductImageResultVO.setParentId(userLikeSort.getParentId());
|
||||||
|
childList.add(toProductImageResultVO);
|
||||||
|
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
||||||
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
|
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||||
|
ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);
|
||||||
|
|
||||||
|
ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
|
||||||
|
if (Objects.isNull(toProductImageRecord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
|
||||||
|
|
||||||
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
|
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
|
||||||
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
|
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
|
||||||
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
|
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
|
||||||
@@ -2293,6 +2411,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
childList.add(poseTransformationVO);
|
childList.add(poseTransformationVO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.info("【获取内容】失败记录清理完成,重新排序后childList.size={}", childList.size());
|
||||||
|
}
|
||||||
o.setChildList(childList);
|
o.setChildList(childList);
|
||||||
|
|
||||||
list.add(o);
|
list.add(o);
|
||||||
|
|||||||
@@ -1,184 +0,0 @@
|
|||||||
server.port=5567
|
|
||||||
|
|
||||||
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
|
|
||||||
#spring.datasource.primary.jdbcUrl=jdbc:mysql://18.167.251.121:33008/aida?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.primary.jdbcUrl=jdbc:mysql://18.167.251.121:33008/aida_back?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
#spring.datasource.primary.jdbcUrl=jdbc:mysql://18.167.251.121:33008/test_aida_3.1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.primary.username=aida_con
|
|
||||||
spring.datasource.primary.password=123456
|
|
||||||
|
|
||||||
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
|
|
||||||
spring.datasource.secondary.jdbcUrl=jdbc:mysql://18.167.251.121:33008/attribute_retrieval_style?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.secondary.username=aida_con
|
|
||||||
spring.datasource.secondary.password=123456
|
|
||||||
|
|
||||||
#security
|
|
||||||
spring.security.jwtSecret=JWTSECRET
|
|
||||||
spring.security.jwtTokenHeader=Authorization
|
|
||||||
spring.security.jwtTokenPrefix=Bearer-
|
|
||||||
## 24Сʱ
|
|
||||||
spring.security.jwtExpiration=8640000000
|
|
||||||
#spring security权限设置 认证了token还要认证权限 不然报错Full authentication is required to access this resource
|
|
||||||
spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\
|
|
||||||
/api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\
|
|
||||||
/api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR,/api/alipay-hk/**,/api/portfolio/**,\
|
|
||||||
/api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/**,/api/project/**,/api/llm/**, /api/subscription_plan/**,/api/global-award/**
|
|
||||||
spring.security.authApi=/auth/login
|
|
||||||
|
|
||||||
|
|
||||||
rsa.private_key=MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
|
|
||||||
|
|
||||||
#mybatis
|
|
||||||
mybatis-plus.global-config.banner=false
|
|
||||||
mybatis-plus.mapper-locations=classpath:mapper/*/*.xml
|
|
||||||
mybatis-plus.global-config.db-config.logic-delete-field=isDeleted
|
|
||||||
mybatis-plus.global-config.db-config.logic-delete-value=1
|
|
||||||
mybatis-plus.global-config.db-config.logic-not-delete-value=0
|
|
||||||
|
|
||||||
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
|
|
||||||
|
|
||||||
file.mac.path=~/file/
|
|
||||||
file.linux.path=/workspace/home/aida/file/
|
|
||||||
#linux服务器域名(预览和下载用)
|
|
||||||
file.linuxDomain=https://www.aida.com.hk/download/
|
|
||||||
file.windows.path=D:\\upload\\
|
|
||||||
spring.servlet.multipart.max-file-size = 10MB
|
|
||||||
spring.servlet.multipart.max-request-size= 10MB
|
|
||||||
#访问python服务的ip(对应环境)
|
|
||||||
access.python.ip=http://18.167.251.121
|
|
||||||
access.python.port=9994
|
|
||||||
access.python.generate_sr_port=9994
|
|
||||||
access.python.address=http://18.167.251.121:9994
|
|
||||||
|
|
||||||
minio.endpoint=https://www.minio-api.aida.com.hk
|
|
||||||
minio.accessKey=admin
|
|
||||||
minio.secretKey=Aidlab123123!
|
|
||||||
minio.bucketName.clothing=aida-clothing
|
|
||||||
minio.bucketName.mannequins=aida-mannequins
|
|
||||||
minio.bucketName.results=aida-results
|
|
||||||
minio.bucketName.sysImage=aida-sys-image
|
|
||||||
minio.bucketName.users=aida-users
|
|
||||||
minio.bucketName.collectionElement=aida-collection-element
|
|
||||||
minio.bucketName.gradient=aida-gradient
|
|
||||||
minio.bucketName.modifiedSketch=aida-modified-sketch
|
|
||||||
minio.bucketName.slogan=aida-slogan
|
|
||||||
minio.bucketName.partialDesign=aida-partial-design
|
|
||||||
minio.bucketName.globalAward=global-award
|
|
||||||
redirect_url=http://18.167.251.121:7788
|
|
||||||
|
|
||||||
spring.rabbitmq.host=18.167.251.121
|
|
||||||
spring.rabbitmq.port=5672
|
|
||||||
spring.rabbitmq.username=rabbit
|
|
||||||
spring.rabbitmq.password=123456
|
|
||||||
spring.rabbitmq.virtual-host=/
|
|
||||||
|
|
||||||
spring.data.redis.host=172.31.11.32
|
|
||||||
#spring.data.redis.host=18.167.251.121
|
|
||||||
spring.data.redis.port=6379
|
|
||||||
spring.data.redis.database=1
|
|
||||||
spring.data.redis.password=Aidlab
|
|
||||||
spring.data.redis.lettuce.pool.max-active=8
|
|
||||||
spring.data.redis.lettuce.pool.max-idle=8
|
|
||||||
spring.data.redis.lettuce.pool.min-idle=0
|
|
||||||
spring.data.redis.lettuce.pool.max-wait=5
|
|
||||||
|
|
||||||
redis.key.orderForGenerate=OrderForGenerate
|
|
||||||
redis.key.generateCancelSet=GenerateCancelSet
|
|
||||||
redis.key.generateExceptionMap=Generate:Exception
|
|
||||||
redis.key.resultMap=ResultMap
|
|
||||||
redis.key.orderForSR=OrderForSR
|
|
||||||
redis.key.SRCancelSet=SRCancelSet
|
|
||||||
redis.key.SRExceptionMap=SRExceptionMap
|
|
||||||
redis.key.taskList=TaskList
|
|
||||||
redis.key.credits.pre-deduction=Credits:PreDeduction
|
|
||||||
redis.key.generateResult=Generate:Result
|
|
||||||
redis.key.toProductImageResultKey=ToProductImage:Result
|
|
||||||
redis.key.relightResultKey=Relight:Result
|
|
||||||
redis.key.newPosted=LastViewNewPostedTime
|
|
||||||
redis.key.maximumUserId=CodeCreate:MaximumUserId
|
|
||||||
|
|
||||||
aws.s3.accessKeyId=AKIAVD3OJIMF6UJFLSHZ
|
|
||||||
aws.s3.secretKey=LNIwFFB27/QedtZ+Q/viVUoX9F5x1DbuM8N0DkD8
|
|
||||||
aws.s3.regionName=ap-east-1
|
|
||||||
|
|
||||||
# RabbitMQ Exchange and Queue configurations
|
|
||||||
rabbitmq.queues.generate=generate-queue-dev
|
|
||||||
rabbitmq.queues.sr=SR-queue-dev
|
|
||||||
rabbitmq.queues.srResult=SuperResolution-dev
|
|
||||||
rabbitmq.queues.generateResult=GenerateImage-dev
|
|
||||||
rabbitmq.queues.toProductImageResult=ToProductImage-dev
|
|
||||||
rabbitmq.queues.relightResult=Relight-dev
|
|
||||||
rabbitmq.queues.poseTransform=PoseTransform-dev
|
|
||||||
rabbitmq.exchange.generate=generate-exchange
|
|
||||||
rabbitmq.queues.designBatch=DesignBatch-dev
|
|
||||||
rabbitmq.queues.relightBatch=BatchRelight-dev
|
|
||||||
rabbitmq.queues.toProductImageBatch=BatchToProductImage-dev
|
|
||||||
rabbitmq.queues.poseTransformBatch=BatchPoseTransform-dev
|
|
||||||
rabbitmq.queues.emailRetry=emailRetry-business
|
|
||||||
# 死信队列配置
|
|
||||||
rabbitmq.dead-letter.exchange=dlx.email-retry
|
|
||||||
rabbitmq.dead-letter.queue=dlx.email-retry.queue
|
|
||||||
rabbitmq.dead-letter.routing-key=dlx.email-retry.key
|
|
||||||
|
|
||||||
orderList.link=https://develop.aida.com.hk/home/homePage?order=
|
|
||||||
|
|
||||||
# 0 不发送邮件通知 1 发送邮件通知
|
|
||||||
stripe.webhook.fail.reminder=0
|
|
||||||
# kim test
|
|
||||||
#stripe.paymentMethodConfiguration=pmc_1LywTWH7nPZ8bkrN6FvdCUWG
|
|
||||||
# developer test
|
|
||||||
stripe.paymentMethodConfiguration=pmc_1QIKyq02n1TEydyNKVEYvhW7
|
|
||||||
#thymelea模板配置
|
|
||||||
#控制 Thymeleaf 是否启用模板缓存 生产环境用true,以提高性能
|
|
||||||
spring.thymeleaf.cache=false
|
|
||||||
|
|
||||||
#指定邮件服务器的地址。
|
|
||||||
spring.mail.host=mail.aida.com.hk
|
|
||||||
#指定邮件服务器的端口号。
|
|
||||||
spring.mail.port=465
|
|
||||||
#指定登录邮件服务器的用户名
|
|
||||||
spring.mail.username=info@aida.com.hk
|
|
||||||
#指定登录邮件服务器的密码 / 授权码
|
|
||||||
spring.mail.password=AIdlab@2025
|
|
||||||
spring.mail.default-encoding=UTF-8
|
|
||||||
|
|
||||||
# SSL 配置
|
|
||||||
#启用 SSL 加密
|
|
||||||
spring.mail.properties.mail.smtp.ssl.enable=true
|
|
||||||
#指定 SSL 连接的端口号。通常与 spring.mail.port 一致
|
|
||||||
spring.mail.properties.mail.smtp.socketFactory.port=465
|
|
||||||
|
|
||||||
ALIYUN_API_KEY=sk-dc3f88b7df844fc5a7d3616ebd8a589c
|
|
||||||
DOUBAO_API_KEY=853b3c55-f1dd-406e-a356-64123637f635
|
|
||||||
FREEPIK_API_KEY=FPSX94e5917d376a4facb87dabbaa0319c72
|
|
||||||
|
|
||||||
ollama.url=http://localhost:11434/api/chat
|
|
||||||
|
|
||||||
#google.client.id=29310152396-c44dcsoksjirhn7vbo29p8u8n0sg4qps.apps.googleusercontent.com
|
|
||||||
google.client.id=157095842121-kdd1fdf8m8nudvj9sprstb2k2prnf9e4.apps.googleusercontent.com
|
|
||||||
#google.client.secret=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
|
|
||||||
google.client.secret=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
|
|
||||||
google.redirect.uri=https://develop.api.aida.com.hk/api/third/party/auth/google_callback
|
|
||||||
design.callback.url=https://develop.api.aida.com.hk/api/third/party/receiveDesignResults
|
|
||||||
|
|
||||||
# ===== 分片上传配置 =====
|
|
||||||
|
|
||||||
# 临时文件目录
|
|
||||||
file.upload.temp.dir=temp/uploads
|
|
||||||
|
|
||||||
# 分片大小配置
|
|
||||||
# PDF分片大小:1MB
|
|
||||||
file.upload.chunk.size.pdf=1048576
|
|
||||||
# 视频分片大小:2MB
|
|
||||||
file.upload.chunk.size.video=2097152
|
|
||||||
|
|
||||||
# 文件大小限制
|
|
||||||
# PDF最大文件大小:20MB
|
|
||||||
file.upload.max.size.pdf=20971520
|
|
||||||
# 视频最大文件大小:100MB
|
|
||||||
file.upload.max.size.video=104857600
|
|
||||||
|
|
||||||
# 上传任务过期时间(小时)
|
|
||||||
file.upload.task.expiry.hours=24
|
|
||||||
|
|
||||||
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
server.port=5567
|
|
||||||
|
|
||||||
#datasource
|
|
||||||
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
|
|
||||||
spring.datasource.primary.jdbcUrl=jdbc:mysql://18.167.251.121:3306/aida?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.primary.username=root
|
|
||||||
spring.datasource.primary.password=QWa998345
|
|
||||||
|
|
||||||
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
|
|
||||||
spring.datasource.secondary.jdbcUrl=jdbc:mysql://18.167.251.121:33008/attribute_retrieval_style?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.secondary.username=aida_con
|
|
||||||
spring.datasource.secondary.password=123456
|
|
||||||
|
|
||||||
#security
|
|
||||||
spring.security.jwtSecret=JWTSECRET
|
|
||||||
spring.security.jwtTokenHeader=Authorization
|
|
||||||
spring.security.jwtTokenPrefix=Bearer-
|
|
||||||
## 24Сʱ
|
|
||||||
#spring.security.jwtExpiration=8640000000
|
|
||||||
spring.security.jwtExpiration=604800000
|
|
||||||
#spring security权限设置 认证了token还要认证权限 不然报错Full authentication is required to access this resource
|
|
||||||
spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\
|
|
||||||
/api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\
|
|
||||||
/api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR,/api/alipay-hk/**,/api/portfolio/**,\
|
|
||||||
/api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/**,/api/project/**,/api/llm/**, /api/subscription_plan/**,/api/global-award/**
|
|
||||||
spring.security.authApi=/auth/login
|
|
||||||
|
|
||||||
|
|
||||||
rsa.private_key=MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
|
|
||||||
|
|
||||||
#mybatis
|
|
||||||
mybatis-plus.global-config.banner=false
|
|
||||||
mybatis-plus.mapper-locations=classpath:mapper/*/*.xml
|
|
||||||
mybatis-plus.global-config.db-config.logic-delete-field=isDeleted
|
|
||||||
mybatis-plus.global-config.db-config.logic-delete-value=1
|
|
||||||
mybatis-plus.global-config.db-config.logic-not-delete-value=0
|
|
||||||
|
|
||||||
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
|
|
||||||
|
|
||||||
file.mac.path=~/file/
|
|
||||||
file.linux.path=/workspace/home/aida/file/
|
|
||||||
#linux服务器域名(预览和下载用)
|
|
||||||
file.linuxDomain=https://www.aida.com.hk/download/
|
|
||||||
file.windows.path=D:\\upload\\
|
|
||||||
spring.servlet.multipart.max-file-size = 10MB
|
|
||||||
spring.servlet.multipart.max-request-size= 10MB
|
|
||||||
#访问python服务的ip(对应环境)
|
|
||||||
access.python.ip=http://18.167.251.121
|
|
||||||
access.python.port=9990
|
|
||||||
access.python.generate_sr_port=9990
|
|
||||||
access.python.address=http://18.167.251.121:9990
|
|
||||||
|
|
||||||
minio.endpoint=https://www.minio-api.aida.com.hk
|
|
||||||
minio.accessKey=admin
|
|
||||||
minio.secretKey=Aidlab123123!
|
|
||||||
minio.bucketName.clothing=aida-clothing
|
|
||||||
minio.bucketName.mannequins=aida-mannequins
|
|
||||||
minio.bucketName.results=aida-results
|
|
||||||
minio.bucketName.sysImage=aida-sys-image
|
|
||||||
minio.bucketName.users=aida-users
|
|
||||||
minio.bucketName.collectionElement=aida-collection-element
|
|
||||||
minio.bucketName.gradient=aida-gradient
|
|
||||||
minio.bucketName.modifiedSketch=aida-modified-sketch
|
|
||||||
minio.bucketName.slogan=aida-slogan
|
|
||||||
minio.bucketName.partialDesign=aida-partial-design
|
|
||||||
minio.bucketName.globalAward=global-award
|
|
||||||
redirect_url=http://18.167.251.121:7788
|
|
||||||
|
|
||||||
spring.rabbitmq.host=18.167.251.121
|
|
||||||
spring.rabbitmq.port=5672
|
|
||||||
spring.rabbitmq.username=rabbit
|
|
||||||
spring.rabbitmq.password=123456
|
|
||||||
spring.rabbitmq.virtual-host=/
|
|
||||||
|
|
||||||
spring.data.redis.host=172.31.11.32
|
|
||||||
#spring.data.redis.host=18.167.251.121
|
|
||||||
spring.data.redis.port=6379
|
|
||||||
spring.data.redis.database=2
|
|
||||||
spring.data.redis.password=Aidlab
|
|
||||||
spring.data.redis.lettuce.pool.max-active=8
|
|
||||||
spring.data.redis.lettuce.pool.max-idle=8
|
|
||||||
spring.data.redis.lettuce.pool.min-idle=0
|
|
||||||
spring.data.redis.lettuce.pool.max-wait=5
|
|
||||||
|
|
||||||
redis.key.orderForGenerate=OrderForGenerate
|
|
||||||
redis.key.generateCancelSet=GenerateCancelSet
|
|
||||||
redis.key.generateExceptionMap=Generate:Exception
|
|
||||||
redis.key.resultMap=ResultMap
|
|
||||||
redis.key.orderForSR=OrderForSR
|
|
||||||
redis.key.SRCancelSet=SRCancelSet
|
|
||||||
redis.key.SRExceptionMap=SRExceptionMap
|
|
||||||
redis.key.taskList=TaskList
|
|
||||||
redis.key.credits.pre-deduction=Credits:PreDeduction
|
|
||||||
redis.key.generateResult=Generate:Result
|
|
||||||
redis.key.toProductImageResultKey=ToProductImage:Result
|
|
||||||
redis.key.relightResultKey=Relight:Result
|
|
||||||
redis.key.newPosted=LastViewNewPostedTime
|
|
||||||
redis.key.maximumUserId=CodeCreate:MaximumUserId
|
|
||||||
|
|
||||||
aws.s3.accessKeyId=AKIAVD3OJIMF6UJFLSHZ
|
|
||||||
aws.s3.secretKey=LNIwFFB27/QedtZ+Q/viVUoX9F5x1DbuM8N0DkD8
|
|
||||||
aws.s3.regionName=ap-east-1
|
|
||||||
|
|
||||||
# RabbitMQ Exchange and Queue configurations
|
|
||||||
rabbitmq.queues.generate=generate-queue-prod
|
|
||||||
rabbitmq.queues.sr=SR-queue-prod
|
|
||||||
rabbitmq.queues.srResult=SuperResolution-prod
|
|
||||||
rabbitmq.queues.generateResult=GenerateImage-prod
|
|
||||||
rabbitmq.queues.toProductImageResult=ToProductImage-prod
|
|
||||||
rabbitmq.queues.relightResult=Relight-prod
|
|
||||||
rabbitmq.queues.poseTransform=PoseTransform-prod
|
|
||||||
rabbitmq.exchange.generate=generate-exchange
|
|
||||||
rabbitmq.queues.designBatch=DesignBatch-dev
|
|
||||||
rabbitmq.queues.relightBatch=BatchRelight-dev
|
|
||||||
rabbitmq.queues.toProductImageBatch=BatchToProductImage-dev
|
|
||||||
rabbitmq.queues.poseTransformBatch=BatchPoseTransform-dev
|
|
||||||
rabbitmq.queues.emailRetry=emailRetry-business
|
|
||||||
# 死信队列配置
|
|
||||||
rabbitmq.dead-letter.exchange=dlx.email-retry
|
|
||||||
rabbitmq.dead-letter.queue=dlx.email-retry.queue
|
|
||||||
rabbitmq.dead-letter.routing-key=dlx.email-retry.key
|
|
||||||
|
|
||||||
orderList.link=https://aida.com.hk/home/homePage?order=
|
|
||||||
|
|
||||||
# 0 不发送邮件通知 1 发送邮件通知
|
|
||||||
stripe.webhook.fail.reminder=1
|
|
||||||
# kim live
|
|
||||||
stripe.paymentMethodConfiguration=pmc_1Qu6yJH7nPZ8bkrNULYnFFPf
|
|
||||||
# kim test
|
|
||||||
#stripe.paymentMethodConfiguration=pmc_1LywTWH7nPZ8bkrN6FvdCUWG
|
|
||||||
# developer test
|
|
||||||
#stripe.paymentMethodConfiguration=pmc_1QIKyq02n1TEydyNKVEYvhW7
|
|
||||||
#thymelea模板配置
|
|
||||||
#控制 Thymeleaf 是否启用模板缓存 生产环境用true,以提高性能
|
|
||||||
spring.thymeleaf.cache=false
|
|
||||||
|
|
||||||
#指定邮件服务器的地址。
|
|
||||||
spring.mail.host=mail.aida.com.hk
|
|
||||||
#指定邮件服务器的端口号。
|
|
||||||
spring.mail.port=465
|
|
||||||
#指定登录邮件服务器的用户名
|
|
||||||
spring.mail.username=info@aida.com.hk
|
|
||||||
#指定登录邮件服务器的密码 / 授权码
|
|
||||||
spring.mail.password=AIdlab@2025
|
|
||||||
spring.mail.default-encoding=UTF-8
|
|
||||||
|
|
||||||
# SSL 配置
|
|
||||||
#启用 SSL 加密
|
|
||||||
spring.mail.properties.mail.smtp.ssl.enable=true
|
|
||||||
#指定 SSL 连接的端口号。通常与 spring.mail.port 一致
|
|
||||||
spring.mail.properties.mail.smtp.socketFactory.port=465
|
|
||||||
|
|
||||||
ALIYUN_API_KEY=sk-dc3f88b7df844fc5a7d3616ebd8a589c
|
|
||||||
DOUBAO_API_KEY=853b3c55-f1dd-406e-a356-64123637f635
|
|
||||||
FREEPIK_API_KEY=FPSX94e5917d376a4facb87dabbaa0319c72
|
|
||||||
|
|
||||||
google.client.id=29310152396-nnsd3h533fld665oguu8ovrt1nukmt46.apps.googleusercontent.com
|
|
||||||
google.client.secret=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
|
|
||||||
google.redirect.uri=https://www.api.aida.com.hk/api/third/party/auth/google_callback
|
|
||||||
design.callback.url=https://api.aida.com.hk/api/third/party/receiveDesignResults
|
|
||||||
|
|
||||||
# ===== 分片上传配置 =====
|
|
||||||
|
|
||||||
# 临时文件目录
|
|
||||||
file.upload.temp.dir=temp/uploads
|
|
||||||
|
|
||||||
# 分片大小配置
|
|
||||||
# PDF分片大小:1MB
|
|
||||||
file.upload.chunk.size.pdf=1048576
|
|
||||||
# 视频分片大小:2MB
|
|
||||||
file.upload.chunk.size.video=2097152
|
|
||||||
|
|
||||||
# 文件大小限制
|
|
||||||
# PDF最大文件大小:20MB
|
|
||||||
file.upload.max.size.pdf=20971520
|
|
||||||
# 视频最大文件大小:100MB
|
|
||||||
file.upload.max.size.video=104857600
|
|
||||||
|
|
||||||
# 上传任务过期时间(小时)
|
|
||||||
file.upload.task.expiry.hours=24
|
|
||||||
|
|
||||||
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
server.port=5567
|
|
||||||
|
|
||||||
#datasource
|
|
||||||
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
|
|
||||||
spring.datasource.primary.jdbcUrl=jdbc:mysql://18.167.251.121:3306/aida?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.primary.username=root
|
|
||||||
spring.datasource.primary.password=QWa998345
|
|
||||||
|
|
||||||
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
|
|
||||||
spring.datasource.secondary.jdbcUrl=jdbc:mysql://18.167.251.121:33008/attribute_retrieval_new?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
||||||
spring.datasource.secondary.username=aida_con
|
|
||||||
spring.datasource.secondary.password=123456
|
|
||||||
|
|
||||||
#security
|
|
||||||
spring.security.jwtSecret=JWTSECRET
|
|
||||||
spring.security.jwtTokenHeader=Authorization
|
|
||||||
spring.security.jwtTokenPrefix=Bearer-
|
|
||||||
## 24Сʱ
|
|
||||||
spring.security.jwtExpiration=8640000000
|
|
||||||
#spring security权限设置 认证了token还要认证权限 不然报错Full authentication is required to access this resource
|
|
||||||
spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\
|
|
||||||
/api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\
|
|
||||||
/api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR
|
|
||||||
spring.security.authApi=/auth/login
|
|
||||||
|
|
||||||
|
|
||||||
rsa.private_key=MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
|
|
||||||
|
|
||||||
#mybatis
|
|
||||||
mybatis-plus.global-config.banner=false
|
|
||||||
mybatis-plus.mapper-locations=classpath:mapper/*/*.xml
|
|
||||||
mybatis-plus.global-config.db-config.logic-delete-field=isDeleted
|
|
||||||
mybatis-plus.global-config.db-config.logic-delete-value=1
|
|
||||||
mybatis-plus.global-config.db-config.logic-not-delete-value=0
|
|
||||||
|
|
||||||
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
|
|
||||||
|
|
||||||
file.mac.path=~/file/
|
|
||||||
file.linux.path=/workspace/home/aida/file/
|
|
||||||
#linux服务器域名(预览和下载用)
|
|
||||||
file.linuxDomain=https://www.aida.com.hk/download/
|
|
||||||
file.windows.path=D:\\upload\\
|
|
||||||
spring.servlet.multipart.max-file-size = 10MB
|
|
||||||
spring.servlet.multipart.max-request-size= 10MB
|
|
||||||
#访问python服务的ip(对应环境)
|
|
||||||
#access.python.ip=http://43.198.80.117
|
|
||||||
access.python.ip=http://18.167.251.121
|
|
||||||
#access.python.ip=http://18.167.251.121:9991/
|
|
||||||
access.python.port=9992
|
|
||||||
access.python.sr=http://18.167.251.121:9994
|
|
||||||
|
|
||||||
minio.endpoint=https://www.minio.aida.com.hk:12024
|
|
||||||
minio.accessKey=admin
|
|
||||||
minio.secretKey=Aidlab123123!
|
|
||||||
minio.bucketName.clothing=aida-clothing
|
|
||||||
minio.bucketName.mannequins=aida-mannequins
|
|
||||||
minio.bucketName.results=aida-results
|
|
||||||
minio.bucketName.sysImage=aida-sys-image
|
|
||||||
minio.bucketName.users=aida-users
|
|
||||||
minio.bucketName.collectionElement=aida-collection-element
|
|
||||||
redirect_url=http://18.167.251.121:7788
|
|
||||||
|
|
||||||
spring.rabbitmq.host=18.167.251.121
|
|
||||||
spring.rabbitmq.port=5672
|
|
||||||
spring.rabbitmq.username=rabbit
|
|
||||||
spring.rabbitmq.password=123456
|
|
||||||
spring.rabbitmq.virtual-host=/
|
|
||||||
|
|
||||||
spring.redis.host=172.31.11.32
|
|
||||||
#spring.redis.host=18.167.251.121
|
|
||||||
spring.redis.port=6379
|
|
||||||
spring.redis.database=1
|
|
||||||
spring.redis.password=Aidlab
|
|
||||||
spring.redis.lettuce.pool.max-active=8
|
|
||||||
spring.redis.lettuce.pool.max-idle=8
|
|
||||||
spring.redis.lettuce.pool.min-idle=0
|
|
||||||
spring.redis.lettuce.pool.max-wait=5
|
|
||||||
|
|
||||||
redis.key.orderForGenerate=OrderForGenerate
|
|
||||||
redis.key.generateCancelSet=GenerateCancelSet
|
|
||||||
redis.key.generateExceptionMap=Generate:Exception
|
|
||||||
redis.key.resultMap=ResultMap
|
|
||||||
redis.key.orderForSR=OrderForSR
|
|
||||||
redis.key.SRCancelSet=SRCancelSet
|
|
||||||
redis.key.SRExceptionMap=SRExceptionMap
|
|
||||||
redis.key.taskList=TaskList
|
|
||||||
redis.key.credits.pre-deduction=Credits:PreDeduction
|
|
||||||
redis.key.generateResult=Generate:Result
|
|
||||||
|
|
||||||
aws.s3.accessKeyId=AKIAVD3OJIMF6UJFLSHZ
|
|
||||||
aws.s3.secretKey=LNIwFFB27/QedtZ+Q/viVUoX9F5x1DbuM8N0DkD8
|
|
||||||
aws.s3.regionName=ap-east-1
|
|
||||||
|
|
||||||
# RabbitMQ Exchange and Queue configurations
|
|
||||||
rabbitmq.queues.generate=generate-queue-test
|
|
||||||
rabbitmq.queues.sr=SR-queue-test
|
|
||||||
rabbitmq.queues.srResult=SuperResolution-test
|
|
||||||
rabbitmq.queues.generateResult=GenerateImage-test
|
|
||||||
rabbitmq.queues.toProductImageResult=ToProductImage-test
|
|
||||||
rabbitmq.queues.relightResult=Relight-test
|
|
||||||
rabbitmq.exchange.generate=generate-exchange
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#<23><><EFBFBD><EFBFBD>application-test<73>ļ<EFBFBD>(<28><><EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>)
|
|
||||||
#spring.profiles.active=test
|
|
||||||
|
|
||||||
#<23><><EFBFBD><EFBFBD>application-prod<6F>ļ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
||||||
#spring.profiles.active=prod
|
|
||||||
|
|
||||||
#<23><><EFBFBD><EFBFBD>application-dev<65>ļ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
||||||
spring.profiles.active=dev
|
|
||||||
134
src/main/resources/application.yml
Normal file
134
src/main/resources/application.yml
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# ============================================================
|
||||||
|
# aida-back - 本地配置(不区分环境)
|
||||||
|
# 公共配置(DB、Redis、RabbitMQ、MinIO、API Keys 等)由 Nacos 统一管理
|
||||||
|
# 此文件仅包含 back 服务私有的业务配置
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
server:
|
||||||
|
port: 5567
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: aida-back
|
||||||
|
|
||||||
|
# ---------- 副数据源(back 私有,由 Nacos 统一管理) ----------
|
||||||
|
|
||||||
|
# ---------- Token 生成参数(由 TokenGenerateUtils 使用) ----------
|
||||||
|
security:
|
||||||
|
jwtSecret: JWTSECRET
|
||||||
|
jwtTokenHeader: Authorization
|
||||||
|
jwtTokenPrefix: Bearer-
|
||||||
|
jwtExpiration: 8640000000
|
||||||
|
|
||||||
|
# ---------- Python 服务 ----------
|
||||||
|
access:
|
||||||
|
python:
|
||||||
|
ip: http://18.167.251.121
|
||||||
|
port: 9994
|
||||||
|
generate_sr_port: 9994
|
||||||
|
address: http://18.167.251.121:9994
|
||||||
|
|
||||||
|
# ---------- MinIO Buckets ----------
|
||||||
|
minio:
|
||||||
|
bucketName:
|
||||||
|
clothing: aida-clothing
|
||||||
|
mannequins: aida-mannequins
|
||||||
|
results: aida-results
|
||||||
|
sysImage: aida-sys-image
|
||||||
|
users: aida-users
|
||||||
|
collectionElement: aida-collection-element
|
||||||
|
gradient: aida-gradient
|
||||||
|
modifiedSketch: aida-modified-sketch
|
||||||
|
slogan: aida-slogan
|
||||||
|
partialDesign: aida-partial-design
|
||||||
|
globalAward: global-award
|
||||||
|
|
||||||
|
# ---------- Redis Keys ----------
|
||||||
|
redis:
|
||||||
|
key:
|
||||||
|
orderForGenerate: OrderForGenerate
|
||||||
|
generateCancelSet: GenerateCancelSet
|
||||||
|
generateExceptionMap: Generate:Exception
|
||||||
|
resultMap: ResultMap
|
||||||
|
orderForSR: OrderForSR
|
||||||
|
SRCancelSet: SRCancelSet
|
||||||
|
SRExceptionMap: SRExceptionMap
|
||||||
|
taskList: TaskList
|
||||||
|
credits:
|
||||||
|
pre-deduction: Credits:PreDeduction
|
||||||
|
generateResult: Generate:Result
|
||||||
|
toProductImageResultKey: ToProductImage:Result
|
||||||
|
relightResultKey: Relight:Result
|
||||||
|
newPosted: LastViewNewPostedTime
|
||||||
|
maximumUserId: CodeCreate:MaximumUserId
|
||||||
|
|
||||||
|
# ---------- RabbitMQ 队列 ----------
|
||||||
|
rabbitmq:
|
||||||
|
queues:
|
||||||
|
generate: generate-queue
|
||||||
|
sr: SR-queue
|
||||||
|
srResult: SuperResolution
|
||||||
|
generateResult: GenerateImage
|
||||||
|
toProductImageResult: ToProductImage
|
||||||
|
relightResult: Relight
|
||||||
|
poseTransform: PoseTransform
|
||||||
|
designBatch: DesignBatch
|
||||||
|
relightBatch: BatchRelight
|
||||||
|
toProductImageBatch: BatchToProductImage
|
||||||
|
poseTransformBatch: BatchPoseTransform
|
||||||
|
emailRetry: emailRetry-business
|
||||||
|
exchange:
|
||||||
|
generate: generate-exchange
|
||||||
|
dead-letter:
|
||||||
|
exchange: dlx.email-retry
|
||||||
|
queue: dlx.email-retry.queue
|
||||||
|
routing-key: dlx.email-retry.key
|
||||||
|
|
||||||
|
# ---------- 第三方服务 ----------
|
||||||
|
orderList:
|
||||||
|
link: https://develop.aida.com.hk/home/homePage?order=
|
||||||
|
|
||||||
|
stripe:
|
||||||
|
webhook:
|
||||||
|
fail:
|
||||||
|
reminder: 0
|
||||||
|
paymentMethodConfiguration: pmc_1QIKyq02n1TEydyNKVEYvhW7
|
||||||
|
|
||||||
|
google:
|
||||||
|
client:
|
||||||
|
id: 157095842121-kdd1fdf8m8nudvj9sprstb2k2prnf9e4.apps.googleusercontent.com
|
||||||
|
secret: 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
|
||||||
|
redirect:
|
||||||
|
uri: https://develop.api.aida.com.hk/api/third/party/auth/google_callback
|
||||||
|
|
||||||
|
design:
|
||||||
|
callback:
|
||||||
|
url: https://darkish-copied-sprinkler.ngrok-free.dev/api/third/party/receiveDesignResults
|
||||||
|
|
||||||
|
redirect:
|
||||||
|
url: http://18.167.251.121:7788
|
||||||
|
|
||||||
|
global:
|
||||||
|
award:
|
||||||
|
link: https://aida-global-design-awards.com.hk/contestants?id=
|
||||||
|
|
||||||
|
# ---------- 文件上传 ----------
|
||||||
|
file:
|
||||||
|
upload:
|
||||||
|
temp:
|
||||||
|
dir: temp/uploads
|
||||||
|
chunk:
|
||||||
|
size:
|
||||||
|
pdf: 1048576
|
||||||
|
video: 2097152
|
||||||
|
max:
|
||||||
|
size:
|
||||||
|
pdf: 20971520
|
||||||
|
video: 104857600
|
||||||
|
task:
|
||||||
|
expiry:
|
||||||
|
hours: 24
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
com.aida: debug
|
||||||
21
src/main/resources/bootstrap.yml
Normal file
21
src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# ============================================================
|
||||||
|
# aida-back - Bootstrap
|
||||||
|
# 通过 NACOS_NAMESPACE 环境变量切换命名空间(dev / test / prod)
|
||||||
|
# 示例:docker run -e NACOS_NAMESPACE=prod ...
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: aida-back
|
||||||
|
config:
|
||||||
|
import: optional:nacos:aida-public-${NACOS_NAMESPACE:test}.yml
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
||||||
|
namespace: ${NACOS_NAMESPACE:test}
|
||||||
|
config:
|
||||||
|
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
||||||
|
namespace: ${NACOS_NAMESPACE:test}
|
||||||
|
group: ${NACOS_GROUP:DEFAULT_GROUP}
|
||||||
|
file-extension: yaml
|
||||||
Reference in New Issue
Block a user