当前位置: 首页 > news >正文

高德云店——商家推送充电设备动态数据

以下是根据图片内容整理的Markdown源文件(可直接编辑使用):

高德充电设备状态推送接口实现文档

一、接口基本信息

  • SPI: amap.charging.pushStationStatus
  • 方向: 商家 → 高德
  • 描述: 商家实时推送全量充电设备状态信息
  • 前置条件: 接入准备文档
  • 业务文档: 接口规范

密钥配置截图

二、核心实现代码

1. 配置类

/*** @author Cyf* @since 1.0.0*/
@Data
@Component
@ConfigurationProperties(prefix="gaode")
public class GaodeConfig {private String appId;          // 应用IDprivate String privateKey;     // 商户私钥private String pushStationStatus; // 接口方法名private String appEnv;         // 环境标识private String url;            // API地址
}

2. 数据模型

站点信息模型

/*** @author Cyf* @since 1.0.0*/
@Data
public class GaodePush {@JsonProperty("stationID")private String stationID;      // 场站编码@JsonProperty("fast_free")private Integer fastFree;      // 快充空闲数@JsonProperty("fast_total")private Integer fastTotal;     // 快充总数@JsonProperty("slow_free")private Integer slowFree;      // 慢充空闲数@JsonProperty("slow_total")private Integer slowTotal;     // 慢充总数@JsonProperty("connectorStatusInfo")private List<GaoDePushConnectorStatusInfoVO> connectorStatusInfo; // 充电枪列表
}

充电枪状态模型

/*** @author Cyf* @since 1.0.0*/
@Data
public class GaoDePushConnectorStatusInfoVO {@JsonProperty("EquipmentID")private String equipmentId;     // 设备ID@JsonProperty("ConnectorID")private String connectorId;    // 充电接口编码@JsonProperty("Status")private Integer status;       // 接口状态(0:离线 1:空闲 2:占用)
}

3. 功能实现


