diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvBuildingDataDTO.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvBuildingDataDTO.java deleted file mode 100644 index dd92d95..0000000 --- a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvBuildingDataDTO.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.jeelowcode.module.biz.dto; - -// todo 待完善 -public class PowerEnvBuildingDataDTO { - - -} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvBuildingItemDTO.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvBuildingItemDTO.java new file mode 100644 index 0000000..2ec6c1a --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvBuildingItemDTO.java @@ -0,0 +1,47 @@ +package com.jeelowcode.module.biz.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 动环系统建筑数据 + * + * @author yangchenjj + */ +@Data +@Accessors(chain = true) +@Schema(description = "动环系统建筑数据") +public class PowerEnvBuildingItemDTO { + + /** + * 建筑ID + */ + @Schema(description = "建筑ID") + private String buildingId; + + /** + * 建筑名称 + */ + @Schema(description = "建筑名称") + private String buildingName; + + /** + * 园区ID + */ + @Schema(description = "园区ID") + private String campusId; + + /** + * 园区名称 + */ + @Schema(description = "园区名称") + private String campusName; + + /** + * 状态(0:停用,1:启用) + */ + @Schema(description = "状态(0:停用,1:启用)") + private Integer status; + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvCampusDataDTO.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvCampusDataDTO.java deleted file mode 100644 index a7ec56a..0000000 --- a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvCampusDataDTO.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.jeelowcode.module.biz.dto; - -import lombok.Data; - -// todo 待完善 -@Data -public class PowerEnvCampusDataDTO { - -} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvCampusItemDTO.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvCampusItemDTO.java new file mode 100644 index 0000000..69c2ae7 --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvCampusItemDTO.java @@ -0,0 +1,35 @@ +package com.jeelowcode.module.biz.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 动环系统园区信息 + * + * @author yangchenjj + */ +@Data +@Accessors(chain = true) +@Schema(description = "动环系统园区信息") +public class PowerEnvCampusItemDTO { + + /** + * 园区编号 + */ + @Schema(description = "园区编号") + private String campusId; + + /** + * 园区名称 + */ + @Schema(description = "园区名称") + private String campusName; + + /** + * 状态(0:停用,1:启用) + */ + @Schema(description = "状态(0:停用,1:启用)") + private Integer status; + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvPageDataDTO.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvPageDataDTO.java new file mode 100644 index 0000000..cdf1741 --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/dto/PowerEnvPageDataDTO.java @@ -0,0 +1,49 @@ +package com.jeelowcode.module.biz.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 动环系统园区数据DTO + * + * @author yangchenjj + */ +@Data +@Accessors(chain = true) +@Schema(description = "动环系统园区数据DTO") +public class PowerEnvPageDataDTO { + + /** + * 总页数 + */ + @Schema(description = "总页数") + private Integer totalPage = 0; + + /** + * 每页数量 + */ + @Schema(description = "每页数量") + private Integer pageSize = 0; + + /** + * 当前页码 + */ + @Schema(description = "当前页码") + private Integer currentPage = 0; + + /** + * 总记录数 + */ + @Schema(description = "总记录数") + private Integer totalCount = 0; + + /** + * 数据项 + */ + @Schema(description = "数据项") + private List items; + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/http/RetryableHttpClient.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/http/RetryableHttpClient.java index 5158b48..f57eb29 100644 --- a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/http/RetryableHttpClient.java +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/http/RetryableHttpClient.java @@ -1,6 +1,7 @@ package com.jeelowcode.module.biz.http; import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; import com.jeelowcode.module.biz.dto.PowerEnvRequestParamsDTO; import com.jeelowcode.module.biz.dto.PowerEnvResponseDataDTO; import lombok.extern.slf4j.Slf4j; @@ -9,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpClientErrorException; @@ -17,23 +19,35 @@ import org.springframework.web.client.RestTemplate; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.Map; +import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; /** * 可重试的HttpClient,支持自动登录和token刷新 * 线程安全的实现,可以在并发环境下使用 + * + * @author yangchenjj */ @Slf4j @Component @ConditionalOnProperty(name = "jeelowcode.powerenv.baseurl") public class RetryableHttpClient { + /** + * 动环系统基础URL + */ @Value("${jeelowcode.powerenv.baseurl}") private String baseUrl; + /** + * 动环系统应用Key + */ @Value("${jeelowcode.powerenv.appKey:campusT0Yoh1U6tXD3ZVXy}") private String appKey; + /** + * 动环系统应用密钥 + */ @Value("${jeelowcode.powerenv.appSecret:3d4d89b5-8a14-4b83-a9aa-715bdc8264a1}") private String appSecret; @@ -62,12 +76,10 @@ public class RetryableHttpClient { /** * 发送GET请求并获取响应数据 * - * @param apiPath API接口路径 * @param requestParams 请求参数 * @return 响应数据 */ - public ResponseEntity> getData( - String apiPath, PowerEnvRequestParamsDTO requestParams) { + public ResponseEntity> getData(PowerEnvRequestParamsDTO requestParams) { // 检查令牌是否过期,如果过期则刷新 if (isTokenExpired()) { refreshAccessToken(); @@ -75,18 +87,49 @@ public class RetryableHttpClient { // 构建带access_token参数的URL String url = baseUrl + API_URL + "?access_token=" + accessToken; try { - return restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(requestParams), - new ParameterizedTypeReference>() { - }); - } catch (HttpClientErrorException.Unauthorized e) { - log.warn("API请求未授权,尝试刷新访问令牌后重试"); - // 如果是401未授权错误,则刷新令牌后重试 - refreshAccessToken(); - url = baseUrl + API_URL + "?access_token=" + accessToken; - return restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(requestParams), - new ParameterizedTypeReference>() { - }); + // 请求数据 + ResponseEntity> response = restTemplate + .exchange(url, HttpMethod.POST, new HttpEntity<>(requestParams), + new ParameterizedTypeReference>() { + }); + + // 检查响应状态码 + if (!Objects.equals(response.getStatusCode(), HttpStatus.OK)) { + // 如果不是200,则抛出异常 + throw new HttpClientErrorException(response.getStatusCode(), "API请求失败"); + } + + // 如果请求返回200,则检查响应内容 + PowerEnvResponseDataDTO responseData = response.getBody(); + if (!Objects.requireNonNull(responseData).getSuccess()) { + // 如果响应消息为false,则还需要进一步查看错误信息 + if (StrUtil.equalsAny(responseData.getCode(), "OPEN_API_PARAM_ERROR", "ACCESS_TOKEN_ERROR")) { + // 需要刷新Token并且重试 + refreshAccessToken(); + url = baseUrl + API_URL + "?access_token=" + accessToken; + + // 获得重试结果 + ResponseEntity> retryResponse = + restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(requestParams), + new ParameterizedTypeReference>() { + }); + if (Objects.equals(retryResponse.getStatusCode(), HttpStatus.OK) && + Objects.requireNonNull(retryResponse.getBody()).getSuccess()) { + // 只放请求成功的结果 + return retryResponse; + } else { + // 重试如果除了任何异常,则抛出异常 + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, responseData.getMsg()); + } + } else { + // 直接抛出异常 + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, responseData.getMsg()); + } + } + // 如果成功了,则直接返回响应数据 + return response; } catch (Exception e) { + // 如果发生异常,则在日志中记录异常,并且抛出 log.error("请求API时发生异常", e); throw e; } diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IBizHttpClientService.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IBizHttpClientService.java index d7b44ba..7b44d86 100644 --- a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IBizHttpClientService.java +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IBizHttpClientService.java @@ -1,11 +1,36 @@ package com.jeelowcode.module.biz.service; +import com.jeelowcode.module.biz.dto.*; + /** - * 业务HTTP客户端服务接口 + * 动环系统客户端服务接口 * - * @author lingma + * @author yangchenjj */ public interface IBizHttpClientService { + /** + * 获取园区列表 + * + * @param params 园区查询参数 + * @return 园区数据列表 + */ + PowerEnvPageDataDTO listCampus(PowerEnvCampusParamsDTO params); -} \ No newline at end of file + /** + * 获取建筑列表 + * + * @param params 建筑查询参数 + * @return 建筑数据列表 + */ + PowerEnvPageDataDTO listBuilding(PowerEnvBuildingParamsDTO params); + + /** + * 获取设备指标数据列表 + * + * @param deviceId 设备ID + * @return 设备指标数据列表 + */ + PowerEnvDeviceDataDTO listDeviceMetrics(String deviceId); + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/BizHttpClientServiceImpl.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/BizHttpClientServiceImpl.java index 3e2a9c1..990a267 100644 --- a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/BizHttpClientServiceImpl.java +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/BizHttpClientServiceImpl.java @@ -1,11 +1,17 @@ package com.jeelowcode.module.biz.service.impl; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.TypeReference; +import com.jeelowcode.module.biz.dto.*; import com.jeelowcode.module.biz.http.RetryableHttpClient; import com.jeelowcode.module.biz.service.IBizHttpClientService; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.Collections; +import java.util.Optional; /** * 业务HTTP客户端服务实现类 @@ -19,4 +25,58 @@ public class BizHttpClientServiceImpl implements IBizHttpClientService { @Resource private RetryableHttpClient retryableHttpClient; -} \ No newline at end of file + /** + * 获取园区分页数据 + * + * @param params 园区查询参数 + * @return 园区分页数据 + */ + @Override + public PowerEnvPageDataDTO listCampus(PowerEnvCampusParamsDTO params) { + PowerEnvResponseDataDTO response = retryableHttpClient.getData( + PowerEnvRequestParamsDTO.buildCampusRequestParams(params)).getBody(); + return Optional.ofNullable(response) + .map(PowerEnvResponseDataDTO::getContent) + .map(content -> Convert.convert( + new TypeReference>() { + }, content)) + .orElse(new PowerEnvPageDataDTO().setItems(Collections.emptyList())); + } + + + /** + * 获取建筑分页数据 + * + * @param params 建筑查询参数 + * @return 建筑分页数据 + */ + @Override + public PowerEnvPageDataDTO listBuilding(PowerEnvBuildingParamsDTO params) { + PowerEnvResponseDataDTO response = retryableHttpClient.getData( + PowerEnvRequestParamsDTO.buildBuildingRequestParams(params)).getBody(); + return Optional.ofNullable(response) + .map(PowerEnvResponseDataDTO::getContent) + .map(content -> Convert.convert( + new TypeReference>() { + }, content)) + .orElse(new PowerEnvPageDataDTO().setItems(Collections.emptyList())); + } + + + /** + * 获取设备指标数据 + * + * @param deviceId 设备ID + * @return 设备指标数据 + */ + @Override + public PowerEnvDeviceDataDTO listDeviceMetrics(String deviceId) { + PowerEnvResponseDataDTO response = retryableHttpClient.getData( + PowerEnvRequestParamsDTO.buildDeviceRunDataRequestParams(deviceId)).getBody(); + return Optional.ofNullable(response) + .map(PowerEnvResponseDataDTO::getContent) + .map(content -> BeanUtil.toBean(content, PowerEnvDeviceDataDTO.class)) + .orElse(new PowerEnvDeviceDataDTO().setDeviceUid(deviceId).setPropertyRunDataList(Collections.emptyList())); + } + +}