update 充电桩数据同步到JCPP

This commit is contained in:
Guoqs
2026-01-05 13:41:12 +08:00
parent 62f455fe70
commit 30ec68abb1
3 changed files with 258 additions and 0 deletions

View 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.5yunkuaichongV160--云快充V1.6yonglianV1--永联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
);
~~~

View File

@@ -0,0 +1,23 @@
package com.jsowell.pile.jcpp.service;
/**
* JCPP 认证服务接口
*
* @author jsowell
*/
public interface IJcppAuthService {
/**
* 获取 JCPP 访问令牌
* 如果 Redis 中有缓存且未过期,直接返回
* 否则调用登录接口获取新的 token
*
* @return 访问令牌
*/
String getAccessToken();
/**
* 清除缓存的令牌(用于强制刷新)
*/
void clearToken();
}

View File

@@ -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);
}
}
}