WaterElectricComponent.java 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package com.chuanghai.ihotel.component;
  2. import com.chuanghai.ihotel.common.exception.BizCodeEnume;
  3. import com.chuanghai.ihotel.common.exception.RRException;
  4. import com.chuanghai.ihotel.config.WaterElectricConfig;
  5. import com.chuanghai.ihotel.constant.RedisKey;
  6. import com.chuanghai.ihotel.util.WaterElectricDataEncAndDecUtil;
  7. import com.chuanghai.ihotel.util.WaterElectricSignUtil;
  8. import com.fasterxml.jackson.databind.JsonNode;
  9. import com.fasterxml.jackson.databind.ObjectMapper;
  10. import lombok.extern.slf4j.Slf4j;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.data.redis.core.StringRedisTemplate;
  13. import org.springframework.http.HttpEntity;
  14. import org.springframework.http.HttpHeaders;
  15. import org.springframework.http.ResponseEntity;
  16. import org.springframework.stereotype.Component;
  17. import org.springframework.util.LinkedMultiValueMap;
  18. import org.springframework.util.MultiValueMap;
  19. import org.springframework.util.StringUtils;
  20. import org.springframework.web.client.RestTemplate;
  21. import java.time.LocalDateTime;
  22. import java.time.format.DateTimeFormatter;
  23. import java.util.HashMap;
  24. import java.util.Map;
  25. import java.util.concurrent.TimeUnit;
  26. /**
  27. * 水电服务
  28. */
  29. @Slf4j
  30. @Component
  31. public class WaterElectricComponent {
  32. private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
  33. @Autowired
  34. private StringRedisTemplate stringRedisTemplate;
  35. @Autowired
  36. private WaterElectricConfig waterElectricConfig;
  37. /**
  38. * 获取token
  39. * @return
  40. */
  41. public String queryToken() {
  42. String token = stringRedisTemplate.opsForValue().get(RedisKey.WATER_AND_ELECTRIC_SERVICE_TOKEN);
  43. if (StringUtils.hasText(token)) {
  44. return token;
  45. } else {
  46. Map<String, String> map = new HashMap<>();
  47. map.put("operatorSecret", waterElectricConfig.getOperatorSecret());
  48. try {
  49. JsonNode jsonNode = queryData("queryToken", map, null);
  50. String accessToken = jsonNode.get("accessToken").asText();
  51. long ttl = jsonNode.get("tokenAvailableTime").asLong();
  52. stringRedisTemplate.opsForValue().set(RedisKey.WATER_AND_ELECTRIC_SERVICE_TOKEN, accessToken, ttl, TimeUnit.SECONDS);
  53. return accessToken;
  54. } catch (Exception e) {
  55. throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取token异常");
  56. }
  57. }
  58. }
  59. /**
  60. * 获取电表实时数据
  61. * @param pointId
  62. * @return
  63. */
  64. public String queryPowerRealTimeData(String pointId) {
  65. Map<String, String> map = new HashMap<>();
  66. map.put("pointId", pointId);
  67. try {
  68. JsonNode jsonNode = queryData("queryPowerRealTimeData", map, queryToken());
  69. // {"bm": 1822.1, "dataTime": "", "frequency": "", "pointId": "", "status": 0}
  70. log.info("读取电表数据【{}】", jsonNode.toString());
  71. return jsonNode.get("bm").asText();
  72. } catch (Exception e) {
  73. throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取电表实时数据异常");
  74. }
  75. }
  76. /**
  77. * 获取电表实时数据
  78. * @param pointId
  79. * @return
  80. */
  81. public String queryLastHistoryCumulantInfo(String pointId) {
  82. Map<String, String> map = new HashMap<>();
  83. map.put("pointId", pointId);
  84. map.put("pointType", "2");
  85. try {
  86. JsonNode jsonNode = queryData("queryLastHistoryCumulantInfo", map, queryToken());
  87. log.info("读取水表数据【{}】", jsonNode.toString());
  88. return jsonNode.get("bm").asText();
  89. } catch (Exception e) {
  90. throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取电表实时数据异常");
  91. }
  92. }
  93. /**
  94. * 远程控制水电表
  95. * @param pointId
  96. * @param operType 1开、2关
  97. * @return
  98. */
  99. public JsonNode remoteDisconnect(String pointId, String operType) {
  100. Map<String, String> map = new HashMap<>();
  101. map.put("pointId", pointId);
  102. map.put("operType", operType);
  103. try {
  104. return queryData("remoteDisconnect", map, queryToken());
  105. } catch (Exception e) {
  106. throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-远程控制水电表异常");
  107. }
  108. }
  109. /**
  110. * 请求数据
  111. *
  112. * @param uri 请求接口url
  113. * @param paramMap 请求参数
  114. * @param token 请求token 获取token时该字段可以为空
  115. */
  116. private JsonNode queryData(String uri, Map<String, String> paramMap, String token) throws Exception {
  117. ObjectMapper mapper = new ObjectMapper();
  118. // 加密data部分
  119. String encode = WaterElectricDataEncAndDecUtil.dataEncode(mapper.writeValueAsString(paramMap), waterElectricConfig.getDataSecret(), waterElectricConfig.getDataSecretIv());
  120. String seq = "0001";
  121. String timeStamp = DTF.format(LocalDateTime.now());
  122. MultiValueMap<String, String> requestMap = new LinkedMultiValueMap<>();
  123. requestMap.add("operatorId", waterElectricConfig.getOperatorId());
  124. requestMap.add("data", encode);
  125. requestMap.add("timeStamp", timeStamp);
  126. requestMap.add("seq", seq);
  127. // 为防止 + 在收发过程中被变成空格,将加密后的密文中的所有空格替换一下,需要签名的参数: operatorId + 加密后的data + 时间戳 + 自增序列
  128. String signSrc = waterElectricConfig.getOperatorId() + encode.replaceAll(" ", "+") + timeStamp + seq;
  129. String sig = WaterElectricSignUtil.sign(signSrc, waterElectricConfig.getSignKey());
  130. requestMap.add("sig", sig);
  131. RestTemplate restTemplate = new RestTemplate();
  132. HttpHeaders headers = new HttpHeaders();
  133. if (StringUtils.hasText(token)) {
  134. headers.add("token", token);
  135. }
  136. HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(requestMap, headers);
  137. log.info("=======开始请求数据=======");
  138. ResponseEntity<String> responseEntity = restTemplate.postForEntity(waterElectricConfig.getServiceHost() + uri, formEntity, String.class);
  139. log.info("=======请求成功===========");
  140. String body = responseEntity.getBody();
  141. JsonNode jsonNode = mapper.readTree(body);
  142. if (!"0".equals(jsonNode.get("ret").asText())) {
  143. log.error("接口请求失败,【{}】", body);
  144. }
  145. // 验签
  146. String dataS = jsonNode.get("data").asText().replaceAll(" ", "+");
  147. String resultSigStr = jsonNode.get("operatorId").asText()
  148. + dataS
  149. + jsonNode.get("msg").asText()
  150. + jsonNode.get("ret").asText();
  151. // 本地签名
  152. String localSign = WaterElectricSignUtil.sign(resultSigStr, waterElectricConfig.getSignKey());
  153. String remoteSign = jsonNode.get("sig").asText();
  154. if (!(StringUtils.hasText(remoteSign) && remoteSign.equals(localSign))) {
  155. log.error("接口验签失败,本地签名【{}】,远程签名【{}】", localSign, remoteSign);
  156. }
  157. String data = WaterElectricDataEncAndDecUtil.dataDecode(dataS, waterElectricConfig.getDataSecret(), waterElectricConfig.getDataSecretIv());
  158. if (!StringUtils.hasText(data)) {
  159. log.error("水电服务接口data解密失败");
  160. }
  161. JsonNode dataJson = mapper.readTree(data);
  162. return dataJson;
  163. }
  164. }