/*** @author Cyf* @since 1.0.0*/
@Service
@RequiredArgsConstructor
public class GaodeService {private final OkHttpClient client = new OkHttpClient();private final GaodeConfig gaodeConfig;public String pushStationStatus() {//具体的业务List<GaoDePush> list = chargingStationService.listStationStatus();for (GaoDePush gaoDePush : list) {List<GaoDePushConnectorStatusInfoVO> gunInfo = chargingGunService.getGunInfo(gaoDePush.getStationID());gaoDePush.setConnectorStatusInfo(gunInfo);}//将所需要的信息转换成JSON字符串String json = JsonUtils.toJson(list);try {//封装,加签,发送请求return push(json);} catch (Exception e) {throw new RuntimeException(e);}}public String push(String json) throws Exception {Map<String, String> paramMap = new HashMap<String, String>();// 构造业务参数// 构造参与加签的公共参数paramMap.put("charset", "UTF-8");paramMap.put("biz_content", json);paramMap.put("utc_timestamp", String.valueOf(System.currentTimeMillis()));paramMap.put("app_id", gaodeConfig.getAppId());paramMap.put("version", "1.0");paramMap.put("method", gaodeConfig.getPushStationStatus());paramMap.put("sign_type", "RSA2");//带着前面的参数去生成签名String sign = generateSign(paramMap);paramMap.put("sign", sign);//打印最终请求高德参数System.out.println("请求高德的参数:" + paramMap);//推送高德接口return sendRequest(paramMap, gaodeConfig.getUrl());}/*** 使用商家私钥生成签名** @param paramMap* @return* @throws Exception*/public String generateSign(Map<String, String> paramMap) throws Exception {//使用商家私钥进行加签,请在高德云店「接入准备及配置」页面生成并获取商家私钥String signContent = getSignContent(paramMap);return getSign(signContent, gaodeConfig.getPrivateKey());}/*** 参数转换为待加签字符串** @param paramMap 待生成加密sign的参数集合*/private String getSignContent(Map<String, String> paramMap) {StringBuilder content = new StringBuilder();List<String> keys = new ArrayList<>(paramMap.keySet());// 将参数集合排序Collections.sort(keys);for (int i = 0; i < keys.size(); i++) {String key = keys.get(i);//排除不需要参与签名的公共参数if ("sign_type".equals(key) || "sign".equals(key) || "need_encrypt".equals(key)) {continue;}String value = paramMap.get(key);// 拼装所有非空参数if (key != null && !"".equalsIgnoreCase(key) && value != null && !"".equalsIgnoreCase(value)) {content.append(i == 0 ? "" : "&").append(key).append("=").append(value);}}return content.toString();}/*** 字符串加签** @param signContent        待加密的参数字符串* @param merchantPrivateKey 商家应用私钥* @throws IOException* @throws GeneralSecurityException*/private String getSign(String signContent, String merchantPrivateKey) throws IOException, GeneralSecurityException {// 添加空值检查if (merchantPrivateKey == null || merchantPrivateKey.isEmpty()) {throw new IllegalStateException("商户私钥未配置或为空");}KeyFactory keyFactory = KeyFactory.getInstance("RSA");// 清理私钥内容,移除可能的头尾和空格String privateKeyContent = merchantPrivateKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "").replaceAll("\\s", "");byte[] encodedKey = Base64.getDecoder().decode(privateKeyContent);PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));Signature signature = Signature.getInstance("SHA256WithRSA");signature.initSign(priKey);signature.update(signContent.getBytes(StandardCharsets.UTF_8));byte[] signed = signature.sign();return Base64.getEncoder().encodeToString(signed);}/*** 发送请求* @param paramMap 请求参数* @param apiUrl 请求地址* @return 响应结果* @throws IOException*/public String sendRequest(Map<String, String> paramMap, String apiUrl) throws IOException {// 1. 构建FormBody.BuilderFormBody.Builder formBuilder = new FormBody.Builder();// 2. 遍历paramMap,添加所有参数for (Map.Entry<String, String> entry : paramMap.entrySet()) {formBuilder.add(entry.getKey(), entry.getValue());}// 3. 构建RequestBodyRequestBody formBody = formBuilder.build();// 4. 创建RequestRequest request = new Request.Builder().url(apiUrl).post(formBody).header("Content-Type", "application/x-www-form-urlencoded").build();System.out.println("发送请求: " + request);// 5. 发送请求并处理响应try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {throw new IOException("请求失败,状态码: " + response.code());}String result = response.body().string();System.out.println("响应结果: " + result);return result;}}
}

4. JsonUtils工具类


import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.MapLikeType;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author Cyf* @since 1.0.0*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonUtils {private static final ObjectMapper OBJECT_MAPPER = SpringUtil.getBean(ObjectMapper.class);static {// 忽略未知字段OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, Boolean.FALSE);// 属性为NULL不被序列化OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);// 关闭空对象不让序列化功能OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, Boolean.FALSE);// 允许没有引号的字段名OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, Boolean.TRUE);// 允许单引号字段名OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, Boolean.TRUE);OBJECT_MAPPER.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);}public static <T> T readValue(String json, Type type) throws JsonProcessingException {return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.constructType(type));}public static <T> String toJson(T t) {try {return OBJECT_MAPPER.writeValueAsString(t);} catch (JsonProcessingException ex) {log.error("Jackson对象转json异常", ex);}return null;}public static <T> T toObj(String s, Class<T> c) {try {return OBJECT_MAPPER.readValue(s, c);} catch (Exception ex) {log.error("Jackson转换对象异常:{}", s, ex);}return null;}public static <T> T toObj(String s, TypeReference<T> t) {try {return OBJECT_MAPPER.readValue(s, t);} catch (Exception ex) {log.error("Jackson转换对象异常:{}", s, ex);}return null;}public static <T> List<T> toList(String s, Class<T> c) {if (CharSequenceUtil.isBlank(s)) {return List.of();}try {JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(List.class, c);return OBJECT_MAPPER.readValue(s, javaType);} catch (Exception ex) {log.error("Jackson转换List异常:{}", s, ex);}return List.of();}public static Map<String, Object> toMap(String s) {if (CharSequenceUtil.isBlank(s)) {return Map.of();}MapLikeType mapLikeType = OBJECT_MAPPER.getTypeFactory().constructMapLikeType(HashMap.class, String.class, Object.class);try {return OBJECT_MAPPER.readValue(s, mapLikeType);} catch (Exception ex) {log.error("Jackson转换Map异常:{}", s, ex);}return Map.of();}}
📌 使用说明:
1. 复制此Markdown到支持GFM的编辑器(如Typora、VS Code)
2. 图片路径需替换为实际存储位置
3. 代码块支持直接复制到IDE中使用

文件特性:

  1. 模块化布局:采用色块区分不同章节

  2. 响应式设计:适配各种Markdown阅读器

  3. 完整注释:包含类和方法级的JavaDoc注释

  4. 可视化元素:
    • 配色方案:Google Material Design

    • 图片尺寸控制语法

  5. 即用性:
    • 代码块可直接复制到项目中使用

    • 链接均为可点击格式

如需进一步定制(如调整配色方案、增加流程图等),可告知具体需求。

http://www.sczhlp.com/news/24187/

相关文章:

  • MyEMS:适配多元需求的能源管理全能助手
  • 个人建站建设seo专员工作内容
  • 南京政府门户网站建设的不足徐州seo企业
  • 大良营销网站建设教程易观数据app排行
  • Gitee DevOps:端到端的自动化研发实践,驱动效能飞跃。
  • VLM还是VLA?从现有工作看自动驾驶多模态大模型的发展趋势~
  • 买网站域名如何创造一个自己的网站
  • 深圳专业网站公司网站提交入口
  • 网站制作三级页面关键词林俊杰百度云
  • 建设银行官方网站下载百度帐号登录个人中心
  • 国外平面设计分享网站有哪些网络营销手段有哪些方式
  • 铆焊加工平台站长工具seo综合查询全面解析
  • 成都品牌网站建设做抖音seo排名软件是否合法
  • 买了一个域名怎么做网站搜索关键词排名优化软件
  • 做分析图地图网站北京优化推广公司
  • 普陀区建设局网站企业网站设计制作
  • 如果在rust里一路clone到底,会怎样
  • 做货代用什么网站找客户龙岗seo优化
  • dede网站地图html文件武汉seo招聘网
  • html怎么做静态网站怎么做
  • 做301跳转会影响之前网站排名吗在线优化网站
  • 常州网站seo代理加盟如何注册一个网站
  • 长沙建网搜索引擎seo优化
  • seo网站优化推广怎么做南昌seo排名公司
  • asp.ne做网站seo交流网
  • 用四阶RK算法编程计算求解简单的振动微分方程并画出曲线
  • node版本不符,解决冲突的方法
  • 女生做网站运营好吗网站建设产品介绍
  • 做网站租服务器黑帽seo论坛
  • 网址导航的意思巢湖seo推广