feat(biz): 优化楼宇数据同步逻辑并增强HTTP客户端功能

- 修改 AlibabaBuildingJob,支持按校区并行拉取楼宇数据
- 默认设置分页参数 pageSize=100 和 page=1
- HTTP 客户端增加 JSON 类型请求头
- 统一异常信息为英文,提升国际化支持
- 优化访问令牌刷新日志与错误提示信息
- 简化 import 语句,使用通配符导入 DTO 包
- 增强 API 请求重试机制中的 entity 构建一致性
This commit is contained in:
2025-12-05 14:34:35 +08:00
parent d08a60094b
commit 6a72c8a623
3 changed files with 37 additions and 32 deletions

View File

@@ -18,13 +18,13 @@ public class PowerEnvCampusParamsDTO {
* 每页数量 * 每页数量
*/ */
@Schema(description = "每页数量") @Schema(description = "每页数量")
private String pageSize; private String pageSize = "1000";
/** /**
* 页码 * 页码
*/ */
@Schema(description = "页码") @Schema(description = "页码")
private String page; private String page = "1";
/** /**
* 关键字 * 关键字

View File

@@ -8,10 +8,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity; import org.springframework.http.*;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@@ -86,17 +83,20 @@ public class RetryableHttpClient {
} }
// 构建带access_token参数的URL // 构建带access_token参数的URL
String url = baseUrl + API_URL + "?access_token=" + accessToken; String url = baseUrl + API_URL + "?access_token=" + accessToken;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<PowerEnvRequestParamsDTO<?>> requestEntity = new HttpEntity<>(requestParams, headers);
try { try {
// 请求数据 // 请求数据
ResponseEntity<PowerEnvResponseDataDTO<?>> response = restTemplate ResponseEntity<PowerEnvResponseDataDTO<?>> response = restTemplate
.exchange(url, HttpMethod.POST, new HttpEntity<>(requestParams), .exchange(url, HttpMethod.POST, requestEntity,
new ParameterizedTypeReference<PowerEnvResponseDataDTO<?>>() { new ParameterizedTypeReference<PowerEnvResponseDataDTO<?>>() {
}); });
// 检查响应状态码 // 检查响应状态码
if (!Objects.equals(response.getStatusCode(), HttpStatus.OK)) { if (!Objects.equals(response.getStatusCode(), HttpStatus.OK)) {
// 如果不是200则抛出异常 // 如果不是200则抛出异常
throw new HttpClientErrorException(response.getStatusCode(), "API请求失败"); throw new HttpClientErrorException(response.getStatusCode(), "API request failed");
} }
// 如果请求返回200,则检查响应内容 // 如果请求返回200,则检查响应内容
@@ -110,7 +110,7 @@ public class RetryableHttpClient {
// 获得重试结果 // 获得重试结果
ResponseEntity<PowerEnvResponseDataDTO<?>> retryResponse = ResponseEntity<PowerEnvResponseDataDTO<?>> retryResponse =
restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(requestParams), restTemplate.exchange(url, HttpMethod.POST, requestEntity,
new ParameterizedTypeReference<PowerEnvResponseDataDTO<?>>() { new ParameterizedTypeReference<PowerEnvResponseDataDTO<?>>() {
}); });
if (Objects.equals(retryResponse.getStatusCode(), HttpStatus.OK) && if (Objects.equals(retryResponse.getStatusCode(), HttpStatus.OK) &&
@@ -130,7 +130,7 @@ public class RetryableHttpClient {
return response; return response;
} catch (Exception e) { } catch (Exception e) {
// 如果发生异常,则在日志中记录异常,并且抛出 // 如果发生异常,则在日志中记录异常,并且抛出
log.error("请求API时发生异常", e); log.error("Exception occurred while requesting API", e);
throw e; throw e;
} }
} }
@@ -146,10 +146,10 @@ public class RetryableHttpClient {
return; return;
} }
log.info("开始刷新访问令牌"); log.info("Starting to refresh access token");
// 构造获取令牌的参数 // 构造获取令牌的参数
String tokenUrl = baseUrl + ACCESS_TOKEN_URL + "?appKey=" + appKey + "&" + appSecret; String tokenUrl = baseUrl + ACCESS_TOKEN_URL + "?appKey=" + appKey + "&appSecret=" + appSecret;
try { try {
// 请求访问令牌 // 请求访问令牌
@@ -170,18 +170,18 @@ public class RetryableHttpClient {
// 设置过期时间提前5分钟过期以确保安全 // 设置过期时间提前5分钟过期以确保安全
tokenExpireTime = System.currentTimeMillis() + (expiresIn - 300) * 1000L; tokenExpireTime = System.currentTimeMillis() + (expiresIn - 300) * 1000L;
log.info("成功刷新访问令牌,新令牌将在 {} 过期", new java.util.Date(tokenExpireTime)); log.info("Successfully refreshed access token, new token will expire at {}", new java.util.Date(tokenExpireTime));
} else { } else {
log.error("获取访问令牌失败: {}", responseBody); log.error("Failed to get access token: {}", responseBody);
throw new RuntimeException("无法获取访问令牌: " + responseBody.get("msg")); throw new RuntimeException("Unable to get access token: " + responseBody.get("msg"));
} }
} else { } else {
log.error("获取访问令牌失败HTTP状态码: {}", response.getStatusCode()); log.error("Failed to get access token, HTTP status code: {}", response.getStatusCode());
throw new RuntimeException("无法获取访问令牌HTTP状态码: " + response.getStatusCode()); throw new RuntimeException("Unable to get access token, HTTP status code: " + response.getStatusCode());
} }
} catch (Exception e) { } catch (Exception e) {
log.error("刷新访问令牌时发生异常", e); log.error("Exception occurred while refreshing access token", e);
throw new RuntimeException("刷新访问令牌失败", e); throw new RuntimeException("Failed to refresh access token", e);
} }
} finally { } finally {
tokenLock.unlock(); tokenLock.unlock();

View File

@@ -1,9 +1,7 @@
package com.jeelowcode.module.biz.job; package com.jeelowcode.module.biz.job;
import com.jeelowcode.module.biz.convert.LcBuildingEntityConvert; import com.jeelowcode.module.biz.convert.LcBuildingEntityConvert;
import com.jeelowcode.module.biz.dto.PowerEnvBuildingItemDTO; import com.jeelowcode.module.biz.dto.*;
import com.jeelowcode.module.biz.dto.PowerEnvBuildingParamsDTO;
import com.jeelowcode.module.biz.dto.PowerEnvPageDataDTO;
import com.jeelowcode.module.biz.entity.LcBuildingEntity; import com.jeelowcode.module.biz.entity.LcBuildingEntity;
import com.jeelowcode.module.biz.service.IBizHttpClientService; import com.jeelowcode.module.biz.service.IBizHttpClientService;
import com.jeelowcode.module.biz.service.ILcBuildingService; import com.jeelowcode.module.biz.service.ILcBuildingService;
@@ -41,16 +39,23 @@ public class AlibabaBuildingJob implements JobHandler {
@Override @Override
@TenantJob @TenantJob
public String execute(String param) throws Exception { public String execute(String param) throws Exception {
// 分页接口但是pageSize默认设置1000应该不会超过1000所以这里就不分页了 PowerEnvPageDataDTO<PowerEnvCampusItemDTO> campusPageData =
PowerEnvPageDataDTO<PowerEnvBuildingItemDTO> pageData = httpClientService.listCampus(new PowerEnvCampusParamsDTO());
httpClientService.listBuilding(new PowerEnvBuildingParamsDTO()); List<PowerEnvCampusItemDTO> campusList = campusPageData.getItems();
// 转化数据 if (campusList == null || campusList.isEmpty()) {
List<LcBuildingEntity> list = LcBuildingEntityConvert.INSTANCE.convertList(pageData.getItems()); log.info("没有查询到任何数据");
// 批量保存数据 return "没有查询到任何数据";
int result = buildingService.saveBatch(list); }
log.info("保存楼宇数据结果:{}", result); campusList.parallelStream().forEach(campus -> {
log.info("保存楼宇数据结果:{}", result == list.size()); PowerEnvPageDataDTO<PowerEnvBuildingItemDTO> pageData =
return "保存楼宇数据结果:" + result + ",楼宇数据大小:" + list.size(); httpClientService.listBuilding(new PowerEnvBuildingParamsDTO().setCampusId(campus.getCampusId()));
// 转化数据
List<LcBuildingEntity> list = LcBuildingEntityConvert.INSTANCE.convertList(pageData.getItems());
// 批量保存数据
int result = buildingService.saveBatch(list);
log.info("保存数据成功,数量为:{}", result == list.size());
});
return "保存数据成功";
} }
} }