This commit is contained in:
parent
cd9227be31
commit
5274fb8d64
@ -1,21 +1,21 @@
|
|||||||
package org.dromara.sis.config;
|
//package org.dromara.sis.config;
|
||||||
|
//
|
||||||
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.web.client.RestTemplate;
|
//import org.springframework.web.client.RestTemplate;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 应用配置类
|
// * 应用配置类
|
||||||
*/
|
// */
|
||||||
@Configuration
|
//@Configuration
|
||||||
public class SOSAppConfig {
|
//public class SOSAppConfig {
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 配置 RestTemplate 用于 API 调用
|
// * 配置 RestTemplate 用于 API 调用
|
||||||
* @return RestTemplate 实例
|
// * @return RestTemplate 实例
|
||||||
*/
|
// */
|
||||||
@Bean
|
// @Bean
|
||||||
public RestTemplate restTemplate() {
|
// public RestTemplate restTemplate() {
|
||||||
return new RestTemplate();
|
// return new RestTemplate();
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
@ -4,16 +4,17 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.dromara.sis.service.ApiService;
|
import org.dromara.sis.service.ApiService;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.retry.annotation.Backoff;
|
||||||
|
import org.springframework.retry.annotation.Retryable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 服务实现类
|
* API服务实现类,支持获取Token、刷新Token和401响应处理
|
||||||
* 负责与外部 API 进行通信
|
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -22,34 +23,43 @@ public class ApiServiceImpl implements ApiService {
|
|||||||
@Value("${api.url}")
|
@Value("${api.url}")
|
||||||
private String apiUrl;
|
private String apiUrl;
|
||||||
|
|
||||||
|
@Value("${api.authUrl}")
|
||||||
|
private String authUrl; // 认证URL: /sos/v1/mntn/account/appId/token
|
||||||
|
|
||||||
|
@Value("${api.refreshUrl}")
|
||||||
|
private String refreshUrl; // 刷新Token URL: /sos/v1/mntn/account/refresh/token
|
||||||
|
|
||||||
|
@Value("${api.appId}")
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
@Value("${api.appCode}")
|
||||||
|
private String appCode;
|
||||||
|
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
// 缓存Token信息
|
||||||
|
private static final Map<String, TokenInfo> tokenCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public ApiServiceImpl(RestTemplate restTemplate) {
|
public ApiServiceImpl(RestTemplate restTemplate) {
|
||||||
this.restTemplate = restTemplate;
|
this.restTemplate = restTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Retryable(value = {HttpClientErrorException.Unauthorized.class}, maxAttempts = 2, backoff = @Backoff(delay = 1000))
|
||||||
public Map<String, Object> fetchAlarmRecords(int pageNum, int pageSize) {
|
public Map<String, Object> fetchAlarmRecords(int pageNum, int pageSize) {
|
||||||
try {
|
String token = getAccessToken();
|
||||||
// 设置请求头
|
|
||||||
|
// 设置请求头,添加Token
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
headers.set("token", token); // 根据接口要求,使用"Token"而非"Authorization"
|
||||||
|
|
||||||
// 构建请求体
|
// 构建请求体
|
||||||
Map<String, Object> requestBody = new HashMap<>();
|
Map<String, Object> requestBody = buildRequestParams(pageNum, pageSize);
|
||||||
requestBody.put("PageSize", pageSize);
|
|
||||||
requestBody.put("PageNum", pageNum);
|
|
||||||
|
|
||||||
List<List<Map<String, Object>>> filters = List.of(
|
log.info("请求参数:{}", requestBody);
|
||||||
List.of(Map.of("Key", "FinishTime", "Type", "str", "Value", "2025-07-27"))
|
try {
|
||||||
);
|
// 发送带Token的请求
|
||||||
requestBody.put("Filters", filters);
|
|
||||||
|
|
||||||
requestBody.put("OrderKey", "StartTime");
|
|
||||||
requestBody.put("Desc", "0");
|
|
||||||
requestBody.put("OrFirst", true);
|
|
||||||
|
|
||||||
// 发送请求
|
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<Map> response = restTemplate.exchange(
|
ResponseEntity<Map> response = restTemplate.exchange(
|
||||||
apiUrl,
|
apiUrl,
|
||||||
@ -57,8 +67,8 @@ public class ApiServiceImpl implements ApiService {
|
|||||||
requestEntity,
|
requestEntity,
|
||||||
Map.class
|
Map.class
|
||||||
);
|
);
|
||||||
|
log.info("请求返回:{}", response);
|
||||||
|
|
||||||
// 处理响应
|
|
||||||
if (response.getStatusCode() == HttpStatus.OK) {
|
if (response.getStatusCode() == HttpStatus.OK) {
|
||||||
Map<String, Object> result = response.getBody();
|
Map<String, Object> result = response.getBody();
|
||||||
if (result != null && result.get("Status").equals(0)) {
|
if (result != null && result.get("Status").equals(0)) {
|
||||||
@ -71,9 +81,211 @@ public class ApiServiceImpl implements ApiService {
|
|||||||
log.error("API请求失败,状态码: {}", response.getStatusCode());
|
log.error("API请求失败,状态码: {}", response.getStatusCode());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
} catch (HttpClientErrorException.Unauthorized e) {
|
||||||
|
// 捕获401错误,清除缓存的Token并重试
|
||||||
|
log.warn("Token已过期,清除缓存并尝试重新获取: {}", e.getMessage());
|
||||||
|
tokenCache.remove(appId);
|
||||||
|
// 重新获取Token并再次调用(由@Retryable注解处理)
|
||||||
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("调用API异常: {}", e.getMessage(), e);
|
log.error("调用API异常: {}", e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取访问Token
|
||||||
|
*/
|
||||||
|
private synchronized String getAccessToken() {
|
||||||
|
// 检查缓存中是否有有效的Token
|
||||||
|
TokenInfo tokenInfo = tokenCache.get(appId);
|
||||||
|
if (tokenInfo != null && !isTokenExpired(tokenInfo)) {
|
||||||
|
return tokenInfo.getAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试刷新Token
|
||||||
|
if (tokenInfo != null && tokenInfo.getRefreshToken() != null) {
|
||||||
|
log.info("尝试刷新现有Token...");
|
||||||
|
try {
|
||||||
|
String refreshedToken = refreshAccessToken(tokenInfo.getRefreshToken());
|
||||||
|
if (refreshedToken != null) {
|
||||||
|
return refreshedToken;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("刷新Token失败,将重新获取: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存中没有有效Token或刷新失败,重新获取
|
||||||
|
log.info("正在获取新的访问Token...");
|
||||||
|
try {
|
||||||
|
// 构建获取Token的请求体
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("AppId", appId);
|
||||||
|
body.put("AppCode", appCode);
|
||||||
|
|
||||||
|
HttpEntity<Map<String, Object>> request = new HttpEntity<>(body, headers);
|
||||||
|
|
||||||
|
// 发送获取Token的请求
|
||||||
|
ResponseEntity<Map> response = restTemplate.postForEntity(
|
||||||
|
authUrl,
|
||||||
|
request,
|
||||||
|
Map.class
|
||||||
|
);
|
||||||
|
log.info("接口响应:{},状态码:{}",response,response.getStatusCode());
|
||||||
|
|
||||||
|
if (response.getStatusCode() == HttpStatus.OK) {
|
||||||
|
Map<String, Object> tokenResponse = response.getBody();
|
||||||
|
if (tokenResponse != null && tokenResponse.get("Status").equals(0)) {
|
||||||
|
String accessToken = (String) tokenResponse.get("Token");
|
||||||
|
String refreshToken = (String) tokenResponse.get("RefreshToken");
|
||||||
|
Integer expireIn = (Integer) tokenResponse.get("ExpireIn");
|
||||||
|
|
||||||
|
// 缓存新获取的Token,设置过期时间(提前1分钟,避免临界点问题)
|
||||||
|
TokenInfo newTokenInfo = new TokenInfo(
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
System.currentTimeMillis() + (expireIn - 60) * 1000
|
||||||
|
);
|
||||||
|
tokenCache.put(appId, newTokenInfo);
|
||||||
|
|
||||||
|
log.info("成功获取新的访问Token,有效期: {}秒", expireIn);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.error("获取Token失败,状态码: {}", response.getStatusCode());
|
||||||
|
throw new RuntimeException("获取访问Token失败");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取Token异常: {}", e.getMessage(), e);
|
||||||
|
throw new RuntimeException("获取访问Token异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新访问Token
|
||||||
|
*/
|
||||||
|
private String refreshAccessToken(String refreshToken) {
|
||||||
|
try {
|
||||||
|
// 构建刷新Token的请求体
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("RefreshToken", refreshToken);
|
||||||
|
|
||||||
|
HttpEntity<Map<String, Object>> request = new HttpEntity<>(body, headers);
|
||||||
|
|
||||||
|
// 发送刷新Token的请求
|
||||||
|
ResponseEntity<Map> response = restTemplate.postForEntity(
|
||||||
|
refreshUrl,
|
||||||
|
request,
|
||||||
|
Map.class
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.getStatusCode() == HttpStatus.OK) {
|
||||||
|
Map<String, Object> tokenResponse = response.getBody();
|
||||||
|
if (tokenResponse != null && tokenResponse.get("Status").equals(0)) {
|
||||||
|
String accessToken = (String) tokenResponse.get("Token");
|
||||||
|
String newRefreshToken = (String) tokenResponse.get("RefreshToken");
|
||||||
|
Integer expireIn = (Integer) tokenResponse.get("ExpireIn");
|
||||||
|
|
||||||
|
// 更新缓存的Token信息
|
||||||
|
TokenInfo tokenInfo = tokenCache.get(appId);
|
||||||
|
if (tokenInfo != null) {
|
||||||
|
tokenInfo.setAccessToken(accessToken);
|
||||||
|
tokenInfo.setRefreshToken(newRefreshToken);
|
||||||
|
tokenInfo.setExpireTime(System.currentTimeMillis() + (expireIn - 60) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("成功刷新访问Token,有效期: {}秒", expireIn);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("刷新Token失败,将重新获取");
|
||||||
|
return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("刷新Token异常: {}", e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查Token是否已过期
|
||||||
|
*/
|
||||||
|
private boolean isTokenExpired(TokenInfo tokenInfo) {
|
||||||
|
return tokenInfo.getExpireTime() < System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建请求参数
|
||||||
|
*/
|
||||||
|
private Map<String, Object> buildRequestParams(int pageNum, int pageSize) {
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("PageSize", pageSize);
|
||||||
|
requestBody.put("PageNum", pageNum);
|
||||||
|
requestBody.put("OrFirst", true);
|
||||||
|
requestBody.put("Filters", Collections.emptyList()); // 空过滤器
|
||||||
|
requestBody.put("OrderKey", "StartTime");
|
||||||
|
requestBody.put("Desc", 1); // 降序排列
|
||||||
|
|
||||||
|
return requestBody;
|
||||||
|
}
|
||||||
|
// private Map<String, Object> buildRequestParams(int pageNum, int pageSize) {
|
||||||
|
// Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
// requestBody.put("'PageSize'", pageSize);
|
||||||
|
// requestBody.put("'PageNum'", pageNum);
|
||||||
|
//
|
||||||
|
// List<List<Map<String, Object>>> filters = new ArrayList<>();
|
||||||
|
// requestBody.put("'Filters'", filters);
|
||||||
|
//
|
||||||
|
// requestBody.put("'OrderKey'", "'StartTime'");
|
||||||
|
// requestBody.put("'Desc'", "1");
|
||||||
|
// requestBody.put("'OrFirst'", true);
|
||||||
|
//
|
||||||
|
// return requestBody;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token信息内部类(修改为可更新的类)
|
||||||
|
*/
|
||||||
|
private static class TokenInfo {
|
||||||
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
private long expireTime;
|
||||||
|
|
||||||
|
public TokenInfo(String accessToken, String refreshToken, long expireTime) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
this.expireTime = expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpireTime() {
|
||||||
|
return expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessToken(String accessToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpireTime(long expireTime) {
|
||||||
|
this.expireTime = expireTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class DataSyncTask {
|
|||||||
// 提取操作记录数据
|
// 提取操作记录数据
|
||||||
Map<Long, List<Map<String, Object>>> operatorMap = new HashMap<>();
|
Map<Long, List<Map<String, Object>>> operatorMap = new HashMap<>();
|
||||||
for (Map<String, Object> recordMap : recordList) {
|
for (Map<String, Object> recordMap : recordList) {
|
||||||
Long recordId = (Long) recordMap.get("Id");
|
Long recordId = Long.valueOf((Integer)recordMap.get("Id"));
|
||||||
List<Map<String, Object>> operators = (List<Map<String, Object>>) recordMap.get("TaskOperators");
|
List<Map<String, Object>> operators = (List<Map<String, Object>>) recordMap.get("TaskOperators");
|
||||||
if (operators != null && !operators.isEmpty()) {
|
if (operators != null && !operators.isEmpty()) {
|
||||||
operatorMap.put(recordId, operators);
|
operatorMap.put(recordId, operators);
|
||||||
|
@ -13,7 +13,10 @@ spring:
|
|||||||
# API 配置
|
# API 配置
|
||||||
api:
|
api:
|
||||||
url: https://norsos.lionking110.com/sos/v1/mntn/business/appId/alarm/list
|
url: https://norsos.lionking110.com/sos/v1/mntn/business/appId/alarm/list
|
||||||
|
authUrl: https://norsos.lionking110.com/sos/v1/mntn/account/appId/token
|
||||||
|
refreshUrl: https://norsos.lionking110.com/sos/v1/mntn/account/refresh/token
|
||||||
|
appId: dfc7ec7507de4626b8c920c4fe1ff8b1
|
||||||
|
appCode: fe11d05aa5704dffaa0b1c4b56ba80b2
|
||||||
# 同步配置
|
# 同步配置
|
||||||
sync:
|
sync:
|
||||||
pageSize: 100
|
pageSize: 100
|
||||||
|
@ -40,9 +40,9 @@ spring.sql.init.platform=mysql
|
|||||||
db.num=1
|
db.num=1
|
||||||
|
|
||||||
### Connect URL of DB:
|
### Connect URL of DB:
|
||||||
db.url.0=jdbc:mysql://127.0.0.1:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
db.url.0=jdbc:mysql://47.109.37.87:23306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||||
db.user.0=root
|
db.user.0=root
|
||||||
db.password.0=root
|
db.password.0=admin@123456
|
||||||
|
|
||||||
### the maximum retry times for push
|
### the maximum retry times for push
|
||||||
nacos.config.push.maxRetryTime=50
|
nacos.config.push.maxRetryTime=50
|
||||||
|
Loading…
Reference in New Issue
Block a user