新疆后端项目
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>data-center-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.renkang.datacenter.api;
|
||||
|
||||
import com.renkang.datacenter.bean.*;
|
||||
import com.renkang.datacenter.config.ImcCenterConstants;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Retryable(maxAttempts = 2, listeners = "restRetryListener")
|
||||
public interface DataCenterExecutor {
|
||||
|
||||
Result<Object> addDevice(WatchDevice device);
|
||||
|
||||
Result<Object> addDeviceBatch(WatchDeviceBatch devices);
|
||||
|
||||
Result<Object> removeDevice(WatchNo watchNo);
|
||||
|
||||
Result<Object> setSwitchStatus(WatchDeviceSwitch watchDeviceSwitch);
|
||||
|
||||
Result<Object> setSwitchStatusAll(DeviceSwitch deviceSwitch);
|
||||
|
||||
Result<Object> cmdNotice(Notice notice);
|
||||
|
||||
Result<Object> cmdNoticeMulti(Notice notice);
|
||||
|
||||
Result<Object> watchDataList(WatchDataList watchDataList);
|
||||
|
||||
Result<Object> increaseWatchDataCount(IncreaseWatchDataCount dataCount);
|
||||
|
||||
Result<Object> increaseWatchDataList(IncreaseWatchDataList dataList);
|
||||
|
||||
Result<Object> watchSdcItemData(WatchSdcItemData sdcItemData);
|
||||
|
||||
Result<Object> deviceInfoAll(WatchNo watchNo);
|
||||
|
||||
Result<Object> getRate(WatchNo watchNo);
|
||||
|
||||
Result<Object> getPeriod(WatchNo watchNo);
|
||||
|
||||
Result<Object> getWarnSwitch(WatchNo watchNo);
|
||||
|
||||
Result<Object> saveRate(Rate rate);
|
||||
|
||||
Result<Object> savePeriod(Period period);
|
||||
|
||||
Result<Object> saveWarnSwitch(WarnSwitch warnSwitch);
|
||||
|
||||
Result<Object> cmdDataPush(String watchNo);
|
||||
|
||||
Result<Object> cmdUpdatePeriod(String watchNo);
|
||||
|
||||
Result<Object> cmdUpdateTask(String watchNo);
|
||||
|
||||
Result<Object> cmdUpdateSwitch(String watchNo);
|
||||
|
||||
@Retryable(maxAttempts = 2, listeners = ImcCenterConstants.IMC_LISTENER)
|
||||
Result<Object> getImageMessage(ImcPeIdVo imcPeIdVo);
|
||||
|
||||
/**
|
||||
* 通过peId获取影像基本信息
|
||||
* @param imcPeIdVo
|
||||
* @return
|
||||
*/
|
||||
@Retryable(maxAttempts = 2, listeners = ImcCenterConstants.IMC_LISTENER)
|
||||
Result<Object> getImageItems(ImcPeIdVo imcPeIdVo);
|
||||
|
||||
String downloadAsString(String filepath);
|
||||
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package com.renkang.datacenter.api;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.renkang.datacenter.bean.*;
|
||||
import com.renkang.datacenter.config.DataCenterConstants;
|
||||
import com.renkang.datacenter.config.DataCenterProperties;
|
||||
import com.renkang.datacenter.config.MethodApi;
|
||||
import com.renkang.datacenter.util.RemoteUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class DefaultDataCenterExecutor implements DataCenterExecutor {
|
||||
|
||||
private DataCenterProperties properties;
|
||||
|
||||
|
||||
@Autowired
|
||||
public void setProperties(DataCenterProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> addDevice(WatchDevice device) {
|
||||
return RemoteUtils.post(MethodApi.ADD_DEVICE,device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> addDeviceBatch(WatchDeviceBatch devices) {
|
||||
return RemoteUtils.post(MethodApi.ADD_DEVICE_BATCH,devices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> removeDevice(WatchNo watchNo) {
|
||||
return RemoteUtils.post(MethodApi.REMOVE_DEVICE, objectToMap(watchNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> setSwitchStatus(WatchDeviceSwitch watchDeviceSwitch) {
|
||||
return RemoteUtils.post(MethodApi.SET_SWITCH_STATUS, watchDeviceSwitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> setSwitchStatusAll(DeviceSwitch deviceSwitch) {
|
||||
return RemoteUtils.post(MethodApi.SET_SWITCH_STATUS_ALL, deviceSwitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> cmdNotice(Notice notice) {
|
||||
return RemoteUtils.post(MethodApi.CMD_NOTICE, objectToMap(notice));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> cmdNoticeMulti(Notice notice) {
|
||||
return RemoteUtils.post(MethodApi.CMD_NOTICE_MULTI, objectToMap(notice));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> watchDataList(WatchDataList watchDataList) {
|
||||
return RemoteUtils.get(MethodApi.WATCH_DATA_LIST, objectToMap(watchDataList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> increaseWatchDataCount(IncreaseWatchDataCount dataCount) {
|
||||
if (Objects.isNull(dataCount.getPageSize()) || dataCount.getPageSize() == 0) {
|
||||
dataCount.setPageSize(properties.getPageSize());
|
||||
}
|
||||
return RemoteUtils.get(MethodApi.INCREASE_WATCH_DATA_PAGE_COUNT, objectToMap(dataCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> increaseWatchDataList(IncreaseWatchDataList dataList) {
|
||||
if (Objects.isNull(dataList.getPageSize()) || dataList.getPageSize() == 0) {
|
||||
dataList.setPageSize(properties.getPageSize());
|
||||
}
|
||||
return RemoteUtils.get(MethodApi.INCREASE_WATCH_DATA_PAGE_LIST, objectToMap(dataList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> watchSdcItemData(WatchSdcItemData sdcItemData) {
|
||||
return RemoteUtils.get(MethodApi.WATCH_SDC_ITEM_DATA, objectToMap(sdcItemData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> deviceInfoAll(WatchNo watchNo) {
|
||||
return RemoteUtils.get(MethodApi.DEVICE_INFO_ALL, objectToMap(watchNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> getRate(WatchNo watchNo) {
|
||||
return RemoteUtils.get(MethodApi.GET_RATE, objectToMap(watchNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> getPeriod(WatchNo watchNo) {
|
||||
return RemoteUtils.get(MethodApi.GET_PERIOD, objectToMap(watchNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> getWarnSwitch(WatchNo watchNo) {
|
||||
return RemoteUtils.get(MethodApi.GET_WARN_SWITCH, objectToMap(watchNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> saveRate(Rate rate) {
|
||||
return RemoteUtils.post(MethodApi.SAVE_RATE, rate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> savePeriod(Period period) {
|
||||
return RemoteUtils.post(MethodApi.SAVE_PERIOD, period);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> saveWarnSwitch(WarnSwitch warnSwitch) {
|
||||
return RemoteUtils.post(MethodApi.SAVE_WARN_SWITCH, warnSwitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> cmdDataPush(String watchNo) {
|
||||
MqttTask task = new MqttTask();
|
||||
task.setWatchNo(watchNo);
|
||||
task.setTaskName(DataCenterConstants.MQTT_CMD_DATA_PUSH);
|
||||
return cmdDataPush(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> cmdUpdatePeriod(String watchNo) {
|
||||
MqttTask task = new MqttTask();
|
||||
task.setWatchNo(watchNo);
|
||||
task.setTaskName(DataCenterConstants.MQTT_CMD_UPDATE_PERIOD);
|
||||
return cmdDataPush(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> cmdUpdateTask(String watchNo) {
|
||||
MqttTask task = new MqttTask();
|
||||
task.setWatchNo(watchNo);
|
||||
task.setTaskName(DataCenterConstants.MQTT_CMD_UPDATE_TASK);
|
||||
return cmdDataPush(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> cmdUpdateSwitch(String watchNo) {
|
||||
MqttTask task = new MqttTask();
|
||||
task.setWatchNo(watchNo);
|
||||
task.setTaskName(DataCenterConstants.MQTT_CMD_UPDATE_SWITCH);
|
||||
return cmdDataPush(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Object> getImageMessage(ImcPeIdVo imcPeIdVo) {
|
||||
return RemoteUtils.post(MethodApi.GET_IMAGE_MESSAGE, imcPeIdVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过peId获取影像基本信息
|
||||
*
|
||||
* @param imcPeIdVo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Result<Object> getImageItems(ImcPeIdVo imcPeIdVo) {
|
||||
return RemoteUtils.post(MethodApi.GET_IMAGE_ITEMS, imcPeIdVo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String downloadAsString(String filepath) {
|
||||
return RemoteUtils.downloadAsString(filepath);
|
||||
}
|
||||
|
||||
private Result<Object> cmdDataPush(MqttTask task) {
|
||||
return RemoteUtils.post(MethodApi.CMD_DATA_PUSH, objectToMap(task));
|
||||
}
|
||||
|
||||
private Map<String,Object> objectToMap(Object source) {
|
||||
return (JSONObject) JSON.toJSON(source);
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataCommon extends WatchDataBase {
|
||||
|
||||
private String wdType;
|
||||
|
||||
private Double dataValue;
|
||||
|
||||
private String timeStamp;
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataEcg extends WatchDataBase {
|
||||
|
||||
|
||||
private Long ecgStartTime;
|
||||
|
||||
private Long ecgEndTime;
|
||||
|
||||
@JSONField(format = "yyyy-MM-dd")
|
||||
private Date dataDate;
|
||||
|
||||
private Integer ecgArrhyType;
|
||||
|
||||
private String ecgArrhyTypeDict;
|
||||
|
||||
private Integer ecgUserSymptom;
|
||||
|
||||
private String ecgUserSymptomDict;
|
||||
|
||||
private Integer ecgArrhyAvgRate;
|
||||
|
||||
private Integer ecgDataPointsCount;
|
||||
|
||||
private String ecgDataPoints;
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataExercise extends WatchDataBase {
|
||||
|
||||
/**
|
||||
* 中高强度运动时间(分钟)
|
||||
*/
|
||||
private Integer strengthTimes;
|
||||
/**
|
||||
* 总活动时长(小时)
|
||||
*/
|
||||
private Integer totalTime;
|
||||
/**
|
||||
* 数据日期
|
||||
*/
|
||||
private String dataDate;
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataGps extends WatchDataBase {
|
||||
|
||||
private Double lon;
|
||||
|
||||
private Double lat;
|
||||
|
||||
private String address;
|
||||
|
||||
private String timeStamp;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataHeartRate extends WatchDataBase {
|
||||
|
||||
private Double dataValue;
|
||||
|
||||
private Double silenceValue;
|
||||
|
||||
private String timeStamp;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataSdc extends WatchDataBase {
|
||||
|
||||
private String sdcDate;
|
||||
|
||||
private Long dataValue;
|
||||
|
||||
private String wdType;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataSleep extends WatchDataBase {
|
||||
|
||||
private String startTimeStamp;
|
||||
|
||||
private String endTimeStamp;
|
||||
|
||||
private String sleepType;
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataSleepNew extends WatchDataBase {
|
||||
|
||||
private String sleepFlag;
|
||||
|
||||
@JSONField(alternateNames = "DataDate")
|
||||
private String dataDate;
|
||||
|
||||
private Integer errCode;
|
||||
|
||||
private List<Error> errCodeArr;
|
||||
|
||||
private List<Day> statusInDayArr;
|
||||
|
||||
private List<Minute> statusInMinuteArr;
|
||||
|
||||
@Data
|
||||
public static class Error implements Serializable {
|
||||
|
||||
private Integer errCode;
|
||||
|
||||
private String startTime;
|
||||
|
||||
private String endTime;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Day implements Serializable {
|
||||
/**
|
||||
* 睡梦时长(分钟)
|
||||
*/
|
||||
private Integer deepSleepPartCnt;
|
||||
/**
|
||||
* 入睡时间点
|
||||
*/
|
||||
private String fallAsleepTime;
|
||||
/**
|
||||
* 上床时间
|
||||
*/
|
||||
private String goBedTime;
|
||||
/**
|
||||
* 睡眠效率百分比
|
||||
*/
|
||||
private Integer sleepEfficiency;
|
||||
/**
|
||||
* 睡眠潜伏期
|
||||
*/
|
||||
private Long sleepLatency;
|
||||
/**
|
||||
* 睡眠得分
|
||||
*/
|
||||
private Integer sleepScore;
|
||||
/**
|
||||
* 原始睡眠得分
|
||||
*/
|
||||
@JSONField(alternateNames = "sleepScoreOrign")
|
||||
private Integer sleepScoreOrigin;
|
||||
/**
|
||||
* 鼾声(每小时次数)
|
||||
*/
|
||||
private Integer snoreFreq;
|
||||
/**
|
||||
* 当天的时间戳
|
||||
*/
|
||||
private String startTime;
|
||||
/**
|
||||
* 数据有效性
|
||||
*/
|
||||
private Double validData;
|
||||
/**
|
||||
* 醒来时间
|
||||
*/
|
||||
private String wakeUpTime;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Minute implements Serializable {
|
||||
/**
|
||||
* 睡眠状态
|
||||
*/
|
||||
private String status;
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private String startTime;
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private String endTime;
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataSteps extends WatchDataBase {
|
||||
|
||||
/**
|
||||
* 数据日期
|
||||
*/
|
||||
@JSONField(format = "yyyy-MM-dd")
|
||||
private Date stepDate;
|
||||
|
||||
private Integer stepCount;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataStress extends WatchDataBase {
|
||||
|
||||
private Double dataValue;
|
||||
|
||||
private String startTimeStamp;
|
||||
|
||||
private String endTimeStamp;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataTemperature extends WatchDataBase {
|
||||
|
||||
private Double skinTempera;
|
||||
|
||||
private Double dataValue;
|
||||
|
||||
private String timeStamp;
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataTrace extends WatchDataBase {
|
||||
|
||||
private String recordId;
|
||||
/**
|
||||
* 海拔
|
||||
*/
|
||||
private Double altitude;
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
private Double latitude;
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private Double longitude;
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
private String utcTime;
|
||||
/**
|
||||
* 数据是否合法
|
||||
*/
|
||||
private String valid;
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class DataWorkout extends WatchDataBase {
|
||||
|
||||
private String workoutType;
|
||||
|
||||
private Double calorie;
|
||||
|
||||
private Double distance;
|
||||
|
||||
private String startTimeStamp;
|
||||
|
||||
private String endTimeStamp;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class DeviceSwitch implements Serializable {
|
||||
|
||||
private String wdType;
|
||||
|
||||
private String switchFlag;
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ImcPeIdVo {
|
||||
|
||||
private String peId;
|
||||
|
||||
private String hospitalId;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class IncreaseWatchDataCount implements Serializable {
|
||||
|
||||
private String wdType;
|
||||
|
||||
private String id;
|
||||
|
||||
private Integer pageSize;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class IncreaseWatchDataList extends IncreaseWatchDataCount implements Serializable {
|
||||
|
||||
private Integer pageNo;
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class Login implements Serializable {
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class MqttTask implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
private String taskName;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class Notice implements Serializable {
|
||||
|
||||
private String noticeTitle;
|
||||
|
||||
private String notice;
|
||||
|
||||
private String watchNo;
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class Period implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
private String wdType;
|
||||
|
||||
private Double warnMin;
|
||||
|
||||
private Double warnMax;
|
||||
|
||||
private Integer period;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class Rate implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
private String wdType;
|
||||
|
||||
private Integer taskRate;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class WarnSwitch implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
private String wdType;
|
||||
|
||||
private String switchFlag;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@Data
|
||||
public class WatchDataBase implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String watchNo;
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class WatchDataList implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
private String queryDate;
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/13
|
||||
*/
|
||||
@Data
|
||||
public class WatchDataResult implements Serializable {
|
||||
|
||||
private String maxId;
|
||||
|
||||
@JSONField(alternateNames = "commonVoList")
|
||||
private List<DataCommon> commonList;
|
||||
|
||||
@JSONField(alternateNames = "heartRateVoList")
|
||||
private List<DataHeartRate> heartRateList;
|
||||
|
||||
@JSONField(alternateNames = "gpsVoList")
|
||||
private List<DataGps> gpsList;
|
||||
|
||||
@JSONField(alternateNames = "sleepVoList")
|
||||
private List<DataSleep> sleepList;
|
||||
|
||||
@JSONField(alternateNames = "sdcVoList")
|
||||
private List<DataSdc> sdcList;
|
||||
|
||||
@JSONField(alternateNames = "tempVoList")
|
||||
private List<DataTemperature> tempList;
|
||||
|
||||
@JSONField(alternateNames = "workoutVoList")
|
||||
private List<DataWorkout> workoutList;
|
||||
|
||||
@JSONField(alternateNames = "stressVoList")
|
||||
private List<DataStress> stressList;
|
||||
|
||||
@JSONField(alternateNames = "exerciseVoList")
|
||||
private List<DataExercise> exerciseList;
|
||||
|
||||
@JSONField(alternateNames = "traceVoList")
|
||||
private List<DataTrace> traceList;
|
||||
|
||||
@JSONField(alternateNames = "sleepNewVoList")
|
||||
private List<DataSleepNew> sleepNewList;
|
||||
|
||||
@JSONField(alternateNames = "ecgVoList")
|
||||
private List<DataEcg> ecgList;
|
||||
|
||||
@JSONField(alternateNames = "stepVoList")
|
||||
private List<DataSteps> stepList;
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class WatchDevice implements Serializable {
|
||||
|
||||
/**
|
||||
* 手表SN编码
|
||||
*/
|
||||
private String watchNo;
|
||||
/**
|
||||
* IMEI编码
|
||||
*/
|
||||
private String imeiNo;
|
||||
/**
|
||||
* EID编码
|
||||
*/
|
||||
private String eid;
|
||||
private String watchModel;
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class WatchDeviceBatch implements Serializable {
|
||||
|
||||
private List<WatchDevice> deviceVoList;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class WatchDeviceSwitch extends DeviceSwitch implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class WatchNo implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
public static WatchNo of(String watchNo) {
|
||||
WatchNo instance = new WatchNo();
|
||||
instance.setWatchNo(watchNo);
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.datacenter.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/5
|
||||
*/
|
||||
@Data
|
||||
public class WatchSdcItemData implements Serializable {
|
||||
|
||||
private String watchNo;
|
||||
|
||||
private String wdType;
|
||||
|
||||
private String queryDate;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
public interface DataCenterConstants {
|
||||
|
||||
//通知更新阈值及频率
|
||||
String MQTT_CMD_UPDATE_PERIOD = "updatePeriod";
|
||||
//通知更新定时任务
|
||||
String MQTT_CMD_UPDATE_TASK = "updateTask";
|
||||
//通知更新开关
|
||||
String MQTT_CMD_UPDATE_SWITCH = "updateSwitch";
|
||||
//通知手表上传数据
|
||||
String MQTT_CMD_DATA_PUSH = "dataPush";
|
||||
|
||||
String REDIS_TOKEN_KEY = "DC_TOKEN";
|
||||
|
||||
String HEADER_TOKEN_KEY = "X-Access-Token";
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties("datacenter")
|
||||
@Data
|
||||
public class DataCenterProperties {
|
||||
|
||||
private String url = "";
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String publicKey;
|
||||
|
||||
private Long timeout = 3000L;
|
||||
|
||||
private Integer pageSize = 500;
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
public interface ImcCenterConstants {
|
||||
|
||||
String IMC_LISTENER = "RestRetryImcListener";
|
||||
String REDIS_TOKEN_KEY = "IMC_TOKEN";
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
@Getter
|
||||
public enum MethodApi {
|
||||
/**
|
||||
* 获取令牌
|
||||
*/
|
||||
GET_TOKEN("sys/getToken"),
|
||||
/**
|
||||
* 添加设备
|
||||
*/
|
||||
ADD_DEVICE("watch/api/addDevice"),
|
||||
/**
|
||||
* 批量添加设备
|
||||
*/
|
||||
ADD_DEVICE_BATCH("watch/api/batchAddDevice"),
|
||||
/**
|
||||
* 删除设备
|
||||
*/
|
||||
REMOVE_DEVICE("watch/api/removeDevice?watchNo={watchNo}"),
|
||||
/**
|
||||
* 设备开关设置
|
||||
*/
|
||||
SET_SWITCH_STATUS("watch/api/setSwitchStatus"),
|
||||
/**
|
||||
* 设备开关全部设置
|
||||
*/
|
||||
SET_SWITCH_STATUS_ALL("watch/api/setAllSwitchStatus"),
|
||||
/**
|
||||
* 通知消息
|
||||
*/
|
||||
CMD_NOTICE("watch/mqtt/cmdNotice?watchNo={watchNo}¬iceTitle={noticeTitle}¬ice={notice}"),
|
||||
/**
|
||||
* 通知消息
|
||||
*/
|
||||
CMD_NOTICE_MULTI("watch/mqtt/cmdNoticeMulti?watchNo={watchNo}¬iceTitle={noticeTitle}¬ice={notice}"),
|
||||
/**
|
||||
* 推送数据通知
|
||||
*/
|
||||
CMD_DATA_PUSH("watch/mqtt/cmdDataPush?watchNo={watchNo}&taskName={taskName}"),
|
||||
/**
|
||||
* 全量数据获取
|
||||
*/
|
||||
WATCH_DATA_LIST("watch/api/getWatchDataList/{queryDate}?watchNo={watchNo}"),
|
||||
/**
|
||||
* 增量数据获取(页数)
|
||||
*/
|
||||
INCREASE_WATCH_DATA_PAGE_COUNT("watch/api/getIncreWatchDataPageCount/{wdType}/{id}/{pageSize}"),
|
||||
/**
|
||||
* 增量数据获取(数据)
|
||||
*/
|
||||
INCREASE_WATCH_DATA_PAGE_LIST("watch/api/getIncreWatchDataPageList/{wdType}/{id}/{pageNo}/{pageSize}"),
|
||||
/**
|
||||
* SDC详细数据获取
|
||||
*/
|
||||
WATCH_SDC_ITEM_DATA("watch/api/getWatchSdcItemData/{watchNo}/{queryDate}/{wdType}"),
|
||||
/**
|
||||
* 设备列表查询
|
||||
*/
|
||||
DEVICE_INFO_ALL("watch/api/getAllDeviceInfo?watchNo={watchNo}"),
|
||||
/**
|
||||
* 查询上传频率设置
|
||||
*/
|
||||
GET_RATE("watch/api/getRateByWatchNo?watchNo={watchNo}"),
|
||||
/**
|
||||
* 设置上传频率
|
||||
*/
|
||||
SAVE_RATE("watch/api/saveRateByNoAndWdType"),
|
||||
/**
|
||||
* 查询阈值设置
|
||||
*/
|
||||
GET_PERIOD("watch/api/getPeriodByWatchNo?watchNo={watchNo}"),
|
||||
/**
|
||||
* 设置阈值
|
||||
*/
|
||||
SAVE_PERIOD("watch/api/savePeriodByNoAndWdType"),
|
||||
/**
|
||||
* 查询报警开关设置
|
||||
*/
|
||||
GET_WARN_SWITCH("watch/api/getWarnListByWatchNo?watchNo={watchNo}"),
|
||||
/**
|
||||
* 设置报警开关
|
||||
*/
|
||||
SAVE_WARN_SWITCH("watch/api/saveWarnByNoAndWdType"),
|
||||
|
||||
// =======================影像中心============================
|
||||
/**
|
||||
* 查询影像人员信息
|
||||
*/
|
||||
GET_IMAGE_MESSAGE("imc/file/getImageMsg"),
|
||||
/**
|
||||
* 通过peId获取影像基本信息
|
||||
*/
|
||||
GET_IMAGE_ITEMS("imc/file/getImageItems"),
|
||||
;
|
||||
|
||||
private final String url;
|
||||
|
||||
MethodApi(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
@Configuration
|
||||
@EnableRetry
|
||||
public class RestConfig {
|
||||
|
||||
private final DataCenterProperties properties;
|
||||
|
||||
public RestConfig(DataCenterProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplate dataCenterTemplate() {
|
||||
return new RestTemplateBuilder()
|
||||
.setConnectTimeout(Duration.of(properties.getTimeout(), ChronoUnit.MILLIS))
|
||||
.additionalMessageConverters(
|
||||
new StringHttpMessageConverter(StandardCharsets.UTF_8),
|
||||
new MappingJackson2HttpMessageConverter()
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.renkang.datacenter.bean.Login;
|
||||
import com.renkang.datacenter.util.RemoteUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.util.RSAEncryptUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.retry.RetryContext;
|
||||
import org.springframework.retry.RetryListener;
|
||||
import org.springframework.retry.interceptor.MethodInvocationRetryCallback;
|
||||
import org.springframework.retry.listener.MethodInvocationRetryListenerSupport;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
@Component(ImcCenterConstants.IMC_LISTENER)
|
||||
@Slf4j
|
||||
public class RestRetryImcListener extends MethodInvocationRetryListenerSupport implements RetryListener {
|
||||
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
private DataCenterProperties properties;
|
||||
|
||||
@Autowired
|
||||
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setProperties(DataCenterProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected <T, E extends Throwable> boolean doOpen(RetryContext context, MethodInvocationRetryCallback<T, E> callback) {
|
||||
String token = "";
|
||||
try{
|
||||
token = (String) redisTemplate.opsForValue().get(ImcCenterConstants.REDIS_TOKEN_KEY);
|
||||
if (!StringUtils.hasLength(token)) {
|
||||
token = refreshToken();
|
||||
}
|
||||
}catch (Exception e){
|
||||
token = refreshToken();
|
||||
}
|
||||
RemoteUtils.TOKEN_CACHE.set(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T, E extends Throwable> void doClose(RetryContext context, MethodInvocationRetryCallback<T, E> callback, Throwable throwable) {
|
||||
RemoteUtils.TOKEN_CACHE.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T, E extends Throwable> void doOnError(RetryContext context, MethodInvocationRetryCallback<T, E> callback, Throwable throwable) {
|
||||
String methodName = callback.getInvocation().getMethod().getName();
|
||||
log.error("执行方法[{}]出错,刷新令牌后重试,当前重试次数:{}",methodName, context.getRetryCount(),throwable);
|
||||
String token = refreshToken();
|
||||
RemoteUtils.TOKEN_CACHE.set(token);
|
||||
}
|
||||
|
||||
private String refreshToken() {
|
||||
|
||||
Login body = new Login();
|
||||
body.setUsername(properties.getUsername());
|
||||
body.setPassword(RSAEncryptUtils.encrypt1(properties.getPassword(),properties.getPublicKey()));
|
||||
Result<Object> result = RemoteUtils.post(MethodApi.GET_TOKEN, body);
|
||||
if (!result.isSuccess()) {
|
||||
log.info("刷新数据中心令牌失败:{}",result.getMessage());
|
||||
return null;
|
||||
}
|
||||
JSONObject data = (JSONObject) JSON.toJSON(result.getResult());
|
||||
String token = data.getString("token");
|
||||
redisTemplate.opsForValue().set(ImcCenterConstants.REDIS_TOKEN_KEY,token, Duration.ofDays(1));
|
||||
log.info("刷新影像中心令牌成功:{}", token);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.renkang.datacenter.config;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.renkang.datacenter.bean.Login;
|
||||
import com.renkang.datacenter.util.RemoteUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.util.RSAEncryptUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.retry.RetryContext;
|
||||
import org.springframework.retry.RetryListener;
|
||||
import org.springframework.retry.interceptor.MethodInvocationRetryCallback;
|
||||
import org.springframework.retry.listener.MethodInvocationRetryListenerSupport;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RestRetryListener extends MethodInvocationRetryListenerSupport implements RetryListener {
|
||||
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
private DataCenterProperties properties;
|
||||
|
||||
@Autowired
|
||||
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setProperties(DataCenterProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected <T, E extends Throwable> boolean doOpen(RetryContext context, MethodInvocationRetryCallback<T, E> callback) {
|
||||
String token = "";
|
||||
try{
|
||||
token = (String) redisTemplate.opsForValue().get(DataCenterConstants.REDIS_TOKEN_KEY);
|
||||
if (!StringUtils.hasLength(token)) {
|
||||
token = refreshToken();
|
||||
}
|
||||
}catch (Exception e){
|
||||
token = refreshToken();
|
||||
}
|
||||
RemoteUtils.TOKEN_CACHE.set(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T, E extends Throwable> void doClose(RetryContext context, MethodInvocationRetryCallback<T, E> callback, Throwable throwable) {
|
||||
RemoteUtils.TOKEN_CACHE.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T, E extends Throwable> void doOnError(RetryContext context, MethodInvocationRetryCallback<T, E> callback, Throwable throwable) {
|
||||
String methodName = callback.getInvocation().getMethod().getName();
|
||||
log.error("执行方法[{}]出错,刷新令牌后重试,当前重试次数:{}",methodName, context.getRetryCount(),throwable);
|
||||
String token = refreshToken();
|
||||
RemoteUtils.TOKEN_CACHE.set(token);
|
||||
}
|
||||
|
||||
private String refreshToken() {
|
||||
|
||||
Login body = new Login();
|
||||
body.setUsername(properties.getUsername());
|
||||
body.setPassword(RSAEncryptUtils.encrypt1(properties.getPassword(),properties.getPublicKey()));
|
||||
Result<Object> result = RemoteUtils.post(MethodApi.GET_TOKEN, body);
|
||||
if (!result.isSuccess()) {
|
||||
log.info("刷新数据中心令牌失败:{}",result.getMessage());
|
||||
return null;
|
||||
}
|
||||
JSONObject data = (JSONObject) JSON.toJSON(result.getResult());
|
||||
String token = data.getString("token");
|
||||
redisTemplate.opsForValue().set(DataCenterConstants.REDIS_TOKEN_KEY,token, Duration.ofDays(1));
|
||||
log.info("刷新数据中心令牌成功:{}", token);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.renkang.datacenter.util;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.renkang.datacenter.config.DataCenterConstants;
|
||||
import com.renkang.datacenter.config.DataCenterProperties;
|
||||
import com.renkang.datacenter.config.MethodApi;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/3
|
||||
*/
|
||||
public class RemoteUtils {
|
||||
|
||||
public static final ThreadLocal<String> TOKEN_CACHE = new ThreadLocal<>();
|
||||
|
||||
private static RestTemplate restTemplate;
|
||||
|
||||
private static DataCenterProperties properties;
|
||||
|
||||
public static RestTemplate getRestTemplate() {
|
||||
if (Objects.isNull(restTemplate)) {
|
||||
restTemplate = SpringContextUtils.getBean("dataCenterTemplate", RestTemplate.class);
|
||||
}
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
public static DataCenterProperties getProperties() {
|
||||
if (Objects.isNull(properties)) {
|
||||
properties = SpringContextUtils.getBean(DataCenterProperties.class);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static Result<Object> get(MethodApi api, Map<String, Object> params) {
|
||||
return exchange(api, HttpMethod.GET, null, params);
|
||||
}
|
||||
|
||||
public static String downloadAsString(String filepath) {
|
||||
return getRestTemplate().getForObject(urlHandlerForFileDown(filepath), String.class);
|
||||
}
|
||||
|
||||
public static Result<Object> get(MethodApi api) {
|
||||
return exchange(api, HttpMethod.GET, null, null);
|
||||
}
|
||||
|
||||
public static Result<Object> post(MethodApi api, Object body) {
|
||||
return exchange(api, HttpMethod.POST, body, null);
|
||||
}
|
||||
|
||||
public static Result<Object> post(MethodApi api, Object body, Map<String, Object> params) {
|
||||
return exchange(api, HttpMethod.POST, body, params);
|
||||
}
|
||||
|
||||
public static Result<Object> post(MethodApi api, Map<String, Object> params) {
|
||||
return exchange(api, HttpMethod.POST, null, params);
|
||||
}
|
||||
|
||||
private static Result<Object> exchange(MethodApi api, HttpMethod method, Object body, Map<String, Object> params) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
String token = TOKEN_CACHE.get();
|
||||
if (StringUtils.hasLength(token)) {
|
||||
headers.add(DataCenterConstants.HEADER_TOKEN_KEY, TOKEN_CACHE.get());
|
||||
}
|
||||
HttpEntity<?> entity = new HttpEntity<>(body, headers);
|
||||
if (CollectionUtils.isEmpty(params)) {
|
||||
return responseHandler(getRestTemplate().exchange(urlHandler(api), method, entity, String.class));
|
||||
} else {
|
||||
return responseHandler(getRestTemplate().exchange(urlHandler(api), method, entity, String.class, params));
|
||||
}
|
||||
}
|
||||
|
||||
private static String urlHandler(MethodApi api) {
|
||||
return urlHandler(api.getUrl());
|
||||
}
|
||||
|
||||
private static String urlHandler(String url) {
|
||||
String baseUrl = getProperties().getUrl();
|
||||
String path = url;
|
||||
if (!baseUrl.endsWith("/") && !path.startsWith("/")) {
|
||||
path = "/".concat(path);
|
||||
}
|
||||
return baseUrl + path;
|
||||
}
|
||||
|
||||
private static String urlHandlerForFileDown(String url) {
|
||||
String fileUrl = "file/down/".concat(url).replace("//", "/");
|
||||
return urlHandler(fileUrl);
|
||||
}
|
||||
|
||||
private static Result<Object> responseHandler(ResponseEntity<String> entity) {
|
||||
String body = entity.getBody();
|
||||
JSONObject responseJson = JSON.parseObject(body);
|
||||
String message = Optional.ofNullable(responseJson.getString("message")).orElse("");
|
||||
if (responseJson.getBoolean("success")) {
|
||||
return Result.OK(message, responseJson.get("result"));
|
||||
} else {
|
||||
return Result.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>font-resources</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>monitoring-sync</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 打包名称 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>default</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>divide-package</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<start-class>com.renkang.sync.ApplicationMain</start-class>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.renkang.sync;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableJpaRepositories(includeFilters = @ComponentScan.Filter(classes = Repository.class))
|
||||
public class ApplicationMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ApplicationMain.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.renkang.sync.bean;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 接口返回数据格式
|
||||
*
|
||||
* @author scott
|
||||
* @email jeecgos@163.com
|
||||
* @date 2019年1月19日
|
||||
*/
|
||||
@Data
|
||||
public class Result<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 成功标志
|
||||
*/
|
||||
private boolean success = true;
|
||||
|
||||
/**
|
||||
* 返回处理消息
|
||||
*/
|
||||
private String message = "";
|
||||
|
||||
/**
|
||||
* 返回代码
|
||||
*/
|
||||
private Integer code = 0;
|
||||
|
||||
/**
|
||||
* 返回数据对象 data
|
||||
*/
|
||||
private T result;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
private long timestamp = System.currentTimeMillis();
|
||||
@JsonIgnore
|
||||
private String onlTable;
|
||||
|
||||
public Result() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容VUE3版token失效不跳转登录页面
|
||||
*/
|
||||
public Result(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public static <T> Result<T> ok() {
|
||||
Result<T> r = new Result<>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 此方法是为了兼容升级所创建
|
||||
*/
|
||||
public static <T> Result<T> ok(String msg) {
|
||||
Result<T> r = new Result<>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
r.setMessage(msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <T> Result<T> ok(T data) {
|
||||
Result<T> r = new Result<>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
r.setResult(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <T> Result<T> ok(String msg, T data) {
|
||||
Result<T> r = new Result<>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
r.setMessage(msg);
|
||||
r.setResult(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <T> Result<T> error(String msg, T data) {
|
||||
Result<T> r = new Result<>();
|
||||
r.setSuccess(false);
|
||||
r.setCode(500);
|
||||
r.setMessage(msg);
|
||||
r.setResult(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <T> Result<T> error(String msg) {
|
||||
return error(500, msg);
|
||||
}
|
||||
|
||||
public static <T> Result<T> error(int code, String msg) {
|
||||
Result<T> r = new Result<>();
|
||||
r.setCode(code);
|
||||
r.setMessage(msg);
|
||||
r.setSuccess(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无权限访问返回结果
|
||||
*/
|
||||
public static <T> Result<T> noAuth(String msg) {
|
||||
return error(401, msg);
|
||||
}
|
||||
|
||||
public Result<T> success(String message) {
|
||||
this.message = message;
|
||||
this.code = 200;
|
||||
this.success = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> error500(String message) {
|
||||
this.message = message;
|
||||
this.code = 500;
|
||||
this.success = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.renkang.sync.bean.lefu;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.renkang.sync.entity.RemoteWeightManufacturerLefu;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Data
|
||||
public class BatchRecord {
|
||||
|
||||
@NotBlank(message = "Missing parameter: sn")
|
||||
private String sn;
|
||||
|
||||
@NotBlank(message = "Missing parameter: type")
|
||||
private String type;
|
||||
|
||||
@NotBlank(message = "Missing parameter: mac")
|
||||
@Pattern(regexp = "([A-Fa-f0-9]{2}[:]){5}[A-Fa-f0-9]{2}", message = "MAC address does not meet the rules")
|
||||
private String mac;
|
||||
|
||||
@NotBlank(message = "Missing parameter: charge")
|
||||
private String charge;
|
||||
|
||||
private String firmwareVersion;
|
||||
|
||||
private String wifiVersion;
|
||||
|
||||
@Valid
|
||||
private List<RecordData> data;
|
||||
|
||||
private RemoteWeightManufacturerLefu toRemoteEntity(RecordData data) {
|
||||
RemoteWeightManufacturerLefu remoteWeightManufacturerLefu = new RemoteWeightManufacturerLefu();
|
||||
remoteWeightManufacturerLefu.setDeviceSn(sn);
|
||||
remoteWeightManufacturerLefu.setDeviceType(type);
|
||||
remoteWeightManufacturerLefu.setDeviceMac(mac);
|
||||
remoteWeightManufacturerLefu.setDeviceCharge(charge);
|
||||
remoteWeightManufacturerLefu.setFirmwareVersion(firmwareVersion);
|
||||
remoteWeightManufacturerLefu.setWifiVersion(wifiVersion);
|
||||
remoteWeightManufacturerLefu.setDeviceImpedance(data.getImpedance());
|
||||
remoteWeightManufacturerLefu.setDataTime(data.getDataTime());
|
||||
remoteWeightManufacturerLefu.setWeight(data.getWeightNum());
|
||||
remoteWeightManufacturerLefu.setHeartRate(data.getHeartRate());
|
||||
remoteWeightManufacturerLefu.setCreateTime(DateUtil.date());
|
||||
return remoteWeightManufacturerLefu;
|
||||
}
|
||||
|
||||
public List<RemoteWeightManufacturerLefu> toRemoteEntities() {
|
||||
return CollectionUtil.isEmpty(data) ? Collections.emptyList() : data.stream()
|
||||
.map(this::toRemoteEntity)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.renkang.sync.bean.lefu;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Data
|
||||
public class DeviceInfo {
|
||||
|
||||
private String sn;
|
||||
|
||||
private String mac;
|
||||
|
||||
private String firmwareVersion;
|
||||
|
||||
@JsonProperty("WifiVersion")
|
||||
private String wifiVersion;
|
||||
|
||||
private String hardwareVersion;
|
||||
|
||||
private String charge;
|
||||
|
||||
private String type;
|
||||
|
||||
private Integer timezone;
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.renkang.sync.bean.lefu;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
public class LefuResponse<T> implements Serializable {
|
||||
|
||||
private static final Integer CODE_OK = 0;
|
||||
private static final Integer CODE_FAIL = 1;
|
||||
private static final Integer CODE_SUCCESS = 200;
|
||||
|
||||
private Integer code;
|
||||
|
||||
private T data;
|
||||
/**
|
||||
* The firmware on the device has been successfully written; this parameter is for compatibility with existing devices.
|
||||
*/
|
||||
private Integer errorCode; // Registration success status, 0 for success, non-zero for failure
|
||||
/**
|
||||
* The firmware on the device has been successfully written; this parameter is for compatibility with existing devices.
|
||||
*/
|
||||
private String text; // Return message, which can explain the reason for success or the reason for failure
|
||||
|
||||
public LefuResponse() {
|
||||
setCode(CODE_SUCCESS);
|
||||
}
|
||||
|
||||
public static <T> LefuResponse<T> ok(String text) {
|
||||
LefuResponse<T> scaleR = new LefuResponse<>();
|
||||
scaleR.setErrorCode(CODE_OK);
|
||||
scaleR.setText(text);
|
||||
return scaleR;
|
||||
}
|
||||
|
||||
public static <T> LefuResponse<T> ok(String text, T data) {
|
||||
LefuResponse<T> scaleR = new LefuResponse<>();
|
||||
scaleR.setErrorCode(CODE_OK);
|
||||
scaleR.setText(text);
|
||||
scaleR.setData(data);
|
||||
return scaleR;
|
||||
}
|
||||
|
||||
public static <T> LefuResponse<T> fail(String text, T data) {
|
||||
LefuResponse<T> scaleR = new LefuResponse<>();
|
||||
scaleR.setErrorCode(CODE_FAIL);
|
||||
scaleR.setText(text);
|
||||
scaleR.setData(data);
|
||||
return scaleR;
|
||||
}
|
||||
|
||||
public static <T> LefuResponse<T> fail(String text) {
|
||||
LefuResponse<T> scaleR = new LefuResponse<>();
|
||||
scaleR.setErrorCode(CODE_FAIL);
|
||||
scaleR.setText(text);
|
||||
return scaleR;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Integer getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public void setErrorCode(Integer errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.renkang.sync.bean.lefu;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.renkang.sync.entity.RemoteWeightManufacturerLefu;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Data
|
||||
public class Record extends RecordData {
|
||||
|
||||
@NotBlank(message = "Missing parameter: sn")
|
||||
private String sn;
|
||||
|
||||
@NotBlank(message = "Missing parameter: type")
|
||||
private String type;
|
||||
|
||||
@NotBlank(message = "Missing parameter: mac")
|
||||
@Pattern(regexp = "([A-Fa-f0-9]{2}[:]){5}[A-Fa-f0-9]{2}", message = "MAC address does not meet the rules")
|
||||
private String mac;
|
||||
|
||||
@NotBlank(message = "Missing parameter: charge")
|
||||
private String charge;
|
||||
|
||||
private String firmwareVersion;
|
||||
|
||||
private String wifiVersion;
|
||||
|
||||
public RemoteWeightManufacturerLefu toRemoteEntity() {
|
||||
RemoteWeightManufacturerLefu remoteWeightManufacturerLefu = new RemoteWeightManufacturerLefu();
|
||||
remoteWeightManufacturerLefu.setDeviceSn(sn);
|
||||
remoteWeightManufacturerLefu.setDeviceType(type);
|
||||
remoteWeightManufacturerLefu.setDeviceMac(mac);
|
||||
remoteWeightManufacturerLefu.setDeviceCharge(charge);
|
||||
remoteWeightManufacturerLefu.setFirmwareVersion(firmwareVersion);
|
||||
remoteWeightManufacturerLefu.setWifiVersion(wifiVersion);
|
||||
remoteWeightManufacturerLefu.setDeviceImpedance(getImpedance());
|
||||
remoteWeightManufacturerLefu.setDataTime(getDataTime());
|
||||
remoteWeightManufacturerLefu.setWeight(getWeightNum());
|
||||
remoteWeightManufacturerLefu.setHeartRate(getHeartRate());
|
||||
remoteWeightManufacturerLefu.setCreateTime(DateUtil.date());
|
||||
return remoteWeightManufacturerLefu;
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.renkang.sync.bean.lefu;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Data
|
||||
public class RecordData {
|
||||
|
||||
private String weight;
|
||||
|
||||
private String impedance;
|
||||
|
||||
@NotBlank(message = "Missing parameter: timestamp")
|
||||
private String timestamp;
|
||||
|
||||
private Integer heartRate;
|
||||
|
||||
public Date getDataTime() {
|
||||
return StrUtil.isNumeric(getTimestamp()) ? DateUtil.date(Long.parseLong(getTimestamp())) : null;
|
||||
}
|
||||
|
||||
public BigDecimal getWeightNum() {
|
||||
return NumberUtil.isNumber(getWeight()) ? new BigDecimal(getWeight()) : null;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.renkang.sync.bean.lefu;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Data
|
||||
public class TimeInfo {
|
||||
|
||||
private Long now;
|
||||
|
||||
private Integer unit;
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.renkang.sync.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@ConfigurationProperties("lefu")
|
||||
@Data
|
||||
public class LefuProperties {
|
||||
|
||||
private Map<String, Service> sync = new HashMap<>();
|
||||
|
||||
@Data
|
||||
public static class Service {
|
||||
|
||||
private String baseUrl = "";
|
||||
|
||||
private String username = "";
|
||||
|
||||
private String password = "";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.renkang.sync.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({SyncProperties.class, LefuProperties.class})
|
||||
@ConditionalOnProperty(prefix = "spring.cloud.nacos.discovery", name = "enabled", havingValue = "false", matchIfMissing = true)
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
public class SyncConfiguration {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskScheduler schedulingTaskExecutor() {
|
||||
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
|
||||
threadPoolTaskScheduler.setPoolSize(10);
|
||||
threadPoolTaskScheduler.setThreadNamePrefix("task-pool-");
|
||||
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
|
||||
return threadPoolTaskScheduler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
|
||||
threadPoolTaskScheduler.setPoolSize(10);
|
||||
threadPoolTaskScheduler.setThreadNamePrefix("async-pool-");
|
||||
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
|
||||
return threadPoolTaskScheduler;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.renkang.sync.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@ConfigurationProperties("sync")
|
||||
@Data
|
||||
public class SyncProperties {
|
||||
|
||||
private Integer size = 100;
|
||||
|
||||
private String cron = "0 */30 * * * *";
|
||||
|
||||
private List<String> baseUrls = new ArrayList<>();
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.renkang.sync.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.renkang.sync.bean.lefu.*;
|
||||
import com.renkang.sync.entity.RemoteWeightManufacturerLefu;
|
||||
import com.renkang.sync.service.LefuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/lefu/wifi")
|
||||
public class LefuController {
|
||||
|
||||
@Autowired
|
||||
private LefuService lefuService;
|
||||
|
||||
@PostMapping("/register")
|
||||
public LefuResponse<TimeInfo> register(@Validated @RequestBody DeviceInfo deviceInfo) {
|
||||
return LefuResponse.ok("DeviceInfo success", getTimeInfo());
|
||||
}
|
||||
|
||||
private TimeInfo getTimeInfo() {
|
||||
TimeInfo timeInfo = new TimeInfo();
|
||||
timeInfo.setUnit(0);
|
||||
timeInfo.setNow(System.currentTimeMillis());
|
||||
return timeInfo;
|
||||
}
|
||||
|
||||
@GetMapping("/config")
|
||||
public LefuResponse<TimeInfo> config(@Validated @RequestBody DeviceInfo deviceInfo) {
|
||||
return LefuResponse.ok("Get config info success", getTimeInfo());
|
||||
}
|
||||
|
||||
@PostMapping("/record")
|
||||
public LefuResponse<Boolean> record(@Validated @RequestBody Record record) throws JsonProcessingException {
|
||||
RemoteWeightManufacturerLefu data = lefuService.record(record);
|
||||
lefuService.sync(Collections.singletonList(data));
|
||||
return LefuResponse.ok("success");
|
||||
}
|
||||
|
||||
@PostMapping("/batchRecord")
|
||||
public LefuResponse<Boolean> batchRecord(@Validated @RequestBody BatchRecord batchRecord) throws JsonProcessingException {
|
||||
List<RemoteWeightManufacturerLefu> data = lefuService.batchRecord(batchRecord);
|
||||
lefuService.sync(data);
|
||||
return LefuResponse.ok("success");
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public LefuResponse<Page<RemoteWeightManufacturerLefu>> list(@RequestParam Integer pageNo, @RequestParam Integer pageSize) {
|
||||
return LefuResponse.ok("", lefuService.list(pageNo, pageSize));
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.renkang.sync.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.renkang.sync.bean.Result;
|
||||
import com.renkang.sync.entity.IdAware;
|
||||
import com.renkang.sync.service.DataService;
|
||||
import com.renkang.sync.util.Constants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.renkang.sync.util.Constants.GET_MAX_ID;
|
||||
import static com.renkang.sync.util.Constants.SAVE_DATA;
|
||||
|
||||
/**
|
||||
* @Name SyncController
|
||||
* @Author YangYuanChen
|
||||
* @Data 2024/7/26下午4:22
|
||||
*/
|
||||
@RestController
|
||||
@ConditionalOnProperty(prefix = "spring.cloud.nacos.discovery", name = "enabled", havingValue = "true")
|
||||
public class SyncController {
|
||||
|
||||
private DataService dataService;
|
||||
|
||||
@Autowired
|
||||
public void setDataService(DataService dataService) {
|
||||
this.dataService = dataService;
|
||||
}
|
||||
|
||||
@GetMapping(GET_MAX_ID)
|
||||
public Result<String> getAllDataId(@RequestParam int type) {
|
||||
BigInteger maxId = dataService.getMaxId(Constants.getClass(type));
|
||||
return Result.ok("", Objects.nonNull(maxId) ? maxId.toString() : "0");
|
||||
}
|
||||
|
||||
@PostMapping(SAVE_DATA)
|
||||
public Result<Void> saveData(@RequestParam int type, @RequestBody String json) throws JsonProcessingException {
|
||||
Class<? extends IdAware> clz = Constants.getClass(type);
|
||||
Objects.requireNonNull(clz, "No type match.");
|
||||
dataService.saveData(clz, json);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.renkang.sync.entity;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
public interface IdAware {
|
||||
|
||||
BigInteger getId();
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.renkang.sync.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @Name IndoorEnvironmentData
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午2:02
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "indoor_environment_data")
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public class IndoorEnvironmentData implements IdAware, Serializable {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private BigInteger id;
|
||||
@Column(name = "meter_code")
|
||||
private String meterCode;
|
||||
@Column(name = "read_time")
|
||||
private Integer readTime;
|
||||
@Column(name = "insert_time")
|
||||
private Integer insertTime;
|
||||
@Column(name = "temperature")
|
||||
private BigDecimal temperature;
|
||||
@Column(name = "humidity")
|
||||
private BigDecimal humidity;
|
||||
@Column(name = "carbon_dioxide")
|
||||
private BigDecimal carbonDioxide;
|
||||
@Column(name = "pm25")
|
||||
private BigDecimal pm25;
|
||||
@Column(name = "pm10")
|
||||
private BigDecimal pm10;
|
||||
@Column(name = "hcho")
|
||||
private BigDecimal hcho;
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
|
||||
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
|
||||
if (thisEffectiveClass != oEffectiveClass) {
|
||||
return false;
|
||||
}
|
||||
IndoorEnvironmentData that = (IndoorEnvironmentData) o;
|
||||
return getId() != null && Objects.equals(getId(), that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.renkang.sync.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @Name OutdoorEnvironmentData
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午2:05
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "outdoor_environment_data")
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public class OutdoorEnvironmentData implements IdAware, Serializable {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private BigInteger id;
|
||||
@Column(name = "meter_code")
|
||||
private String meterCode;
|
||||
@Column(name = "read_time")
|
||||
private Integer readTime;
|
||||
@Column(name = "insert_time")
|
||||
private Integer insertTime;
|
||||
@Column(name = "temperature")
|
||||
private BigDecimal temperature;
|
||||
@Column(name = "humidity")
|
||||
private BigDecimal humidity;
|
||||
@Column(name = "pm25")
|
||||
private BigDecimal pm25;
|
||||
@Column(name = "pm10")
|
||||
private BigDecimal pm10;
|
||||
@Column(name = "illuminance")
|
||||
private BigDecimal illuminance;
|
||||
@Column(name = "wind_speed")
|
||||
private BigDecimal windSpeed;
|
||||
@Column(name = "wind_direction")
|
||||
private Integer windDirection;
|
||||
@Column(name = "rs_ra")
|
||||
private BigDecimal rsRa;
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
|
||||
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
|
||||
if (thisEffectiveClass != oEffectiveClass) {
|
||||
return false;
|
||||
}
|
||||
OutdoorEnvironmentData that = (OutdoorEnvironmentData) o;
|
||||
return getId() != null && Objects.equals(getId(), that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.renkang.sync.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @Name PollenData
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午1:46
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "pollen_data")
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public class PollenData implements IdAware, Serializable {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private BigInteger id;
|
||||
@Column(name = "meter_code")
|
||||
private String meterCode;
|
||||
@Column(name = "read_time")
|
||||
private Integer readTime;
|
||||
@Column(name = "insert_time")
|
||||
private Integer insertTime;
|
||||
@Column(name = "one")
|
||||
private Integer one;
|
||||
@Column(name = "two")
|
||||
private Integer two;
|
||||
@Column(name = "three")
|
||||
private Integer three;
|
||||
@Column(name = "four")
|
||||
private Integer four;
|
||||
@Column(name = "five")
|
||||
private Integer five;
|
||||
@Column(name = "six")
|
||||
private Integer six;
|
||||
@Column(name = "temperature")
|
||||
private BigDecimal temperature;
|
||||
@Column(name = "humidity")
|
||||
private BigDecimal humidity;
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
|
||||
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
|
||||
if (thisEffectiveClass != oEffectiveClass) {
|
||||
return false;
|
||||
}
|
||||
PollenData that = (PollenData) o;
|
||||
return getId() != null && Objects.equals(getId(), that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.renkang.sync.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "remote_weight_manufacturer_lefu")
|
||||
public class RemoteWeightManufacturerLefu {
|
||||
@Id
|
||||
@Size(max = 32)
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "snow_flake_generator")
|
||||
@GenericGenerator(name = "snow_flake_generator", strategy = "com.renkang.sync.util.SnowFlakeIdGenerator")
|
||||
@Column(name = "id", nullable = false, length = 32)
|
||||
private String id;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "device_sn", length = 32)
|
||||
private String deviceSn;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "device_type", length = 32)
|
||||
private String deviceType;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "device_mac", length = 32)
|
||||
private String deviceMac;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "device_charge", length = 32)
|
||||
private String deviceCharge;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "device_impedance", length = 32)
|
||||
private String deviceImpedance;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "wifi_version", length = 32)
|
||||
private String wifiVersion;
|
||||
|
||||
@Size(max = 32)
|
||||
@Column(name = "firmware_version", length = 32)
|
||||
private String firmwareVersion;
|
||||
|
||||
@Column(name = "data_time")
|
||||
private Date dataTime;
|
||||
|
||||
@Column(name = "weight", precision = 6, scale = 2)
|
||||
private BigDecimal weight;
|
||||
|
||||
@Column(name = "heart_rate")
|
||||
private Integer heartRate;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.renkang.sync.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @Name WaterQualityData
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午2:41
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "water_quality_data")
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public class WaterQualityData implements IdAware, Serializable {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private BigInteger id;
|
||||
@Column(name = "meter_code")
|
||||
private String meterCode;
|
||||
@Column(name = "insert_time")
|
||||
private Integer insertTime;
|
||||
@Column(name = "read_time")
|
||||
private Integer readTime;
|
||||
@Column(name = "temperature")
|
||||
private BigDecimal temperature;
|
||||
@Column(name = "conductivity")
|
||||
private BigDecimal conductivity;
|
||||
@Column(name = "turbidity")
|
||||
private BigDecimal turbidity;
|
||||
@Column(name = "residual_chlorine")
|
||||
private BigDecimal residualChlorine;
|
||||
@Column(name = "ph")
|
||||
private BigDecimal ph;
|
||||
@Column(name = "salinity")
|
||||
private BigDecimal salinity;
|
||||
@Column(name = "resistivity")
|
||||
private BigDecimal resistivity;
|
||||
@Column(name = "tds")
|
||||
private BigDecimal tds;
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
|
||||
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
|
||||
if (thisEffectiveClass != oEffectiveClass) {
|
||||
return false;
|
||||
}
|
||||
WaterQualityData that = (WaterQualityData) o;
|
||||
return getId() != null && Objects.equals(getId(), that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.renkang.sync.repository;
|
||||
|
||||
import com.renkang.sync.entity.IdAware;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
public interface BaseRepository<T extends IdAware> extends JpaRepository<T, BigInteger> {
|
||||
|
||||
/**
|
||||
* 根据起始ID查询分页数据
|
||||
*
|
||||
* @param id 起始ID
|
||||
* @param pageable 分页参数
|
||||
* @return 分页数据
|
||||
*/
|
||||
Page<T> findByIdGreaterThan(BigInteger id, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 查询所有数据并返回 ID 最大的 BigInteger
|
||||
*
|
||||
* @return 最大ID值
|
||||
*/
|
||||
BigInteger findMaxId();
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.renkang.sync.repository;
|
||||
|
||||
import com.renkang.sync.entity.IndoorEnvironmentData;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @Name IndoorRepository
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午4:52
|
||||
*/
|
||||
@Repository
|
||||
public interface IndoorRepository extends BaseRepository<IndoorEnvironmentData> {
|
||||
|
||||
/**
|
||||
* 查询所有数据并返回 ID 最大的 BigInteger
|
||||
*
|
||||
* @return 最大ID值
|
||||
*/
|
||||
@Override
|
||||
@Query("SELECT MAX(id) FROM IndoorEnvironmentData")
|
||||
BigInteger findMaxId();
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.renkang.sync.repository;
|
||||
|
||||
import com.renkang.sync.entity.RemoteWeightManufacturerLefu;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Repository
|
||||
public interface LefuRepository extends JpaRepository<RemoteWeightManufacturerLefu, String> {
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.renkang.sync.repository;
|
||||
|
||||
import com.renkang.sync.entity.OutdoorEnvironmentData;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @Name OutdoorRepository
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午4:57
|
||||
*/
|
||||
@Repository
|
||||
public interface OutdoorRepository extends BaseRepository<OutdoorEnvironmentData> {
|
||||
|
||||
/**
|
||||
* 查询所有数据并返回 ID 最大的 BigInteger
|
||||
*
|
||||
* @return 最大ID值
|
||||
*/
|
||||
@Override
|
||||
@Query("SELECT MAX(id) FROM OutdoorEnvironmentData")
|
||||
BigInteger findMaxId();
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.renkang.sync.repository;
|
||||
|
||||
import com.renkang.sync.entity.PollenData;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @Name PollenRepository
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午4:58
|
||||
*/
|
||||
@Repository
|
||||
public interface PollenRepository extends BaseRepository<PollenData> {
|
||||
|
||||
/**
|
||||
* 查询所有数据并返回 ID 最大的 BigInteger
|
||||
*
|
||||
* @return 最大ID值
|
||||
*/
|
||||
@Override
|
||||
@Query("SELECT MAX(id) FROM PollenData")
|
||||
BigInteger findMaxId();
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.renkang.sync.repository;
|
||||
|
||||
import com.renkang.sync.entity.WaterQualityData;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @Name WaterRepository
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/25下午4:59
|
||||
*/
|
||||
@Repository
|
||||
public interface WaterRepository extends BaseRepository<WaterQualityData> {
|
||||
|
||||
/**
|
||||
* 查询所有数据并返回 ID 最大的 BigInteger
|
||||
*
|
||||
* @return 最大ID值
|
||||
*/
|
||||
@Override
|
||||
@Query("SELECT MAX(id) FROM WaterQualityData")
|
||||
BigInteger findMaxId();
|
||||
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package com.renkang.sync.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.renkang.sync.entity.*;
|
||||
import com.renkang.sync.repository.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @Name DataService
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/26下午3:41
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DataService {
|
||||
|
||||
private IndoorRepository indoorRepository;
|
||||
|
||||
private OutdoorRepository outdoorRepository;
|
||||
|
||||
private PollenRepository pollenRepository;
|
||||
|
||||
private WaterRepository waterRepository;
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
public void setIndoorRepository(IndoorRepository indoorRepository) {
|
||||
this.indoorRepository = indoorRepository;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setOutdoorRepository(OutdoorRepository outdoorRepository) {
|
||||
this.outdoorRepository = outdoorRepository;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setPollenRepository(PollenRepository pollenRepository) {
|
||||
this.pollenRepository = pollenRepository;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setWaterRepository(WaterRepository waterRepository) {
|
||||
this.waterRepository = waterRepository;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setObjectMapper(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IdAware> Page<T> getPagedDate(Class<T> clz, BigInteger start, Pageable pageable) {
|
||||
if (clz.equals(IndoorEnvironmentData.class)) {
|
||||
return (Page<T>) indoorRepository.findByIdGreaterThan(start, pageable);
|
||||
} else if (clz.equals(OutdoorEnvironmentData.class)) {
|
||||
return (Page<T>) outdoorRepository.findByIdGreaterThan(start, pageable);
|
||||
} else if (clz.equals(PollenData.class)) {
|
||||
return (Page<T>) pollenRepository.findByIdGreaterThan(start, pageable);
|
||||
} else if (clz.equals(WaterQualityData.class)) {
|
||||
return (Page<T>) waterRepository.findByIdGreaterThan(start, pageable);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void saveData(Class<? extends IdAware> clz, String json) throws JsonProcessingException {
|
||||
if (clz.equals(IndoorEnvironmentData.class)) {
|
||||
JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, IndoorEnvironmentData.class);
|
||||
List<IndoorEnvironmentData> data = objectMapper.readValue(json, javaType);
|
||||
save(indoorRepository, data);
|
||||
} else if (clz.equals(OutdoorEnvironmentData.class)) {
|
||||
JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, OutdoorEnvironmentData.class);
|
||||
List<OutdoorEnvironmentData> data = objectMapper.readValue(json, javaType);
|
||||
save(outdoorRepository, data);
|
||||
} else if (clz.equals(PollenData.class)) {
|
||||
JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, PollenData.class);
|
||||
List<PollenData> data = objectMapper.readValue(json, javaType);
|
||||
save(pollenRepository, data);
|
||||
} else if (clz.equals(WaterQualityData.class)) {
|
||||
JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, WaterQualityData.class);
|
||||
List<WaterQualityData> data = objectMapper.readValue(json, javaType);
|
||||
save(waterRepository, data);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends IdAware> void save(BaseRepository<T> repository, List<T> data) {
|
||||
repository.saveAll(data);
|
||||
}
|
||||
|
||||
public BigInteger getMaxId(Class<?> clz) {
|
||||
BaseRepository<? extends IdAware> repository = getRepository(clz);
|
||||
Objects.requireNonNull(repository, "No repository match.");
|
||||
return repository.findMaxId();
|
||||
}
|
||||
|
||||
private BaseRepository<? extends IdAware> getRepository(Class<?> clz) {
|
||||
if (clz == null) {
|
||||
return null;
|
||||
}
|
||||
if (clz.equals(IndoorEnvironmentData.class)) {
|
||||
return indoorRepository;
|
||||
} else if (clz.equals(OutdoorEnvironmentData.class)) {
|
||||
return outdoorRepository;
|
||||
} else if (clz.equals(PollenData.class)) {
|
||||
return pollenRepository;
|
||||
} else if (clz.equals(WaterQualityData.class)) {
|
||||
return waterRepository;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package com.renkang.sync.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import com.renkang.sync.bean.Result;
|
||||
import com.renkang.sync.bean.lefu.BatchRecord;
|
||||
import com.renkang.sync.bean.lefu.Record;
|
||||
import com.renkang.sync.config.LefuProperties;
|
||||
import com.renkang.sync.entity.RemoteWeightManufacturerLefu;
|
||||
import com.renkang.sync.repository.LefuRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class LefuService {
|
||||
|
||||
public static final String X_ACCESS_TOKEN = "X-Access-Token";
|
||||
public static String PUSH_DATA = "/remote/data/device/weighing/lefu/sync";
|
||||
public static String CHECK_TOKEN = "/sys/checkToken";
|
||||
public static String GET_TOKEN = "/sys/thirdLogin";
|
||||
private final Map<String, String> tokenMap = new ConcurrentHashMap<>();
|
||||
private final ObjectMapper objectMapper;
|
||||
private LefuRepository lefuRepository;
|
||||
private LefuProperties lefuProperties;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public LefuService() {
|
||||
objectMapper = new ObjectMapper();
|
||||
//处理bigDecimal
|
||||
objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
|
||||
objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
|
||||
//处理失败
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, false);
|
||||
//默认的处理日期时间格式
|
||||
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
objectMapper.registerModule(javaTimeModule);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setRestTemplate(RestTemplate restTemplate) {
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setLefuProperties(LefuProperties lefuProperties) {
|
||||
this.lefuProperties = lefuProperties;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setLefuRepository(LefuRepository lefuRepository) {
|
||||
this.lefuRepository = lefuRepository;
|
||||
}
|
||||
|
||||
@Async
|
||||
public void sync(List<RemoteWeightManufacturerLefu> data) throws JsonProcessingException {
|
||||
Map<String, LefuProperties.Service> sync = lefuProperties.getSync();
|
||||
for (Map.Entry<String, LefuProperties.Service> entry : sync.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
LefuProperties.Service service = entry.getValue();
|
||||
String url = service.getBaseUrl() + PUSH_DATA;
|
||||
ResponseEntity<Result<Void>> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(objectMapper.writeValueAsString(data), getHeaders(name, service)),
|
||||
new ParameterizedTypeReference<Result<Void>>() {
|
||||
});
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)
|
||||
|| ObjectUtils.isEmpty(response.getBody())
|
||||
|| !response.getBody().isSuccess()) {
|
||||
throw new RuntimeException("Push Lefu Data Error remotely");
|
||||
}
|
||||
log.info("Push Lefu Success {} for {}", data.size(), name);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders(String name, LefuProperties.Service service) throws JsonProcessingException {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.add(X_ACCESS_TOKEN, getToken(name, service));
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
private String getToken(String name, LefuProperties.Service service) throws JsonProcessingException {
|
||||
String token = tokenMap.get(name);
|
||||
if (StrUtil.isBlank(token)) {
|
||||
remoteToken(name, service);
|
||||
} else {
|
||||
if (!checkToken(token, service)) {
|
||||
remoteToken(name, service);
|
||||
}
|
||||
}
|
||||
return tokenMap.get(name);
|
||||
}
|
||||
|
||||
private void remoteToken(String name, LefuProperties.Service service) throws JsonProcessingException {
|
||||
Map<String, String> data = new HashMap<>();
|
||||
data.put("username", service.getUsername());
|
||||
data.put("password", service.getPassword());
|
||||
String url = service.getBaseUrl() + GET_TOKEN;
|
||||
ResponseEntity<Result<Map<String, String>>> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(objectMapper.writeValueAsString(data)),
|
||||
new ParameterizedTypeReference<Result<Map<String, String>>>() {
|
||||
});
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)
|
||||
|| ObjectUtils.isEmpty(response.getBody())
|
||||
|| !response.getBody().isSuccess()) {
|
||||
throw new RuntimeException("Get Token Error remotely");
|
||||
}
|
||||
String token = response.getBody().getResult().get("token");
|
||||
tokenMap.put(name, token);
|
||||
}
|
||||
|
||||
private boolean checkToken(String token, LefuProperties.Service service) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.add(X_ACCESS_TOKEN, token);
|
||||
String url = service.getBaseUrl() + CHECK_TOKEN;
|
||||
ResponseEntity<Result<Void>> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(httpHeaders),
|
||||
new ParameterizedTypeReference<Result<Void>>() {
|
||||
});
|
||||
return response.getStatusCode().equals(HttpStatus.OK)
|
||||
&& !ObjectUtils.isEmpty(response.getBody())
|
||||
&& response.getBody().isSuccess();
|
||||
}
|
||||
|
||||
public RemoteWeightManufacturerLefu record(Record record) {
|
||||
return lefuRepository.save(record.toRemoteEntity());
|
||||
}
|
||||
|
||||
public List<RemoteWeightManufacturerLefu> batchRecord(BatchRecord batchRecord) {
|
||||
return lefuRepository.saveAll(batchRecord.toRemoteEntities());
|
||||
}
|
||||
|
||||
public Page<RemoteWeightManufacturerLefu> list(Integer pageNo, Integer pageSize) {
|
||||
Pageable pageable = PageRequest.of(pageNo, pageSize).withSort(Sort.by(Sort.Order.desc("createTime")));
|
||||
return lefuRepository.findAll(pageable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
package com.renkang.sync.task;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.renkang.sync.bean.Result;
|
||||
import com.renkang.sync.config.SyncProperties;
|
||||
import com.renkang.sync.entity.*;
|
||||
import com.renkang.sync.service.DataService;
|
||||
import com.renkang.sync.util.Constants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import static com.renkang.sync.util.Constants.*;
|
||||
|
||||
/**
|
||||
* @Name SyncTask
|
||||
* @Author YangYuanChen
|
||||
* @Data 20242024/7/29下午7:45
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@ConditionalOnProperty(prefix = "spring.cloud.nacos.discovery", name = "enabled", havingValue = "false", matchIfMissing = true)
|
||||
public class SyncTask {
|
||||
|
||||
private static final int[] TYPES = new int[]{
|
||||
INDOOR,
|
||||
OUTDOOR,
|
||||
POLLEN,
|
||||
WATER
|
||||
};
|
||||
private DataService dataService;
|
||||
private SyncProperties syncProperties;
|
||||
private RestTemplate restTemplate;
|
||||
private TaskScheduler schedulingTaskExecutor;
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
public void setDataService(DataService dataService) {
|
||||
this.dataService = dataService;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setSyncProperties(SyncProperties syncProperties) {
|
||||
this.syncProperties = syncProperties;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setRestTemplate(RestTemplate restTemplate) {
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setSchedulingTaskExecutor(TaskScheduler schedulingTaskExecutor) {
|
||||
this.schedulingTaskExecutor = schedulingTaskExecutor;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setObjectMapper(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
String cron = syncProperties.getCron();
|
||||
CronTrigger trigger = new CronTrigger(cron);
|
||||
for (String baseUrl : syncProperties.getBaseUrls()) {
|
||||
log.info("Add schedule task for base: {}", baseUrl);
|
||||
schedulingTaskExecutor.schedule(() -> {
|
||||
try {
|
||||
run(baseUrl);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}, trigger);
|
||||
}
|
||||
}
|
||||
|
||||
private void run(String baseUrl) throws JsonProcessingException {
|
||||
for (int type : TYPES) {
|
||||
try {
|
||||
BigInteger remoteMaxId = getRemoteMaxId(baseUrl, type);
|
||||
BigInteger localMaxId = getLocalMaxId(type);
|
||||
log.info("MaxId for base {} is: {}", baseUrl, remoteMaxId);
|
||||
if (remoteMaxId.compareTo(localMaxId) >= 0) {
|
||||
log.info("remote base {} is up-to-date", baseUrl);
|
||||
continue;
|
||||
}
|
||||
pushData(baseUrl, remoteMaxId, type);
|
||||
} catch (Exception e) {
|
||||
log.error("Error has occurred for base {} and type {}", baseUrl, type, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BigInteger getRemoteMaxId(String baseUrl, int type) {
|
||||
String url = getUrl(baseUrl, type, GET_MAX_ID);
|
||||
ResponseEntity<Result<String>> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
HttpEntity.EMPTY,
|
||||
new ParameterizedTypeReference<Result<String>>() {
|
||||
});
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)
|
||||
|| ObjectUtils.isEmpty(response.getBody())
|
||||
|| !StringUtils.hasText(response.getBody().getResult())) {
|
||||
errorLog(response);
|
||||
throw new RuntimeException("Get maxId Error remotely");
|
||||
}
|
||||
return new BigInteger(response.getBody().getResult());
|
||||
}
|
||||
|
||||
private BigInteger getLocalMaxId(int type) {
|
||||
BigInteger maxId = dataService.getMaxId(Constants.getClass(type));
|
||||
if (ObjectUtils.isEmpty(maxId)) {
|
||||
throw new RuntimeException("Get maxId Error locally");
|
||||
}
|
||||
return maxId;
|
||||
}
|
||||
|
||||
private void pushData(String baseUrl, BigInteger start, int type) throws JsonProcessingException {
|
||||
Pageable pageable = pageableInstance();
|
||||
Page<?> pagedData;
|
||||
boolean first = true;
|
||||
do {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
pageable = pageable.next();
|
||||
}
|
||||
pagedData = getPagedData(start, type, pageable);
|
||||
if (pagedData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
remotePush(baseUrl, pagedData.getContent(), type);
|
||||
} while (pagedData.hasNext());
|
||||
}
|
||||
|
||||
private Pageable pageableInstance() {
|
||||
Sort sort = Sort.by(Sort.Order.asc(ID_FIELD));
|
||||
return PageRequest.of(0, syncProperties.getSize(), sort);
|
||||
}
|
||||
|
||||
private <T extends IdAware> Page<T> getPagedData(BigInteger start, Class<T> clz, Pageable pageable) {
|
||||
return dataService.getPagedDate(clz, start, pageable);
|
||||
}
|
||||
|
||||
private Page<?> getPagedData(BigInteger start, int type, Pageable pageable) {
|
||||
if (type == INDOOR) {
|
||||
return getPagedData(start, IndoorEnvironmentData.class, pageable);
|
||||
} else if (type == OUTDOOR) {
|
||||
return getPagedData(start, OutdoorEnvironmentData.class, pageable);
|
||||
} else if (type == POLLEN) {
|
||||
return getPagedData(start, PollenData.class, pageable);
|
||||
} else if (type == WATER) {
|
||||
return getPagedData(start, WaterQualityData.class, pageable);
|
||||
} else {
|
||||
throw new RuntimeException("Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
private void remotePush(String baseUrl, List<?> data, int type) throws JsonProcessingException {
|
||||
String url = getUrl(baseUrl, type, SAVE_DATA);
|
||||
ResponseEntity<Result<Void>> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(objectMapper.writeValueAsString(data)),
|
||||
new ParameterizedTypeReference<Result<Void>>() {
|
||||
});
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)
|
||||
|| ObjectUtils.isEmpty(response.getBody())
|
||||
|| !response.getBody().isSuccess()) {
|
||||
errorLog(response);
|
||||
throw new RuntimeException("Push Data Error remotely");
|
||||
}
|
||||
log.info("Push Success {} for type {}", data.size(), type);
|
||||
}
|
||||
|
||||
private void errorLog(ResponseEntity<?> response) {
|
||||
log.error("MaxId HttpCode: {}", response.getStatusCodeValue());
|
||||
log.error("MaxId Response: {}", response.getBody());
|
||||
}
|
||||
|
||||
private String getUrl(String baseUrl, int type, String api) {
|
||||
return UriComponentsBuilder.fromHttpUrl(baseUrl + api)
|
||||
.queryParam(TYPE_PARAM, type)
|
||||
.encode()
|
||||
.toUriString();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.renkang.sync.util;
|
||||
|
||||
import com.renkang.sync.entity.*;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
public interface Constants {
|
||||
|
||||
int INDOOR = 1;
|
||||
|
||||
int OUTDOOR = 2;
|
||||
|
||||
int POLLEN = 3;
|
||||
|
||||
int WATER = 4;
|
||||
|
||||
String TYPE_PARAM = "type";
|
||||
|
||||
String ID_FIELD = "id";
|
||||
|
||||
String GET_MAX_ID = "/maxId";
|
||||
String SAVE_DATA = "/saveData";
|
||||
|
||||
/**
|
||||
* 根据字典类型返回对应的类
|
||||
*
|
||||
* @param type 类型
|
||||
* @return 实体类
|
||||
*/
|
||||
static Class<? extends IdAware> getClass(int type) {
|
||||
switch (type) {
|
||||
case INDOOR:
|
||||
return IndoorEnvironmentData.class;
|
||||
case OUTDOOR:
|
||||
return OutdoorEnvironmentData.class;
|
||||
case POLLEN:
|
||||
return PollenData.class;
|
||||
case WATER:
|
||||
return WaterQualityData.class;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.renkang.sync.util;
|
||||
|
||||
import cn.hutool.core.lang.Snowflake;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
@Slf4j
|
||||
public class SnowFlakeIdGenerator implements IdentifierGenerator {
|
||||
|
||||
private final Snowflake snowFlake;
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
public SnowFlakeIdGenerator() {
|
||||
this.snowFlake = IdUtil.getSnowflake();
|
||||
}
|
||||
|
||||
public synchronized long snowflakeId() {
|
||||
return snowFlake.nextId();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable generate(SharedSessionContractImplementor session, Object object)
|
||||
throws HibernateException {
|
||||
long id = snowflakeId();
|
||||
if (Long.class.isAssignableFrom(type)) {
|
||||
return id;
|
||||
} else if (String.class.isAssignableFrom(type)) {
|
||||
return Long.toString(id);
|
||||
} else if (byte[].class.isAssignableFrom(type)) {
|
||||
return Long.toUnsignedString(id).getBytes();
|
||||
} else {
|
||||
throw new HibernateException("Unanticipated return type [" + type.getName() + "] for ID conversion");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
|
||||
this.type = type.getReturnedClass();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
PROFILE_NAME=dev
|
||||
SERVER_PORT=27002
|
||||
NACOS_SERVER_ADDR=nacos.yg.dt.io:80
|
||||
NACOS_USERNAME=cqyt
|
||||
NACOS_PASSWORD=Aa123456
|
||||
NACOS_NAMESPACE=2639a2d4-7b64-4408-98c9-b97e0bdf4c1f
|
||||
NACOS_GROUP=dev
|
||||
NACOS_ENABLE=false
|
||||
@@ -0,0 +1,27 @@
|
||||
server:
|
||||
port: ${SERVER_PORT:27001}
|
||||
spring:
|
||||
application:
|
||||
name: env-sync
|
||||
config:
|
||||
import:
|
||||
- optional:nacos:${spring.application.name}-${PROFILE_NAME}.yaml
|
||||
cloud:
|
||||
nacos:
|
||||
server-addr: ${NACOS_SERVER_ADDR}
|
||||
username: ${NACOS_USERNAME:nacos}
|
||||
password: ${NACOS_PASSWORD:nacos}
|
||||
config:
|
||||
enabled: true
|
||||
namespace: ${NACOS_NAMESPACE:}
|
||||
group: ${NACOS_GROUP:DEFAULT_GROUP}
|
||||
server-addr: ${spring.cloud.nacos.server-addr}
|
||||
username: ${spring.cloud.nacos.username}
|
||||
password: ${spring.cloud.nacos.password}
|
||||
discovery:
|
||||
enabled: ${NACOS_ENABLE:false}
|
||||
namespace: ${NACOS_NAMESPACE:}
|
||||
group: ${NACOS_GROUP:DEFAULT_GROUP}
|
||||
server-addr: ${spring.cloud.nacos.server-addr}
|
||||
username: ${spring.cloud.nacos.username}
|
||||
password: ${spring.cloud.nacos.password}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-parent</artifactId>
|
||||
<version>4.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>renkang-starter-batch</module>
|
||||
<module>renkang-starter-aspose-word</module>
|
||||
<module>data-center-api</module>
|
||||
<module>font-resources</module>
|
||||
<module>monitoring-sync</module>
|
||||
<module>renkang-test</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>renkang-starter-aspose-word</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.aspose</groupId>
|
||||
<artifactId>aspose-words</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.renkang.aspose.configure;
|
||||
|
||||
import com.aspose.words.*;
|
||||
import com.renkang.aspose.util.DocConvertUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/29
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(AsposeWordProperties.class)
|
||||
@Slf4j
|
||||
public class AsposeAutoConfiguration {
|
||||
|
||||
private final AsposeWordProperties properties;
|
||||
|
||||
public AsposeAutoConfiguration(AsposeWordProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public License license() throws Exception {
|
||||
License license = new License();
|
||||
ClassPathResource resource = new ClassPathResource("license.xml");
|
||||
license.setLicense(resource.getInputStream());
|
||||
log.info("加载Aspose License成功");
|
||||
return license;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoadOptions loadOptions() throws IOException {
|
||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource[] resources = resolver.getResources(properties.getFontLocation());
|
||||
FontSourceBase[] fonts = Stream.of(resources)
|
||||
.map(resource -> {
|
||||
try {
|
||||
if (!isFont(resource)) {
|
||||
return null;
|
||||
}
|
||||
log.info("加载字体{}", resource.getFilename());
|
||||
byte[] bytes = StreamUtils.copyToByteArray(resource.getInputStream());
|
||||
return new MemoryFontSource(bytes);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(FontSourceBase[]::new);
|
||||
LoadOptions loadOptions = new LoadOptions();
|
||||
FontSettings fontSettings = new FontSettings();
|
||||
fontSettings.setFontsSources(fonts);
|
||||
loadOptions.setFontSettings(fontSettings);
|
||||
DocConvertUtil.setLoadOptions(loadOptions);
|
||||
return loadOptions;
|
||||
}
|
||||
|
||||
private boolean isFont(Resource resource) {
|
||||
String filename = resource.getFilename();
|
||||
if (!StringUtils.hasText(filename)) {
|
||||
return false;
|
||||
}
|
||||
int i = filename.lastIndexOf(".");
|
||||
if (i < 0) {
|
||||
return false;
|
||||
}
|
||||
String ext = filename.substring(i + 1);
|
||||
return "ttf".equalsIgnoreCase(ext)
|
||||
|| "ttc".equalsIgnoreCase(ext)
|
||||
|| "woff".equalsIgnoreCase(ext)
|
||||
|| "woff2".equalsIgnoreCase(ext)
|
||||
|| "oft".equalsIgnoreCase(ext);
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.renkang.aspose.configure;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/29
|
||||
*/
|
||||
@ConfigurationProperties("renkang.aspose")
|
||||
@Data
|
||||
public class AsposeWordProperties {
|
||||
|
||||
private String fontLocation = "classpath*:font/**/*";
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.renkang.aspose.util;
|
||||
|
||||
import com.aspose.words.Document;
|
||||
import com.aspose.words.LoadOptions;
|
||||
import com.aspose.words.SaveFormat;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/29
|
||||
*/
|
||||
public class DocConvertUtil {
|
||||
|
||||
private static LoadOptions loadOptions;
|
||||
|
||||
public static void setLoadOptions(LoadOptions loadOptions) {
|
||||
DocConvertUtil.loadOptions = loadOptions;
|
||||
}
|
||||
|
||||
public static boolean checkTraversal(String path) {
|
||||
return path.contains("..");
|
||||
}
|
||||
|
||||
public static void docxConvertPdfSaveLocalAspose(String docxPath, String pdfPath) throws Exception {
|
||||
if (checkTraversal(docxPath)) {
|
||||
throw new InvalidPathException(docxPath, "Illegal path symbol");
|
||||
}
|
||||
if (checkTraversal(pdfPath)) {
|
||||
throw new InvalidPathException(pdfPath, "Illegal path symbol");
|
||||
}
|
||||
//保存pdf
|
||||
//保存pdf
|
||||
try (
|
||||
InputStream ins = Files.newInputStream(Paths.get(docxPath));
|
||||
OutputStream outs = Files.newOutputStream(Paths.get(pdfPath));
|
||||
) {
|
||||
Document doc = new Document(ins, loadOptions);
|
||||
doc.save(outs, SaveFormat.PDF);
|
||||
//关流
|
||||
outs.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public static void docxConvertPdfSaveLocalAspose(Path docxPath, Path pdfPath) throws Exception {
|
||||
//保存pdf
|
||||
try (
|
||||
InputStream ins = Files.newInputStream(docxPath);
|
||||
OutputStream outs = Files.newOutputStream(pdfPath)
|
||||
) {
|
||||
Document doc = new Document(ins, loadOptions);
|
||||
doc.save(outs, SaveFormat.PDF);
|
||||
//关流
|
||||
outs.flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
com.renkang.aspose.configure.AsposeAutoConfiguration
|
||||
@@ -0,0 +1,15 @@
|
||||
<License>
|
||||
<Data>
|
||||
<Products>
|
||||
<Product>Aspose.Total for Java</Product>
|
||||
<Product>Aspose.Words for Java</Product>
|
||||
</Products>
|
||||
<EditionType>Enterprise</EditionType>
|
||||
<SubscriptionExpiry>20991231</SubscriptionExpiry>
|
||||
<LicenseExpiry>20991231</LicenseExpiry>
|
||||
<SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
|
||||
</Data>
|
||||
<Signature>
|
||||
sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=
|
||||
</Signature>
|
||||
</License>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>renkang-starter-batch</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-batch</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package com.renkang.batch.configure;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
|
||||
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
|
||||
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchDataSource;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchDataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.jdbc.support.JdbcTransactionManager;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/9
|
||||
*/
|
||||
@AutoConfiguration(
|
||||
before = {
|
||||
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class,
|
||||
DynamicDataSourceAutoConfiguration.class
|
||||
}
|
||||
)
|
||||
@EnableConfigurationProperties({RenkangBatchProperties.class, BatchProperties.class})
|
||||
@EnableBatchProcessing
|
||||
public class BatchAutoConfiguration {
|
||||
|
||||
private final BatchProperties batchProperties;
|
||||
|
||||
private final RenkangBatchProperties renkangBatchProperties;
|
||||
|
||||
private final DynamicDataSourceProperties dynamicDataSourceProperties;
|
||||
|
||||
public BatchAutoConfiguration(
|
||||
BatchProperties batchProperties,
|
||||
RenkangBatchProperties renkangBatchProperties,
|
||||
DynamicDataSourceProperties dynamicDataSourceProperties
|
||||
) {
|
||||
this.batchProperties = batchProperties;
|
||||
this.renkangBatchProperties = renkangBatchProperties;
|
||||
this.dynamicDataSourceProperties = dynamicDataSourceProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public PlatformTransactionManager bizTransactionManager(DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
|
||||
JdbcTransactionManager bizTransactionManager = new JdbcTransactionManager(dataSource);
|
||||
transactionManagerCustomizers.customize(bizTransactionManager);
|
||||
return bizTransactionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BatchConfigurer batchConfigurer(
|
||||
@BatchDataSource DataSource dataSource,
|
||||
TransactionManagerCustomizers transactionManagerCustomizers,
|
||||
@Qualifier("batchTaskExecutor") TaskExecutor taskExecutor) {
|
||||
return new CustomBatchConfigurer(batchProperties, dataSource, transactionManagerCustomizers, taskExecutor);
|
||||
}
|
||||
|
||||
@Bean("batchTaskExecutor")
|
||||
@ConditionalOnProperty(prefix = "renkang.batch", name = "async", havingValue = "true", matchIfMissing = false)
|
||||
public TaskExecutor asyncBatchTaskExecutor() {
|
||||
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
|
||||
taskExecutor.setCorePoolSize(16);
|
||||
taskExecutor.setThreadNamePrefix("Job-Pool-");
|
||||
taskExecutor.setMaxPoolSize(32);
|
||||
taskExecutor.setQueueCapacity(16);
|
||||
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
taskExecutor.afterPropertiesSet();
|
||||
return taskExecutor;
|
||||
}
|
||||
|
||||
@Bean("batchTaskExecutor")
|
||||
@ConditionalOnProperty(prefix = "renkang.batch", name = "async", havingValue = "false", matchIfMissing = true)
|
||||
public TaskExecutor syncBatchTaskExecutor() {
|
||||
return new SyncTaskExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource dataSource(List<DynamicDataSourceProvider> providers) {
|
||||
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
|
||||
dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
|
||||
dataSource.setStrict(dynamicDataSourceProperties.getStrict());
|
||||
dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
|
||||
dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
|
||||
dataSource.setSeata(dynamicDataSourceProperties.getSeata());
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "renkang.batch", name = "jdbc-url")
|
||||
@BatchDataSource
|
||||
public DataSource batchDataSource() {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl(renkangBatchProperties.getJdbcUrl());
|
||||
config.setUsername(renkangBatchProperties.getUsername());
|
||||
config.setPassword(renkangBatchProperties.getPassword());
|
||||
config.setDriverClassName(renkangBatchProperties.getDriverClassName());
|
||||
return new HikariDataSource(config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BatchDataSourceScriptDatabaseInitializer batchDataSourceInitializer(
|
||||
DataSource dataSource,
|
||||
@BatchDataSource ObjectProvider<DataSource> batchDataSource,
|
||||
BatchProperties properties
|
||||
) {
|
||||
return new BatchDataSourceScriptDatabaseInitializer(batchDataSource.getIfAvailable(() -> dataSource),
|
||||
properties.getJdbc());
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.renkang.batch.configure;
|
||||
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
|
||||
import org.springframework.boot.autoconfigure.batch.BasicBatchConfigurer;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchProperties;
|
||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/9
|
||||
*/
|
||||
public class CustomBatchConfigurer extends BasicBatchConfigurer {
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
/**
|
||||
* Create a new {@link BasicBatchConfigurer} instance.
|
||||
*
|
||||
* @param properties the batch properties
|
||||
* @param dataSource the underlying data source
|
||||
* @param transactionManagerCustomizers transaction manager customizers (or
|
||||
* {@code null})
|
||||
*/
|
||||
protected CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
|
||||
super(properties, dataSource, transactionManagerCustomizers);
|
||||
}
|
||||
|
||||
public CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers, TaskExecutor taskExecutor) {
|
||||
super(properties, dataSource, transactionManagerCustomizers);
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobLauncher createJobLauncher() throws Exception {
|
||||
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
|
||||
jobLauncher.setJobRepository(getJobRepository());
|
||||
if (taskExecutor != null) {
|
||||
jobLauncher.setTaskExecutor(taskExecutor);
|
||||
}
|
||||
jobLauncher.afterPropertiesSet();
|
||||
return jobLauncher;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.renkang.batch.configure;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/9
|
||||
*/
|
||||
@ConfigurationProperties("renkang.batch")
|
||||
@Data
|
||||
public class RenkangBatchProperties {
|
||||
|
||||
private String jdbcUrl;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String driverClassName;
|
||||
|
||||
private Integer writeSize = 100;
|
||||
|
||||
private boolean async = false;
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.renkang.batch.job;
|
||||
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2023/11/11
|
||||
*/
|
||||
public abstract class AbstractSimpleTasklet implements Tasklet {
|
||||
|
||||
private ExecutionContext jobExecutionContext;
|
||||
|
||||
private ExecutionContext stepExecutionContext;
|
||||
|
||||
/**
|
||||
* Task执行方法
|
||||
*
|
||||
* @return 返回 {@link ExitStatus#COMPLETED} 视为成功,其他均视为失败,将执行 {@link AbstractSimpleTasklet#onError(Throwable)} 方法
|
||||
*/
|
||||
public abstract ExitStatus doExecute();
|
||||
|
||||
/**
|
||||
* 任务执行失败时,执行的方法,可以是 {@link AbstractSimpleTasklet#doExecute()} 方法
|
||||
* 返回了失败或产生异常
|
||||
*
|
||||
* @param throwable 若返回了失败,则 {@link Throwable} 为null
|
||||
* @throws Exception 抛出的异常,可以抛出自定义异常
|
||||
*/
|
||||
public abstract void onError(Throwable throwable) throws Exception;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
setExecutionContext(contribution);
|
||||
try {
|
||||
ExitStatus exitStatus = doExecute();
|
||||
if (exitStatus == ExitStatus.COMPLETED) {
|
||||
return setComplete(contribution, chunkContext);
|
||||
} else {
|
||||
contribution.setExitStatus(exitStatus);
|
||||
onError(null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
onError(e);
|
||||
throw e;
|
||||
}
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
public ExecutionContext getJobExecutionContext() {
|
||||
return jobExecutionContext;
|
||||
}
|
||||
|
||||
private void setJobExecutionContext(StepContribution contribution) {
|
||||
jobExecutionContext = contribution.getStepExecution()
|
||||
.getJobExecution()
|
||||
.getExecutionContext();
|
||||
}
|
||||
|
||||
public ExecutionContext getStepExecutionContext() {
|
||||
return stepExecutionContext;
|
||||
}
|
||||
|
||||
private void setStepExecutionContext(StepContribution contribution) {
|
||||
stepExecutionContext = contribution.getStepExecution()
|
||||
.getExecutionContext();
|
||||
}
|
||||
|
||||
private void setExecutionContext(StepContribution contribution) {
|
||||
setJobExecutionContext(contribution);
|
||||
setStepExecutionContext(contribution);
|
||||
}
|
||||
|
||||
private RepeatStatus setComplete(StepContribution contribution, ChunkContext chunkContext) {
|
||||
contribution.setExitStatus(ExitStatus.COMPLETED);
|
||||
chunkContext.setComplete();
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
com.renkang.batch.configure.BatchAutoConfiguration
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.renkang</groupId>
|
||||
<artifactId>functional-modules</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>renkang-test</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.renkang;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.UnavailableSecurityManagerException;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.subject.support.SubjectThreadState;
|
||||
import org.apache.shiro.util.LifecycleUtils;
|
||||
import org.apache.shiro.util.ThreadState;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
|
||||
/**
|
||||
* @author Jiang Shunzhi
|
||||
*/
|
||||
public abstract class AbstractShiroTest {
|
||||
|
||||
private static ThreadState subjectThreadState;
|
||||
|
||||
public AbstractShiroTest() {
|
||||
}
|
||||
|
||||
private static void doClearSubject() {
|
||||
if (subjectThreadState != null) {
|
||||
subjectThreadState.clear();
|
||||
subjectThreadState = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static org.apache.shiro.mgt.SecurityManager getSecurityManager() {
|
||||
return SecurityUtils.getSecurityManager();
|
||||
}
|
||||
|
||||
protected static void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) {
|
||||
SecurityUtils.setSecurityManager(securityManager);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDownShiro() {
|
||||
doClearSubject();
|
||||
try {
|
||||
SecurityManager securityManager = getSecurityManager();
|
||||
LifecycleUtils.destroy(securityManager);
|
||||
} catch (UnavailableSecurityManagerException e) {
|
||||
//we don't care about this when cleaning up the test environment
|
||||
//(for example, maybe the subclass is a unit test and it didn't
|
||||
// need a SecurityManager instance because it was using only
|
||||
// mock Subject instances)
|
||||
}
|
||||
setSecurityManager(null);
|
||||
}
|
||||
|
||||
protected Subject getSubject() {
|
||||
return SecurityUtils.getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to set the currently executing {@link Subject} instance.
|
||||
*
|
||||
* @param subject the Subject instance
|
||||
*/
|
||||
protected void setSubject(Subject subject) {
|
||||
clearSubject();
|
||||
subjectThreadState = createThreadState(subject);
|
||||
subjectThreadState.bind();
|
||||
}
|
||||
|
||||
protected ThreadState createThreadState(Subject subject) {
|
||||
return new SubjectThreadState(subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears Shiro's thread state, ensuring the thread remains clean for future test execution.
|
||||
*/
|
||||
protected void clearSubject() {
|
||||
doClearSubject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.renkang;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import lombok.Getter;
|
||||
import org.apache.shiro.UnavailableSecurityManagerException;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.jeecg.common.api.CommonAPI;
|
||||
import org.jeecg.common.config.mqtoken.UserTokenContext;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.common.util.RedisUtil;
|
||||
import org.jeecg.common.util.TokenUtils;
|
||||
import org.jeecg.config.shiro.JwtToken;
|
||||
import org.jeecg.config.shiro.TokenThreadLocal;
|
||||
import org.jeecg.global.GlobalUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Shunzhi Jiang
|
||||
* @since 2024/11/9
|
||||
*/
|
||||
public abstract class AbstractTestSupport extends AbstractShiroTest {
|
||||
|
||||
|
||||
@Autowired
|
||||
@Getter
|
||||
private CommonAPI commonAPI;
|
||||
|
||||
@Autowired
|
||||
@Getter
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
protected Subject adminSubject() {
|
||||
Subject subject = new Subject.Builder().buildSubject();
|
||||
String temporaryToken = GlobalUtils.getTemporaryToken();
|
||||
TokenThreadLocal.setToken(temporaryToken);
|
||||
UserTokenContext.setToken(temporaryToken);
|
||||
subject.login(new JwtToken(temporaryToken));
|
||||
return subject;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
protected void setAdminSubject() {
|
||||
checkSecurityManager();
|
||||
setSubject(adminSubject());
|
||||
}
|
||||
|
||||
protected void checkSecurityManager() {
|
||||
try {
|
||||
getSecurityManager();
|
||||
} catch (UnavailableSecurityManagerException e) {
|
||||
setSecurityManager(applicationContext.getBean(SecurityManager.class));
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
protected void clearTokenCache() {
|
||||
String token = getToken();
|
||||
redisUtil.del(CommonConstant.FAKE_USER_KEY_PREFIX + token, CommonConstant.PREFIX_USER_TOKEN + token);
|
||||
TokenThreadLocal.clear();
|
||||
UserTokenContext.remove();
|
||||
}
|
||||
|
||||
protected String getToken() {
|
||||
return TokenThreadLocal.getToken();
|
||||
}
|
||||
|
||||
protected <T> T getBean(Class<T> clazz) {
|
||||
return applicationContext.getBean(clazz);
|
||||
}
|
||||
|
||||
protected void fakeUser(String userId) {
|
||||
LoginUser loginUserById = TokenUtils.getLoginUserById(userId, commonAPI, redisUtil);
|
||||
if (Objects.isNull(loginUserById)) {
|
||||
throw new RuntimeException("未获取到模拟用户数据");
|
||||
}
|
||||
Subject subject = getSubject();
|
||||
Object principal = subject.getPrincipal();
|
||||
BeanUtil.copyProperties(loginUserById, principal);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user