同步充电桩数据

This commit is contained in:
Guoqs
2025-12-30 15:59:34 +08:00
parent 3f42441869
commit ee7a3425d0
38 changed files with 4663 additions and 131 deletions

View File

@@ -0,0 +1,129 @@
package com.jsowell.web.controller.jcpp;
import com.jsowell.common.annotation.Log;
import com.jsowell.common.core.controller.BaseController;
import com.jsowell.common.core.domain.AjaxResult;
import com.jsowell.common.core.page.TableDataInfo;
import com.jsowell.common.enums.BusinessType;
import com.jsowell.pile.domain.JcppSyncRecord;
import com.jsowell.pile.jcpp.dto.sync.JcppSyncResponse;
import com.jsowell.pile.jcpp.service.IJcppPileSyncService;
import com.jsowell.pile.mapper.JcppSyncRecordMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* JCPP 充电桩同步控制器
*
* @author jsowell
*/
@Slf4j
@Api(tags = "JCPP 充电桩同步")
@RestController
@RequestMapping("/jcpp/sync")
public class JcppPileSyncController extends BaseController {
@Autowired
private IJcppPileSyncService jcppPileSyncService;
@Autowired
private JcppSyncRecordMapper jcppSyncRecordMapper;
/**
* 全量同步充电桩数据
*/
@ApiOperation("全量同步充电桩数据")
@PreAuthorize("@ss.hasPermi('jcpp:sync:full')")
@Log(title = "JCPP 充电桩同步", businessType = BusinessType.OTHER)
@PostMapping("/full")
public AjaxResult syncFull() {
try {
log.info("开始执行全量同步");
JcppSyncResponse response = jcppPileSyncService.syncAllPiles();
return AjaxResult.success("全量同步完成", response);
} catch (Exception e) {
log.error("全量同步失败", e);
return AjaxResult.error("全量同步失败: " + e.getMessage());
}
}
/**
* 增量同步充电桩数据
*/
@ApiOperation("增量同步充电桩数据")
@PreAuthorize("@ss.hasPermi('jcpp:sync:incremental')")
@Log(title = "JCPP 充电桩同步", businessType = BusinessType.OTHER)
@PostMapping("/incremental")
public AjaxResult syncIncremental(
@ApiParam("上次同步时间可选格式yyyy-MM-dd HH:mm:ss")
@RequestParam(required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
Date lastSyncTime) {
try {
log.info("开始执行增量同步,上次同步时间: {}", lastSyncTime);
JcppSyncResponse response = jcppPileSyncService.syncIncrementalPiles(lastSyncTime);
return AjaxResult.success("增量同步完成", response);
} catch (Exception e) {
log.error("增量同步失败", e);
return AjaxResult.error("增量同步失败: " + e.getMessage());
}
}
/**
* 同步单个充电桩
*/
@ApiOperation("同步单个充电桩")
@PreAuthorize("@ss.hasPermi('jcpp:sync:single')")
@Log(title = "JCPP 充电桩同步", businessType = BusinessType.OTHER)
@PostMapping("/pile/{pileSn}")
public AjaxResult syncSinglePile(
@ApiParam("充电桩编号")
@PathVariable String pileSn) {
try {
log.info("开始同步单个充电桩: {}", pileSn);
boolean success = jcppPileSyncService.syncSinglePile(pileSn);
if (success) {
return AjaxResult.success("同步成功");
} else {
return AjaxResult.error("同步失败");
}
} catch (Exception e) {
log.error("同步单个充电桩失败: {}", pileSn, e);
return AjaxResult.error("同步失败: " + e.getMessage());
}
}
/**
* 查询同步记录列表
*/
@ApiOperation("查询同步记录列表")
@PreAuthorize("@ss.hasPermi('jcpp:sync:list')")
@GetMapping("/records")
public TableDataInfo getSyncRecords(JcppSyncRecord jcppSyncRecord) {
startPage();
List<JcppSyncRecord> list = jcppSyncRecordMapper.selectJcppSyncRecordList(jcppSyncRecord);
return getDataTable(list);
}
/**
* 查询同步记录详情
*/
@ApiOperation("查询同步记录详情")
@PreAuthorize("@ss.hasPermi('jcpp:sync:query')")
@GetMapping("/records/{id}")
public AjaxResult getSyncRecordDetail(
@ApiParam("同步记录ID")
@PathVariable Long id) {
JcppSyncRecord record = jcppSyncRecordMapper.selectJcppSyncRecordById(id);
return AjaxResult.success(record);
}
}

View File

@@ -3,12 +3,33 @@ jsowell:
# 文件路径 示例( Windows配置D:/jsowell/uploadPathLinux配置 /home/jsowell/uploadPath
profile: /www/wwwroot/jsowellftp
# JCPP 配置
jcpp:
rabbitmq:
# 分区数量(与 JCPP 保持一致)
partition-count: 10
# Exchange 名称
exchange: jcpp.uplink.exchange
# 队列前缀
queue-prefix: jcpp.uplink.partition
sync:
# JCPP 同步接口地址
api-url: http://localhost:8080/api/sync
# 批量同步大小
batch-size: 100
# 超时时间(毫秒)
timeout: 60000
# 是否启用自动增量同步
auto-sync-enabled: false
# 自动同步间隔(分钟)
auto-sync-interval: 30
# 数据源配置
spring:
# redis 配置
redis:
# 地址
host: 192.168.0.32
host: 106.14.94.149
# 端口默认为6379
port: 6379
# 数据库索引
@@ -35,11 +56,11 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://192.168.0.32:3306/jsowell_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: jsowell_dev
# url: jdbc:mysql://192.168.0.32:3306/jsowell_prd_copy?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://106.14.94.149:3306/jsowell_pre?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: jsowell_pre
# url: jdbc:mysql://106.14.94.149:3306/jsowell_prd_copy?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: jsowell_prd_copy
password: 123456
password: Js@160829
# 从库数据源
slave:
# 从数据源开关/默认关闭
@@ -89,7 +110,7 @@ spring:
# rabbitmq配置 sit
rabbitmq:
host: 192.168.0.32
host: 106.14.94.149
port: 5672
username: admin
password: admin
@@ -263,7 +284,7 @@ dubbo:
name: wcc-server
qosEnable: false
registry:
address: nacos://192.168.0.32:8848
address: nacos://106.14.94.149:8848
parameters:
namespace: e328faaf-8516-42d0-817a-7406232b3581
username: nacos

View File

@@ -8,7 +8,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import java.util.HashMap;
import java.util.Map;
@@ -52,7 +51,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("LOGIN")
.timestamp(System.currentTimeMillis())
.data(loginData)
.data(JSON.toJSONString(loginData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -77,7 +76,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("HEARTBEAT")
.timestamp(System.currentTimeMillis())
.data(heartbeatData)
.data(JSON.toJSONString(heartbeatData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -101,7 +100,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("QUERY_PRICING")
.timestamp(System.currentTimeMillis())
.data(queryData)
.data(JSON.toJSONString(queryData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -130,7 +129,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("START_CHARGE")
.timestamp(System.currentTimeMillis())
.data(startData)
.data(JSON.toJSONString(startData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -163,7 +162,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("REAL_TIME_DATA")
.timestamp(System.currentTimeMillis())
.data(realTimeData)
.data(JSON.toJSONString(realTimeData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -196,7 +195,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("TRANSACTION_RECORD")
.timestamp(System.currentTimeMillis())
.data(transactionData)
.data(JSON.toJSONString(transactionData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -224,7 +223,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("REMOTE_START_RESULT")
.timestamp(System.currentTimeMillis())
.data(resultData)
.data(JSON.toJSONString(resultData))
.build();
mockMvc.perform(post("/api/jcpp/uplink")
@@ -245,7 +244,7 @@ public class JcppMessageControllerTest {
.pileCode("TEST001")
.messageType("INVALID_TYPE")
.timestamp(System.currentTimeMillis())
.data(new HashMap<>())
.data(JSON.toJSONString(new HashMap<>()))
.build();
mockMvc.perform(post("/api/jcpp/uplink")

View File

@@ -1,5 +1,6 @@
package com.jsowell.jcpp;
import com.google.common.collect.Lists;
import com.jsowell.pile.jcpp.dto.JcppPricingModel;
import com.jsowell.pile.jcpp.util.PricingModelConverter;
import com.jsowell.pile.vo.web.BillingDetailVO;
@@ -25,17 +26,17 @@ public class PricingModelConverterTest {
@Test
public void testConvertStandardPricing() {
BillingTemplateVO template = new BillingTemplateVO();
template.setId(1L);
template.setName("标准计费模板");
template.setTemplateId("1L");
template.setTemplateName("标准计费模板");
List<BillingDetailVO> details = new ArrayList<>();
BillingDetailVO detail = new BillingDetailVO();
detail.setTimeType("3"); // 平时
detail.setElectricityPrice(new BigDecimal("0.8"));
detail.setServicePrice(new BigDecimal("0.4"));
detail.setApplyTime("00:00-24:00");
detail.setApplyTime(Lists.newArrayList("00:00-24:00"));
details.add(detail);
template.setBillingDetailList(details);
// template.setBillingDetailList(details);
JcppPricingModel model = PricingModelConverter.convert(template);
@@ -53,8 +54,8 @@ public class PricingModelConverterTest {
@Test
public void testConvertPeakValleyPricing() {
BillingTemplateVO template = new BillingTemplateVO();
template.setId(2L);
template.setName("峰谷计费模板");
template.setTemplateId("2L");
template.setTemplateName("峰谷计费模板");
List<BillingDetailVO> details = new ArrayList<>();
@@ -63,7 +64,7 @@ public class PricingModelConverterTest {
sharpDetail.setTimeType("1");
sharpDetail.setElectricityPrice(new BigDecimal("1.2"));
sharpDetail.setServicePrice(new BigDecimal("0.6"));
sharpDetail.setApplyTime("10:00-12:00,18:00-20:00");
sharpDetail.setApplyTime(Lists.newArrayList("10:00-12:00","18:00-20:00"));
details.add(sharpDetail);
// 峰时
@@ -71,7 +72,7 @@ public class PricingModelConverterTest {
peakDetail.setTimeType("2");
peakDetail.setElectricityPrice(new BigDecimal("1.0"));
peakDetail.setServicePrice(new BigDecimal("0.5"));
peakDetail.setApplyTime("08:00-10:00,12:00-18:00");
peakDetail.setApplyTime(Lists.newArrayList("08:00-10:00","12:00-18:00"));
details.add(peakDetail);
// 平时
@@ -79,7 +80,7 @@ public class PricingModelConverterTest {
flatDetail.setTimeType("3");
flatDetail.setElectricityPrice(new BigDecimal("0.8"));
flatDetail.setServicePrice(new BigDecimal("0.4"));
flatDetail.setApplyTime("06:00-08:00,20:00-22:00");
flatDetail.setApplyTime(Lists.newArrayList("06:00-08:00","20:00-22:00"));
details.add(flatDetail);
// 谷时
@@ -87,10 +88,10 @@ public class PricingModelConverterTest {
valleyDetail.setTimeType("4");
valleyDetail.setElectricityPrice(new BigDecimal("0.4"));
valleyDetail.setServicePrice(new BigDecimal("0.2"));
valleyDetail.setApplyTime("00:00-06:00,22:00-24:00");
valleyDetail.setApplyTime(Lists.newArrayList("00:00-06:00","22:00-24:00"));
details.add(valleyDetail);
template.setBillingDetailList(details);
// template.setBillingDetailList(details);
JcppPricingModel model = PricingModelConverter.convert(template);
@@ -131,9 +132,9 @@ public class PricingModelConverterTest {
@Test
public void testConvertTemplateWithoutDetails() {
BillingTemplateVO template = new BillingTemplateVO();
template.setId(3L);
template.setName("无详情模板");
template.setBillingDetailList(null);
template.setTemplateId("3L");
template.setTemplateName("无详情模板");
// template.setBillingDetailList(null);
JcppPricingModel model = PricingModelConverter.convert(template);