package com.chuanghai.ihotel.component; import com.chuanghai.ihotel.common.exception.BizCodeEnume; import com.chuanghai.ihotel.common.exception.RRException; import com.chuanghai.ihotel.config.WaterElectricConfig; import com.chuanghai.ihotel.constant.RedisKey; import com.chuanghai.ihotel.util.WaterElectricDataEncAndDecUtil; import com.chuanghai.ihotel.util.WaterElectricSignUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * 水电服务 */ @Slf4j @Component public class WaterElectricComponent { private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private WaterElectricConfig waterElectricConfig; /** * 获取token * @return */ public String queryToken() { String token = stringRedisTemplate.opsForValue().get(RedisKey.WATER_AND_ELECTRIC_SERVICE_TOKEN); if (StringUtils.hasText(token)) { return token; } else { Map map = new HashMap<>(); map.put("operatorSecret", waterElectricConfig.getOperatorSecret()); try { JsonNode jsonNode = queryData("queryToken", map, null); String accessToken = jsonNode.get("accessToken").asText(); long ttl = jsonNode.get("tokenAvailableTime").asLong(); stringRedisTemplate.opsForValue().set(RedisKey.WATER_AND_ELECTRIC_SERVICE_TOKEN, accessToken, ttl, TimeUnit.SECONDS); return accessToken; } catch (Exception e) { throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取token异常"); } } } /** * 获取电表实时数据 * @param pointId * @return */ public String queryPowerRealTimeData(String pointId) { Map map = new HashMap<>(); map.put("pointId", pointId); try { JsonNode jsonNode = queryData("queryPowerRealTimeData", map, queryToken()); // {"bm": 1822.1, "dataTime": "", "frequency": "", "pointId": "", "status": 0} log.info("读取电表数据【{}】", jsonNode.toString()); return jsonNode.get("bm").asText(); } catch (Exception e) { throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取电表实时数据异常"); } } /** * 获取电表实时数据 * @param pointId * @return */ public String queryLastHistoryCumulantInfo(String pointId) { Map map = new HashMap<>(); map.put("pointId", pointId); map.put("pointType", "2"); try { JsonNode jsonNode = queryData("queryLastHistoryCumulantInfo", map, queryToken()); log.info("读取水表数据【{}】", jsonNode.toString()); return jsonNode.get("bm").asText(); } catch (Exception e) { throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取电表实时数据异常"); } } /** * 远程控制水电表 * @param pointId * @param operType 1开、2关 * @return */ public JsonNode remoteDisconnect(String pointId, String operType) { Map map = new HashMap<>(); map.put("pointId", pointId); map.put("operType", operType); try { return queryData("remoteDisconnect", map, queryToken()); } catch (Exception e) { throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-远程控制水电表异常"); } } /** * 请求数据 * * @param uri 请求接口url * @param paramMap 请求参数 * @param token 请求token 获取token时该字段可以为空 */ private JsonNode queryData(String uri, Map paramMap, String token) throws Exception { ObjectMapper mapper = new ObjectMapper(); // 加密data部分 String encode = WaterElectricDataEncAndDecUtil.dataEncode(mapper.writeValueAsString(paramMap), waterElectricConfig.getDataSecret(), waterElectricConfig.getDataSecretIv()); String seq = "0001"; String timeStamp = DTF.format(LocalDateTime.now()); MultiValueMap requestMap = new LinkedMultiValueMap<>(); requestMap.add("operatorId", waterElectricConfig.getOperatorId()); requestMap.add("data", encode); requestMap.add("timeStamp", timeStamp); requestMap.add("seq", seq); // 为防止 + 在收发过程中被变成空格,将加密后的密文中的所有空格替换一下,需要签名的参数: operatorId + 加密后的data + 时间戳 + 自增序列 String signSrc = waterElectricConfig.getOperatorId() + encode.replaceAll(" ", "+") + timeStamp + seq; String sig = WaterElectricSignUtil.sign(signSrc, waterElectricConfig.getSignKey()); requestMap.add("sig", sig); RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); if (StringUtils.hasText(token)) { headers.add("token", token); } HttpEntity> formEntity = new HttpEntity<>(requestMap, headers); log.info("=======开始请求数据======="); ResponseEntity responseEntity = restTemplate.postForEntity(waterElectricConfig.getServiceHost() + uri, formEntity, String.class); log.info("=======请求成功==========="); String body = responseEntity.getBody(); JsonNode jsonNode = mapper.readTree(body); if (!"0".equals(jsonNode.get("ret").asText())) { log.error("接口请求失败,【{}】", body); } // 验签 String dataS = jsonNode.get("data").asText().replaceAll(" ", "+"); String resultSigStr = jsonNode.get("operatorId").asText() + dataS + jsonNode.get("msg").asText() + jsonNode.get("ret").asText(); // 本地签名 String localSign = WaterElectricSignUtil.sign(resultSigStr, waterElectricConfig.getSignKey()); String remoteSign = jsonNode.get("sig").asText(); if (!(StringUtils.hasText(remoteSign) && remoteSign.equals(localSign))) { log.error("接口验签失败,本地签名【{}】,远程签名【{}】", localSign, remoteSign); } String data = WaterElectricDataEncAndDecUtil.dataDecode(dataS, waterElectricConfig.getDataSecret(), waterElectricConfig.getDataSecretIv()); if (!StringUtils.hasText(data)) { log.error("水电服务接口data解密失败"); } JsonNode dataJson = mapper.readTree(data); return dataJson; } }