mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-19 18:45:03 +08:00
update 充电桩数据同步到JCPP
This commit is contained in:
111
doc/充电桩数据同步.md
Normal file
111
doc/充电桩数据同步.md
Normal file
@@ -0,0 +1,111 @@
|
||||
充电桩数据首先是在web项目生成的,现在需要把web项目生成的充电桩数据同步到JCPP项目中,用于登录鉴权等操作
|
||||
|
||||
下面是web项目中充电桩相关表结构(注意使用的是mysql 5.7)
|
||||
|
||||
~~~mysql
|
||||
CREATE TABLE `pile_basic_info` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`name` varchar(32) DEFAULT NULL COMMENT '别名',
|
||||
`sn` varchar(20) DEFAULT NULL COMMENT '桩号',
|
||||
`business_type` char(5) DEFAULT NULL COMMENT '经营类型(1-运营桩;2-个人桩)',
|
||||
`secret_key` varchar(10) DEFAULT NULL COMMENT '个人桩密钥',
|
||||
`software_protocol` varchar(20) DEFAULT NULL COMMENT '软件协议(yunkuaichongV150--云快充V1.5;yunkuaichongV160--云快充V1.6;yonglianV1--永联;youdianV1--友电)',
|
||||
`production_date` datetime DEFAULT NULL COMMENT '生产日期',
|
||||
`licence_id` int(11) DEFAULT NULL COMMENT '证书编号',
|
||||
`model_id` int(11) DEFAULT NULL COMMENT '充电桩型号',
|
||||
`sim_id` int(11) DEFAULT NULL COMMENT 'sim卡id',
|
||||
`iccid` varchar(50) DEFAULT NULL COMMENT 'sim卡iccid',
|
||||
`merchant_id` int(11) DEFAULT NULL COMMENT '运营商id',
|
||||
`station_id` int(11) DEFAULT NULL COMMENT '充电站id',
|
||||
`longitude` varchar(30) DEFAULT NULL COMMENT '经度',
|
||||
`latitude` varchar(30) DEFAULT NULL COMMENT '纬度',
|
||||
`vin_flag` char(5) DEFAULT NULL COMMENT '是否支持汽车VIN码识别',
|
||||
`fault_reason` varchar(255) DEFAULT NULL COMMENT '故障原因',
|
||||
`create_by` varchar(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(20) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` char(5) DEFAULT '0' COMMENT '删除标识(0-正常;1-删除)',
|
||||
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_sn` (`sn`) USING BTREE,
|
||||
KEY `idx_station_id` (`station_id`) USING BTREE,
|
||||
KEY `idx_iccid` (`iccid`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=6845 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='充电桩基本信息表';
|
||||
|
||||
CREATE TABLE `pile_connector_info` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`name` varchar(20) DEFAULT NULL COMMENT '名称',
|
||||
`pile_sn` varchar(20) DEFAULT NULL COMMENT '所属充电桩sn',
|
||||
`pile_connector_code` varchar(20) DEFAULT NULL COMMENT '充电枪编号,由充电桩SN+01生成',
|
||||
`status` varchar(5) DEFAULT '0' COMMENT '状态 0:离网 (默认);1:空闲;2:占用(未充电);3:占用(充电中);4:占用(预约锁定) ;255:故障 ',
|
||||
`park_no` varchar(5) DEFAULT NULL COMMENT '车位号(推送联联平台所用字段)',
|
||||
`create_by` varchar(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(20) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标识(0-正常;1-删除)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_pile_sn` (`pile_sn`) USING BTREE,
|
||||
KEY `idx_code` (`pile_connector_code`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=30061 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='充电桩枪口信息表';
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
下面是JCPP项目充电桩相关表结构(注意使用的是postgreSQL 17)
|
||||
|
||||
~~~
|
||||
CREATE TABLE "public"."t_pile" (
|
||||
"id" uuid NOT NULL,
|
||||
"created_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_time" timestamp(6),
|
||||
"additional_info" jsonb,
|
||||
"pile_name" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"pile_code" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"protocol" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"station_id" uuid NOT NULL,
|
||||
"brand" varchar(255) COLLATE "pg_catalog"."default",
|
||||
"model" varchar(255) COLLATE "pg_catalog"."default",
|
||||
"manufacturer" varchar(255) COLLATE "pg_catalog"."default",
|
||||
"type" varchar(16) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"version" int4 DEFAULT 1,
|
||||
CONSTRAINT "pile_pkey" PRIMARY KEY ("id")
|
||||
)
|
||||
;
|
||||
|
||||
ALTER TABLE "public"."t_pile"
|
||||
OWNER TO "postgres";
|
||||
|
||||
CREATE UNIQUE INDEX "uni_pile_code" ON "public"."t_pile" USING btree (
|
||||
"pile_code" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
CREATE TABLE "public"."t_gun" (
|
||||
"id" uuid NOT NULL,
|
||||
"created_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_time" timestamp(6),
|
||||
"additional_info" varchar(255) COLLATE "pg_catalog"."default",
|
||||
"gun_no" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"gun_name" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"gun_code" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"station_id" uuid NOT NULL,
|
||||
"pile_id" uuid NOT NULL,
|
||||
"version" int4 DEFAULT 1,
|
||||
CONSTRAINT "t_gun_pkey" PRIMARY KEY ("id")
|
||||
)
|
||||
;
|
||||
|
||||
ALTER TABLE "public"."t_gun"
|
||||
OWNER TO "postgres";
|
||||
|
||||
CREATE UNIQUE INDEX "uni_gun_code" ON "public"."t_gun" USING btree (
|
||||
"gun_code" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "uni_gun_pile_gun_no" ON "public"."t_gun" USING btree (
|
||||
"pile_id" "pg_catalog"."uuid_ops" ASC NULLS LAST,
|
||||
"gun_no" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
|
||||
);
|
||||
~~~
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.jsowell.pile.jcpp.service;
|
||||
|
||||
/**
|
||||
* JCPP 认证服务接口
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
public interface IJcppAuthService {
|
||||
|
||||
/**
|
||||
* 获取 JCPP 访问令牌
|
||||
* 如果 Redis 中有缓存且未过期,直接返回
|
||||
* 否则调用登录接口获取新的 token
|
||||
*
|
||||
* @return 访问令牌
|
||||
*/
|
||||
String getAccessToken();
|
||||
|
||||
/**
|
||||
* 清除缓存的令牌(用于强制刷新)
|
||||
*/
|
||||
void clearToken();
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.jsowell.pile.jcpp.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.jsowell.pile.jcpp.service.IJcppAuthService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* JCPP 认证服务实现
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class JcppAuthServiceImpl implements IJcppAuthService {
|
||||
|
||||
private static final String JCPP_TOKEN_KEY = "jcpp:auth:token";
|
||||
private static final long TOKEN_EXPIRE_MINUTES = 30L;
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Value("${jcpp.sync.api-url:http://localhost:8180/api/sync}")
|
||||
private String jcppApiUrl;
|
||||
|
||||
@Value("${jcpp.auth.username:sanbing}")
|
||||
private String username;
|
||||
|
||||
@Value("${jcpp.auth.password:password123}")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 获取 JCPP 访问令牌
|
||||
*/
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
// 1. 尝试从 Redis 获取缓存的 token
|
||||
String cachedToken = stringRedisTemplate.opsForValue().get(JCPP_TOKEN_KEY);
|
||||
if (cachedToken != null && !cachedToken.isEmpty()) {
|
||||
log.debug("使用缓存的 JCPP token");
|
||||
return cachedToken;
|
||||
}
|
||||
|
||||
// 2. 缓存中没有,调用登录接口获取新的 token
|
||||
log.info("缓存中没有 token,调用登录接口获取");
|
||||
String token = login();
|
||||
|
||||
// 3. 将 token 缓存到 Redis,有效期 30 分钟
|
||||
if (token != null && !token.isEmpty()) {
|
||||
stringRedisTemplate.opsForValue().set(JCPP_TOKEN_KEY, token, TOKEN_EXPIRE_MINUTES, TimeUnit.MINUTES);
|
||||
log.info("JCPP token 已缓存,有效期 {} 分钟", TOKEN_EXPIRE_MINUTES);
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存的令牌
|
||||
*/
|
||||
@Override
|
||||
public void clearToken() {
|
||||
stringRedisTemplate.delete(JCPP_TOKEN_KEY);
|
||||
log.info("已清除缓存的 JCPP token");
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 JCPP 登录接口
|
||||
*/
|
||||
private String login() {
|
||||
// 构建登录 URL(从 api-url 中提取基础 URL)
|
||||
String baseUrl = jcppApiUrl.replace("/api/sync", "");
|
||||
String loginUrl = baseUrl + "/api/auth/login";
|
||||
|
||||
try {
|
||||
// 构建请求体
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("username", username);
|
||||
requestBody.put("password", password);
|
||||
|
||||
// 设置请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
|
||||
|
||||
log.info("调用 JCPP 登录接口: {}", loginUrl);
|
||||
|
||||
// 发送请求
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(loginUrl, entity, String.class);
|
||||
|
||||
if (response.getStatusCode() == HttpStatus.OK) {
|
||||
// 解析响应,提取 token
|
||||
JSONObject responseBody = JSON.parseObject(response.getBody());
|
||||
String token = responseBody.getString("token");
|
||||
|
||||
if (token != null && !token.isEmpty()) {
|
||||
log.info("JCPP 登录成功,获取到 token");
|
||||
return token;
|
||||
} else {
|
||||
log.error("JCPP 登录响应中没有 token: {}", response.getBody());
|
||||
throw new RuntimeException("登录响应中没有 token");
|
||||
}
|
||||
} else {
|
||||
log.error("JCPP 登录失败,状态码: ", response.getStatusCode());
|
||||
throw new RuntimeException("登录失败,状态码: " + response.getStatusCode());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("调用 JCPP 登录接口异常", e);
|
||||
throw new RuntimeException("登录失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user