init
This commit is contained in:
4
logs/mqtt-config-api-api.log
Normal file
4
logs/mqtt-config-api-api.log
Normal file
@ -0,0 +1,4 @@
|
||||
2025-10-01 20:48:47.371 [http-nio-7999-exec-1] INFO c.x.m.c.ClimateThresholdController - getThresholdById id: 1, threshold: Optional.empty
|
||||
2025-10-01 20:50:35.861 [http-nio-7999-exec-5] INFO c.x.m.c.ClimateThresholdController - getThresholdById id: 1, threshold: Optional[com.xzzn.movecheck.repo.ClimateThreshold@9a18622]
|
||||
2025-10-01 20:56:13.467 [http-nio-7999-exec-3] INFO c.x.m.c.ClimateThresholdController - getThresholdById id: 1, threshold: Optional[com.xzzn.movecheck.repo.ClimateThreshold@54616eab]
|
||||
2025-10-01 20:59:12.931 [http-nio-7999-exec-8] INFO c.x.m.c.ClimateThresholdController - getThresholdById id: 1, threshold: Optional[com.xzzn.movecheck.repo.ClimateThreshold@3ed28f8d]
|
||||
68
pom.xml
Normal file
68
pom.xml
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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>
|
||||
|
||||
<groupId>com.xzzn</groupId>
|
||||
<artifactId>movecheck</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.5.15</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.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-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
<!-- HttpClient -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.83</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
15
src/main/java/com/xzzn/movecheck/MovecheckApplication.java
Normal file
15
src/main/java/com/xzzn/movecheck/MovecheckApplication.java
Normal file
@ -0,0 +1,15 @@
|
||||
package com.xzzn.movecheck;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MovecheckApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
SpringApplication.run(MovecheckApplication.class, args
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
25
src/main/java/com/xzzn/movecheck/config/CorsConfig.java
Normal file
25
src/main/java/com/xzzn/movecheck/config/CorsConfig.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.xzzn.movecheck.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins("*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(false) // 设置为false
|
||||
.maxAge(3600);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
// config/HttpClientConfig.java
|
||||
package com.xzzn.movecheck.config;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class HttpClientConfig {
|
||||
|
||||
@Bean
|
||||
public CloseableHttpClient closeableHttpClient() {
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(30000) // 连接超时30秒
|
||||
.setSocketTimeout(30000) // socket超时30秒
|
||||
.setConnectionRequestTimeout(30000) // 请求超时30秒
|
||||
.build();
|
||||
|
||||
return HttpClientBuilder.create()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.xzzn.movecheck.config;
|
||||
|
||||
import com.xzzn.movecheck.service.MqttMessageHandler;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
@Configuration
|
||||
public class MqttAutoConfiguration {
|
||||
|
||||
@Value("${mqtt.broker:tcp://localhost:1883}")
|
||||
private String broker;
|
||||
|
||||
@Value("${mqtt.clientId:springboot-mqtt-client}")
|
||||
private String clientId;
|
||||
|
||||
@Value("${mqtt.topics:HDYDCJ_01_DEVICE,HDYDCJ_01_UP}")
|
||||
private String[] topics;
|
||||
|
||||
@Value("${mqtt.qos:1,1}")
|
||||
private int[] qos;
|
||||
|
||||
private MqttClient mqttClient;
|
||||
|
||||
@Bean
|
||||
public MqttConnectOptions mqttConnectOptions() {
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setServerURIs(new String[]{broker});
|
||||
options.setCleanSession(true);
|
||||
options.setConnectionTimeout(10);
|
||||
options.setKeepAliveInterval(20);
|
||||
options.setAutomaticReconnect(true);
|
||||
options.setMaxReconnectDelay(5000);
|
||||
options.setUserName("dmbroker");
|
||||
options.setPassword("qwer1234".toCharArray());
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MqttClient mqttClient(MqttConnectOptions options, MqttMessageHandler messageHandler)
|
||||
throws MqttException {
|
||||
mqttClient = new MqttClient(broker, clientId, new MemoryPersistence());
|
||||
|
||||
// 设置回调
|
||||
mqttClient.setCallback(messageHandler);
|
||||
|
||||
// 连接
|
||||
mqttClient.connect(options);
|
||||
System.out.println("MQTT客户端连接成功");
|
||||
|
||||
// 订阅主题
|
||||
if (topics != null && topics.length > 0) {
|
||||
mqttClient.subscribe(topics, qos);
|
||||
for (String topic : topics) {
|
||||
System.out.println("已订阅主题: " + topic);
|
||||
}
|
||||
}
|
||||
|
||||
return mqttClient;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
if (mqttClient != null && mqttClient.isConnected()) {
|
||||
try {
|
||||
mqttClient.disconnect();
|
||||
mqttClient.close();
|
||||
System.out.println("MQTT客户端已断开连接");
|
||||
} catch (MqttException e) {
|
||||
System.err.println("关闭MQTT客户端时出错: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/main/java/com/xzzn/movecheck/config/UserConfig.java
Normal file
18
src/main/java/com/xzzn/movecheck/config/UserConfig.java
Normal file
@ -0,0 +1,18 @@
|
||||
// UserConfig.java
|
||||
package com.xzzn.movecheck.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class UserConfig {
|
||||
private String username = "admin";
|
||||
private String password = "123456";
|
||||
|
||||
// Getter和Setter
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
}
|
||||
149
src/main/java/com/xzzn/movecheck/repo/AlertData.java
Normal file
149
src/main/java/com/xzzn/movecheck/repo/AlertData.java
Normal file
@ -0,0 +1,149 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "alert_data")
|
||||
public class AlertData {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "content", nullable = false, length = 1000)
|
||||
private String content; // 告警内容
|
||||
|
||||
@Column(name = "category", nullable = false)
|
||||
private String category; // 告警种类
|
||||
|
||||
@Column(name = "alert_time", nullable = false)
|
||||
private LocalDateTime alertTime; // 告警时间
|
||||
|
||||
@Column(name = "level", nullable = false)
|
||||
private String level; // 告警级别
|
||||
|
||||
@Column(name = "action")
|
||||
private String action; // 处置措施
|
||||
|
||||
@Column(name = "action_time")
|
||||
private LocalDateTime actionTime; // 处置时间
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime; // 创建时间
|
||||
|
||||
@Column(name = "device_id")
|
||||
private String deviceId; // 设备ID(可选)
|
||||
|
||||
// 构造函数
|
||||
public AlertData() {
|
||||
this.createTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public AlertData(String content, String category, LocalDateTime alertTime, String level) {
|
||||
this();
|
||||
this.content = content;
|
||||
this.category = category;
|
||||
this.alertTime = alertTime;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public AlertData(String content, String category, LocalDateTime alertTime, String level,
|
||||
String action, LocalDateTime actionTime, String deviceId) {
|
||||
this();
|
||||
this.content = content;
|
||||
this.category = category;
|
||||
this.alertTime = alertTime;
|
||||
this.level = level;
|
||||
this.action = action;
|
||||
this.actionTime = actionTime;
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public LocalDateTime getAlertTime() {
|
||||
return alertTime;
|
||||
}
|
||||
|
||||
public void setAlertTime(LocalDateTime alertTime) {
|
||||
this.alertTime = alertTime;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public LocalDateTime getActionTime() {
|
||||
return actionTime;
|
||||
}
|
||||
|
||||
public void setActionTime(LocalDateTime actionTime) {
|
||||
this.actionTime = actionTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AlertData{" +
|
||||
"id=" + id +
|
||||
", content='" + content + '\'' +
|
||||
", category='" + category + '\'' +
|
||||
", alertTime=" + alertTime +
|
||||
", level='" + level + '\'' +
|
||||
", action='" + action + '\'' +
|
||||
", actionTime=" + actionTime +
|
||||
", deviceId='" + deviceId + '\'' +
|
||||
", createTime=" + createTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface AlertDataRepository extends JpaRepository<AlertData, Long> {
|
||||
|
||||
// 按创建时间倒序获取最新数据
|
||||
List<AlertData> findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
// 分页查询
|
||||
Page<AlertData> findAllByOrderByCreateTimeDesc(Pageable pageable);
|
||||
// AlertDataRepository.java
|
||||
Page<AlertData> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
|
||||
Page<AlertData> findByCreateTimeAfter(LocalDateTime startTime, Pageable pageable);
|
||||
Page<AlertData> findByCreateTimeBefore(LocalDateTime endTime, Pageable pageable);}
|
||||
90
src/main/java/com/xzzn/movecheck/repo/ClimateThreshold.java
Normal file
90
src/main/java/com/xzzn/movecheck/repo/ClimateThreshold.java
Normal file
@ -0,0 +1,90 @@
|
||||
// ClimateThreshold.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "climate_threshold") // 确保表名正确
|
||||
public class ClimateThreshold {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "setting_name", unique = true, nullable = false)
|
||||
private String settingName;
|
||||
|
||||
@Column(name = "min_temperature", precision = 5, scale = 2, nullable = false)
|
||||
private BigDecimal minTemperature;
|
||||
|
||||
@Column(name = "max_temperature", precision = 5, scale = 2, nullable = false)
|
||||
private BigDecimal maxTemperature;
|
||||
|
||||
@Column(name = "min_humidity", precision = 5, scale = 2, nullable = false)
|
||||
private BigDecimal minHumidity;
|
||||
|
||||
@Column(name = "max_humidity", precision = 5, scale = 2, nullable = false)
|
||||
private BigDecimal maxHumidity;
|
||||
|
||||
@Column(length = 500)
|
||||
private String description;
|
||||
|
||||
@Column(name = "created_time")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@Column(name = "updated_time")
|
||||
private LocalDateTime updatedTime;
|
||||
|
||||
// 构造方法
|
||||
public ClimateThreshold() {
|
||||
this.createdTime = LocalDateTime.now();
|
||||
this.updatedTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public ClimateThreshold(String settingName, BigDecimal minTemperature,
|
||||
BigDecimal maxTemperature, BigDecimal minHumidity,
|
||||
BigDecimal maxHumidity, String description) {
|
||||
this();
|
||||
this.settingName = settingName;
|
||||
this.minTemperature = minTemperature;
|
||||
this.maxTemperature = maxTemperature;
|
||||
this.minHumidity = minHumidity;
|
||||
this.maxHumidity = maxHumidity;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
// Getter和Setter方法
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public String getSettingName() { return settingName; }
|
||||
public void setSettingName(String settingName) { this.settingName = settingName; }
|
||||
|
||||
public BigDecimal getMinTemperature() { return minTemperature; }
|
||||
public void setMinTemperature(BigDecimal minTemperature) { this.minTemperature = minTemperature; }
|
||||
|
||||
public BigDecimal getMaxTemperature() { return maxTemperature; }
|
||||
public void setMaxTemperature(BigDecimal maxTemperature) { this.maxTemperature = maxTemperature; }
|
||||
|
||||
public BigDecimal getMinHumidity() { return minHumidity; }
|
||||
public void setMinHumidity(BigDecimal minHumidity) { this.minHumidity = minHumidity; }
|
||||
|
||||
public BigDecimal getMaxHumidity() { return maxHumidity; }
|
||||
public void setMaxHumidity(BigDecimal maxHumidity) { this.maxHumidity = maxHumidity; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public LocalDateTime getCreatedTime() { return createdTime; }
|
||||
public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; }
|
||||
|
||||
public LocalDateTime getUpdatedTime() { return updatedTime; }
|
||||
public void setUpdatedTime(LocalDateTime updatedTime) { this.updatedTime = updatedTime; }
|
||||
|
||||
@PreUpdate
|
||||
public void preUpdate() {
|
||||
this.updatedTime = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
// ClimateThresholdRepository.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface ClimateThresholdRepository extends JpaRepository<ClimateThreshold, Long> {
|
||||
|
||||
// 根据设置名称查找
|
||||
Optional<ClimateThreshold> findBySettingName(String settingName);
|
||||
|
||||
// 检查设置名称是否存在
|
||||
boolean existsBySettingName(String settingName);
|
||||
|
||||
// 根据温度范围查找
|
||||
List<ClimateThreshold> findByMinTemperatureLessThanEqualAndMaxTemperatureGreaterThanEqual(BigDecimal temperature, BigDecimal temperature2);
|
||||
|
||||
// 自定义查询示例
|
||||
@Query("SELECT ct FROM ClimateThreshold ct WHERE ct.minTemperature <= :temp AND ct.maxTemperature >= :temp")
|
||||
List<ClimateThreshold> findSuitableThresholdsByTemperature(BigDecimal temp);
|
||||
}
|
||||
46
src/main/java/com/xzzn/movecheck/repo/EmqxClientInfo.java
Normal file
46
src/main/java/com/xzzn/movecheck/repo/EmqxClientInfo.java
Normal file
@ -0,0 +1,46 @@
|
||||
// EmqxClientInfo.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class EmqxClientInfo {
|
||||
@JsonProperty("clientid")
|
||||
private String clientId;
|
||||
|
||||
private String username;
|
||||
private Boolean connected;
|
||||
private Long connectedAt;
|
||||
private String ipAddress;
|
||||
private Integer port;
|
||||
private Integer keepalive;
|
||||
private Integer protoVer;
|
||||
private String protoName;
|
||||
|
||||
// Getter和Setter
|
||||
public String getClientId() { return clientId; }
|
||||
public void setClientId(String clientId) { this.clientId = clientId; }
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public Boolean getConnected() { return connected; }
|
||||
public void setConnected(Boolean connected) { this.connected = connected; }
|
||||
|
||||
public Long getConnectedAt() { return connectedAt; }
|
||||
public void setConnectedAt(Long connectedAt) { this.connectedAt = connectedAt; }
|
||||
|
||||
public String getIpAddress() { return ipAddress; }
|
||||
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
|
||||
|
||||
public Integer getPort() { return port; }
|
||||
public void setPort(Integer port) { this.port = port; }
|
||||
|
||||
public Integer getKeepalive() { return keepalive; }
|
||||
public void setKeepalive(Integer keepalive) { this.keepalive = keepalive; }
|
||||
|
||||
public Integer getProtoVer() { return protoVer; }
|
||||
public void setProtoVer(Integer protoVer) { this.protoVer = protoVer; }
|
||||
|
||||
public String getProtoName() { return protoName; }
|
||||
public void setProtoName(String protoName) { this.protoName = protoName; }
|
||||
}
|
||||
121
src/main/java/com/xzzn/movecheck/repo/EventData.java
Normal file
121
src/main/java/com/xzzn/movecheck/repo/EventData.java
Normal file
@ -0,0 +1,121 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "event_data")
|
||||
public class EventData {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "event_type", nullable = false)
|
||||
private String eventType; // 事件类型
|
||||
|
||||
@Column(name = "event_time", nullable = false)
|
||||
private LocalDateTime eventTime; // 事件时间
|
||||
|
||||
@Column(name = "status", nullable = false)
|
||||
private String status; // 状态
|
||||
|
||||
@Column(name = "description")
|
||||
private String description; // 事件描述
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime; // 创建时间
|
||||
|
||||
@Column(name = "device_id")
|
||||
private String deviceId; // 设备ID(可选)
|
||||
|
||||
// 构造函数
|
||||
public EventData() {
|
||||
this.createTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public EventData(String eventType, LocalDateTime eventTime, String status) {
|
||||
this();
|
||||
this.eventType = eventType;
|
||||
this.eventTime = eventTime;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public EventData(String eventType, LocalDateTime eventTime, String status, String description, String deviceId) {
|
||||
this();
|
||||
this.eventType = eventType;
|
||||
this.eventTime = eventTime;
|
||||
this.status = status;
|
||||
this.description = description;
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(String eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
public LocalDateTime getEventTime() {
|
||||
return eventTime;
|
||||
}
|
||||
|
||||
public void setEventTime(LocalDateTime eventTime) {
|
||||
this.eventTime = eventTime;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EventData{" +
|
||||
"id=" + id +
|
||||
", eventType='" + eventType + '\'' +
|
||||
", eventTime=" + eventTime +
|
||||
", status='" + status + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", deviceId='" + deviceId + '\'' +
|
||||
", createTime=" + createTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface EventDataRepository extends JpaRepository<EventData, Long> {
|
||||
|
||||
// 按创建时间倒序获取最新数据
|
||||
List<EventData> findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
// 分页查询
|
||||
Page<EventData> findAllByOrderByCreateTimeDesc(Pageable pageable);
|
||||
// EventDataRepository.java
|
||||
Page<EventData> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
|
||||
Page<EventData> findByCreateTimeAfter(LocalDateTime startTime, Pageable pageable);
|
||||
Page<EventData> findByCreateTimeBefore(LocalDateTime endTime, Pageable pageable);
|
||||
|
||||
|
||||
}
|
||||
99
src/main/java/com/xzzn/movecheck/repo/HealthDevice.java
Normal file
99
src/main/java/com/xzzn/movecheck/repo/HealthDevice.java
Normal file
@ -0,0 +1,99 @@
|
||||
// entity/HealthDevice.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "health_device")
|
||||
public class HealthDevice {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "ac", length = 1)
|
||||
private String ac;
|
||||
|
||||
@Column(name = "wsd", length = 1)
|
||||
private String wsd;
|
||||
|
||||
@Column(name = "pm25", length = 1)
|
||||
private String pm25;
|
||||
|
||||
@Column(name = "created_time")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@Column(name = "updated_time")
|
||||
private LocalDateTime updatedTime;
|
||||
|
||||
// 构造方法
|
||||
public HealthDevice() {
|
||||
}
|
||||
|
||||
public HealthDevice(String ac, String wsd, String pm25) {
|
||||
this.ac = ac;
|
||||
this.wsd = wsd;
|
||||
this.pm25 = pm25;
|
||||
}
|
||||
|
||||
// getters and setters
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAc() {
|
||||
return ac;
|
||||
}
|
||||
|
||||
public void setAc(String ac) {
|
||||
this.ac = ac;
|
||||
}
|
||||
|
||||
public String getWsd() {
|
||||
return wsd;
|
||||
}
|
||||
|
||||
public void setWsd(String wsd) {
|
||||
this.wsd = wsd;
|
||||
}
|
||||
|
||||
public String getPm25() {
|
||||
return pm25;
|
||||
}
|
||||
|
||||
public void setPm25(String pm25) {
|
||||
this.pm25 = pm25;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
public void setCreatedTime(LocalDateTime createdTime) {
|
||||
this.createdTime = createdTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedTime() {
|
||||
return updatedTime;
|
||||
}
|
||||
|
||||
public void setUpdatedTime(LocalDateTime updatedTime) {
|
||||
this.updatedTime = updatedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HealthDevice{" +
|
||||
"id=" + id +
|
||||
", ac='" + ac + '\'' +
|
||||
", wsd='" + wsd + '\'' +
|
||||
", pm25='" + pm25 + '\'' +
|
||||
", createdTime=" + createdTime +
|
||||
", updatedTime=" + updatedTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
// repository/HealthDeviceRepository.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface HealthDeviceRepository extends JpaRepository<HealthDevice, Integer> {
|
||||
|
||||
// 自定义查询:查找最新的记录
|
||||
@Query(value = "SELECT * FROM health_device ORDER BY created_time DESC LIMIT 1", nativeQuery = true)
|
||||
List<HealthDevice> findLatestRecord();
|
||||
|
||||
}
|
||||
79
src/main/java/com/xzzn/movecheck/repo/SensorData.java
Normal file
79
src/main/java/com/xzzn/movecheck/repo/SensorData.java
Normal file
@ -0,0 +1,79 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sensor_data")
|
||||
public class SensorData {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "sd_value")
|
||||
private Double sd;
|
||||
|
||||
@Column(name = "wd_value")
|
||||
private Double wd;
|
||||
@Column(name = "pm_value")
|
||||
private Double pm;
|
||||
|
||||
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// 构造函数
|
||||
public SensorData() {
|
||||
this.createTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public SensorData(Double sd, Double wd, Double pm) {
|
||||
this();
|
||||
this.sd = sd;
|
||||
this.wd = wd;
|
||||
this.pm = pm;
|
||||
|
||||
}
|
||||
|
||||
// getter 和 setter 方法
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Double getSd() {
|
||||
return sd;
|
||||
}
|
||||
|
||||
public void setSd(Double sd) {
|
||||
this.sd = sd;
|
||||
}
|
||||
|
||||
public Double getWd() {
|
||||
return wd;
|
||||
}
|
||||
|
||||
public void setWd(Double wd) {
|
||||
this.wd = wd;
|
||||
}
|
||||
|
||||
public Double getPm() {
|
||||
return pm;
|
||||
}
|
||||
|
||||
public void setPm(Double pm) {
|
||||
this.pm = pm;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface SensorDataRepository extends JpaRepository<SensorData, Long> {
|
||||
|
||||
// 查找最新的数据
|
||||
List<SensorData> findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
// 根据时间范围查询
|
||||
List<SensorData> findByCreateTimeBetween(LocalDateTime start, LocalDateTime end);
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "temperature_humidity_data")
|
||||
public class TemperatureHumidityData {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "temperature", nullable = false)
|
||||
private Double temperature; // 温度
|
||||
|
||||
@Column(name = "humidity", nullable = false)
|
||||
private Double humidity; // 湿度
|
||||
|
||||
@Column(name = "device_id")
|
||||
private String deviceId; // 设备ID
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime; // 创建时间
|
||||
|
||||
// 构造函数
|
||||
public TemperatureHumidityData() {
|
||||
this.createTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public TemperatureHumidityData(Double temperature, Double humidity) {
|
||||
this();
|
||||
this.temperature = temperature;
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public TemperatureHumidityData(Double temperature, Double humidity, String deviceId) {
|
||||
this();
|
||||
this.temperature = temperature;
|
||||
this.humidity = humidity;
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Double getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(Double temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public Double getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(Double humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TemperatureHumidityData{" +
|
||||
"id=" + id +
|
||||
", temperature=" + temperature +
|
||||
", humidity=" + humidity +
|
||||
", deviceId='" + deviceId + '\'' +
|
||||
", createTime=" + createTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface TemperatureHumidityRepository extends JpaRepository<TemperatureHumidityData, Long> {
|
||||
|
||||
/**
|
||||
* 获取最新的温湿度数据 - 使用原生SQL查询
|
||||
*/
|
||||
@Query(value = "SELECT * FROM temperature_humidity_data ORDER BY create_time DESC LIMIT 1", nativeQuery = true)
|
||||
Optional<TemperatureHumidityData> findLatestData();
|
||||
|
||||
/**
|
||||
* 根据设备ID获取最新数据 - 使用原生SQL查询
|
||||
*/
|
||||
@Query(value = "SELECT * FROM temperature_humidity_data WHERE device_id = :deviceId ORDER BY create_time DESC LIMIT 1", nativeQuery = true)
|
||||
Optional<TemperatureHumidityData> findLatestByDeviceId(@Param("deviceId") String deviceId);
|
||||
|
||||
/**
|
||||
* 获取最新的N条数据 - 使用Spring Data JPA方法名查询
|
||||
*/
|
||||
List<TemperatureHumidityData> findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
/**
|
||||
* 根据设备ID获取最新的N条数据 - 使用Spring Data JPA方法名查询
|
||||
*/
|
||||
List<TemperatureHumidityData> findTop10ByDeviceIdOrderByCreateTimeDesc(String deviceId);
|
||||
|
||||
/**
|
||||
* 分页查询所有数据
|
||||
*/
|
||||
Page<TemperatureHumidityData> findAllByOrderByCreateTimeDesc(Pageable pageable);
|
||||
|
||||
/**
|
||||
* 根据设备ID分页查询
|
||||
*/
|
||||
Page<TemperatureHumidityData> findByDeviceIdOrderByCreateTimeDesc(String deviceId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 根据时间范围查询
|
||||
*/
|
||||
List<TemperatureHumidityData> findByCreateTimeBetweenOrderByCreateTimeDesc(LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 根据设备ID和时间范围查询
|
||||
*/
|
||||
List<TemperatureHumidityData> findByDeviceIdAndCreateTimeBetweenOrderByCreateTimeDesc(String deviceId, LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 获取所有设备ID列表
|
||||
*/
|
||||
@Query("SELECT DISTINCT t.deviceId FROM TemperatureHumidityData t WHERE t.deviceId IS NOT NULL")
|
||||
List<String> findAllDeviceIds();
|
||||
|
||||
/**
|
||||
* 获取第一条记录(按创建时间升序)
|
||||
*/
|
||||
Optional<TemperatureHumidityData> findFirstByOrderByCreateTimeAsc();
|
||||
|
||||
/**
|
||||
* 获取最后一条记录(按创建时间降序)
|
||||
*/
|
||||
Optional<TemperatureHumidityData> findFirstByOrderByCreateTimeDesc();
|
||||
}
|
||||
71
src/main/java/com/xzzn/movecheck/repo/User.java
Normal file
71
src/main/java/com/xzzn/movecheck/repo/User.java
Normal file
@ -0,0 +1,71 @@
|
||||
// User.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "system_user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true, nullable = false, length = 50)
|
||||
private String username;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String password;
|
||||
|
||||
@Column(length = 100)
|
||||
private String nickname;
|
||||
|
||||
private Boolean enabled = true;
|
||||
|
||||
@Column(name = "created_time")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@Column(name = "updated_time")
|
||||
private LocalDateTime updatedTime;
|
||||
|
||||
// 构造方法
|
||||
public User() {
|
||||
this.createdTime = LocalDateTime.now();
|
||||
this.updatedTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public User(String username, String password, String nickname) {
|
||||
this();
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
// Getter和Setter
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
|
||||
public String getNickname() { return nickname; }
|
||||
public void setNickname(String nickname) { this.nickname = nickname; }
|
||||
|
||||
public Boolean getEnabled() { return enabled; }
|
||||
public void setEnabled(Boolean enabled) { this.enabled = enabled; }
|
||||
|
||||
public LocalDateTime getCreatedTime() { return createdTime; }
|
||||
public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; }
|
||||
|
||||
public LocalDateTime getUpdatedTime() { return updatedTime; }
|
||||
public void setUpdatedTime(LocalDateTime updatedTime) { this.updatedTime = updatedTime; }
|
||||
|
||||
@PreUpdate
|
||||
public void preUpdate() {
|
||||
this.updatedTime = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
23
src/main/java/com/xzzn/movecheck/repo/UserRepository.java
Normal file
23
src/main/java/com/xzzn/movecheck/repo/UserRepository.java
Normal file
@ -0,0 +1,23 @@
|
||||
// UserRepository.java
|
||||
package com.xzzn.movecheck.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
// 根据用户名查找用户
|
||||
Optional<User> findByUsername(String username);
|
||||
|
||||
// 根据用户名和密码查找用户
|
||||
@Query("SELECT u FROM User u WHERE u.username = :username AND u.password = :password AND u.enabled = true")
|
||||
Optional<User> findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
|
||||
|
||||
// 检查用户名是否存在
|
||||
boolean existsByUsername(String username);
|
||||
}
|
||||
110
src/main/java/com/xzzn/movecheck/service/AuthService.java
Normal file
110
src/main/java/com/xzzn/movecheck/service/AuthService.java
Normal file
@ -0,0 +1,110 @@
|
||||
// AuthService.java
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.xzzn.movecheck.repo.User;
|
||||
import com.xzzn.movecheck.repo.UserRepository;
|
||||
import com.xzzn.movecheck.util.SimpleTokenUtil;
|
||||
import com.xzzn.movecheck.wsd.LoginRequest;
|
||||
import com.xzzn.movecheck.wsd.LoginResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class AuthService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private SimpleTokenUtil tokenUtil;
|
||||
|
||||
// 内存token存储(生产环境建议用Redis)
|
||||
private Map<String, String> tokenStore = new HashMap<>();
|
||||
|
||||
public LoginResponse login(LoginRequest loginRequest) {
|
||||
// 从数据库验证用户名密码
|
||||
Optional<User> userOpt = userRepository.findByUsernameAndPassword(
|
||||
loginRequest.getUsername(),
|
||||
loginRequest.getPassword()
|
||||
);
|
||||
|
||||
if (userOpt.isPresent()) {
|
||||
User user = userOpt.get();
|
||||
|
||||
// 检查用户是否被禁用
|
||||
if (!user.getEnabled()) {
|
||||
return new LoginResponse(false, "用户已被禁用");
|
||||
}
|
||||
|
||||
// 生成token
|
||||
String token = tokenUtil.generateToken(user.getUsername());
|
||||
|
||||
// 存储token
|
||||
tokenStore.put(token, user.getUsername());
|
||||
|
||||
// 使用正确的构造函数
|
||||
return new LoginResponse(
|
||||
true,
|
||||
"登录成功",
|
||||
token,
|
||||
user.getUsername(),
|
||||
user.getNickname() != null ? user.getNickname() : user.getUsername() // 确保nickname不为null
|
||||
);
|
||||
} else {
|
||||
return new LoginResponse(false, "用户名或密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validateToken(String token) {
|
||||
if (token == null || !tokenStore.containsKey(token)) {
|
||||
return false;
|
||||
}
|
||||
return tokenUtil.validateToken(token);
|
||||
}
|
||||
|
||||
public String getUsernameFromToken(String token) {
|
||||
return tokenStore.get(token);
|
||||
}
|
||||
|
||||
// 获取当前登录用户信息
|
||||
public Optional<User> getCurrentUser(String token) {
|
||||
String username = getUsernameFromToken(token);
|
||||
if (username != null) {
|
||||
return userRepository.findByUsername(username);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// 登出
|
||||
public void logout(String token) {
|
||||
tokenStore.remove(token);
|
||||
}
|
||||
|
||||
// 获取所有用户(管理功能)
|
||||
public java.util.List<User> getAllUsers() {
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
// 创建用户(管理功能)
|
||||
public User createUser(User user) {
|
||||
if (userRepository.existsByUsername(user.getUsername())) {
|
||||
throw new RuntimeException("用户名已存在");
|
||||
}
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
// 更新用户(管理功能)
|
||||
public User updateUser(Long id, User userDetails) {
|
||||
User user = userRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("用户不存在"));
|
||||
|
||||
user.setNickname(userDetails.getNickname());
|
||||
user.setEnabled(userDetails.getEnabled());
|
||||
|
||||
return userRepository.save(user);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
// ClimateThresholdService.java
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.xzzn.movecheck.repo.ClimateThreshold;
|
||||
import com.xzzn.movecheck.repo.ClimateThresholdRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ClimateThresholdService {
|
||||
|
||||
@Autowired
|
||||
private ClimateThresholdRepository thresholdRepository;
|
||||
|
||||
// 保存或更新阈值设置
|
||||
public ClimateThreshold saveThreshold(ClimateThreshold threshold) {
|
||||
validateThreshold(threshold);
|
||||
return thresholdRepository.save(threshold);
|
||||
}
|
||||
|
||||
// 根据ID查找
|
||||
public Optional<ClimateThreshold> findById(Long id) {
|
||||
return thresholdRepository.findById(id);
|
||||
}
|
||||
|
||||
// 根据名称查找
|
||||
public Optional<ClimateThreshold> findBySettingName(String settingName) {
|
||||
return thresholdRepository.findBySettingName(settingName);
|
||||
}
|
||||
|
||||
// 获取所有设置
|
||||
public List<ClimateThreshold> findAll() {
|
||||
return thresholdRepository.findAll();
|
||||
}
|
||||
|
||||
// 删除设置
|
||||
public void deleteById(Long id) {
|
||||
thresholdRepository.deleteById(id);
|
||||
}
|
||||
|
||||
// 验证阈值范围
|
||||
private void validateThreshold(ClimateThreshold threshold) {
|
||||
if (threshold.getMinTemperature().compareTo(threshold.getMaxTemperature()) >= 0) {
|
||||
throw new IllegalArgumentException("最小温度不能大于等于最大温度");
|
||||
}
|
||||
|
||||
if (threshold.getMinHumidity().compareTo(threshold.getMaxHumidity()) >= 0) {
|
||||
throw new IllegalArgumentException("最小湿度不能大于等于最大湿度");
|
||||
}
|
||||
|
||||
if (threshold.getMinHumidity().compareTo(BigDecimal.ZERO) < 0 ||
|
||||
threshold.getMaxHumidity().compareTo(new BigDecimal("100")) > 0) {
|
||||
throw new IllegalArgumentException("湿度范围应在0-100之间");
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前环境状态
|
||||
public String checkEnvironmentStatus(String settingName, BigDecimal currentTemp, BigDecimal currentHumidity) {
|
||||
Optional<ClimateThreshold> thresholdOpt = thresholdRepository.findBySettingName(settingName);
|
||||
|
||||
if (thresholdOpt == null) {
|
||||
return "未找到对应的阈值设置: " + settingName;
|
||||
}
|
||||
|
||||
ClimateThreshold threshold = thresholdOpt.get();
|
||||
StringBuilder status = new StringBuilder();
|
||||
|
||||
// 检查温度
|
||||
if (currentTemp.compareTo(threshold.getMinTemperature()) < 0) {
|
||||
status.append("温度过低");
|
||||
} else if (currentTemp.compareTo(threshold.getMaxTemperature()) > 0) {
|
||||
status.append("温度过高");
|
||||
} else {
|
||||
status.append("温度正常");
|
||||
}
|
||||
|
||||
status.append(" | ");
|
||||
|
||||
// 检查湿度
|
||||
if (currentHumidity.compareTo(threshold.getMinHumidity()) < 0) {
|
||||
status.append("湿度过低");
|
||||
} else if (currentHumidity.compareTo(threshold.getMaxHumidity()) > 0) {
|
||||
status.append("湿度过高");
|
||||
} else {
|
||||
status.append("湿度正常");
|
||||
}
|
||||
|
||||
return status.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
// DataProcessingService.java
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.xzzn.movecheck.repo.HealthDevice;
|
||||
import com.xzzn.movecheck.repo.HealthDeviceRepository;
|
||||
import com.xzzn.movecheck.repo.SensorData;
|
||||
import com.xzzn.movecheck.repo.SensorDataRepository;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class DataProcessingService implements IMqttMessageListener {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DataProcessingService.class);
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Autowired
|
||||
private HealthDeviceRepository healthDeviceRepository;
|
||||
|
||||
@Autowired
|
||||
private SensorDataRepository sensorDataRepository;
|
||||
|
||||
@Override
|
||||
public void messageArrived(String topic, MqttMessage message) {
|
||||
String payload = new String(message.getPayload());
|
||||
logger.info("收到MQTT消息 - Topic: {}, QoS: {}", topic, message.getQos());
|
||||
|
||||
try {
|
||||
switch (topic) {
|
||||
case "HDYDCJ_01_DEVICE":
|
||||
processDeviceHealthData(payload);
|
||||
break;
|
||||
case "HDYDCJ_01_UP":
|
||||
processSensorData(payload);
|
||||
break;
|
||||
default:
|
||||
logger.warn("未知的Topic: {}", topic);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("处理MQTT消息失败 - Topic: {}, Error: {}", topic, e.getMessage());
|
||||
// 可以根据需要在这里添加重试逻辑或错误处理
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设备健康数据 HDYDCJ_01_DEVICE
|
||||
*/
|
||||
private void processDeviceHealthData(String payload) {
|
||||
logger.debug("开始处理设备健康数据: {}", payload);
|
||||
|
||||
JSONObject deviceHealthData = JSON.parseObject(payload);
|
||||
String wsd = String.valueOf(deviceHealthData.get("WSD"));
|
||||
String pm25 = String.valueOf(deviceHealthData.get("PM25"));
|
||||
String ac = String.valueOf(deviceHealthData.get("AC"));
|
||||
|
||||
HealthDevice healthDevice = new HealthDevice();
|
||||
healthDevice.setId(1);
|
||||
healthDevice.setAc(ac);
|
||||
healthDevice.setWsd(wsd);
|
||||
healthDevice.setPm25(pm25);
|
||||
healthDeviceRepository.save(healthDevice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理传感器数据 HDYDCJ_01_UP
|
||||
*/
|
||||
private void processSensorData(String payload) {
|
||||
logger.debug("开始处理传感器数据: {}", payload);
|
||||
|
||||
// 注意:这里payload是数组格式
|
||||
try {
|
||||
JsonNode rootNode = objectMapper.readTree(payload);
|
||||
|
||||
// 读取顶层字段
|
||||
String device = rootNode.get("Device").asText();
|
||||
long timestamp = rootNode.get("timestamp").asLong();
|
||||
|
||||
// 读取Data对象中的字段
|
||||
JsonNode dataNode = rootNode.get("Data");
|
||||
double pm10 = dataNode.get("PM10").asDouble();
|
||||
double pm25 = dataNode.get("PM25").asDouble();
|
||||
double wd = dataNode.get("WD").asDouble();
|
||||
double sd = dataNode.get("SD").asDouble();
|
||||
|
||||
System.out.println("Device: " + device);
|
||||
System.out.println("Timestamp: " + timestamp);
|
||||
System.out.println("PM10: " + pm10);
|
||||
System.out.println("PM25: " + pm25);
|
||||
System.out.println("WD: " + wd);
|
||||
System.out.println("SD: " + sd);
|
||||
|
||||
List<SensorData> list = sensorDataRepository.findTop10ByOrderByCreateTimeDesc();
|
||||
SensorData entity = new SensorData();
|
||||
entity.setWd(wd);
|
||||
entity.setPm(pm25);
|
||||
entity.setSd(sd);
|
||||
if (BigDecimal.valueOf(wd).compareTo(BigDecimal.ZERO) == 0) {
|
||||
entity.setWd(list.get(0).getWd());
|
||||
}
|
||||
if (BigDecimal.valueOf(pm25).compareTo(BigDecimal.ZERO) == 0) {
|
||||
entity.setPm(list.get(0).getPm());
|
||||
}
|
||||
if (BigDecimal.valueOf(sd).compareTo(BigDecimal.ZERO) == 0) {
|
||||
entity.setSd(list.get(0).getSd());
|
||||
}
|
||||
sensorDataRepository.save(entity);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
193
src/main/java/com/xzzn/movecheck/service/EmqxClientService.java
Normal file
193
src/main/java/com/xzzn/movecheck/service/EmqxClientService.java
Normal file
@ -0,0 +1,193 @@
|
||||
// service/EmqxClientService.java
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.xzzn.movecheck.wsd.ClientInfo;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class EmqxClientService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmqxClientService.class);
|
||||
|
||||
private String username = "f080a5e8e41e10bf";
|
||||
|
||||
private String password="ynAnM9BXWDqgwmx672D2MxHNaal6ZmpcCEgpnPx0ludL";
|
||||
|
||||
private String baseUrl="http://122.51.194.184:18083";
|
||||
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public EmqxClientService(CloseableHttpClient httpClient, ObjectMapper objectMapper) {
|
||||
this.httpClient = httpClient;
|
||||
this.objectMapper = objectMapper;
|
||||
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
logger.info("EMQX API Service initialized with base URL: {}", baseUrl);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
try {
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Error closing HTTP client", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定客户端信息
|
||||
*/
|
||||
public ClientInfo getClientInfo(String clientId) {
|
||||
String url = baseUrl + "/api/v5/clients/" + clientId;
|
||||
logger.info("Requesting client info from: {}", url);
|
||||
|
||||
String auth = username + ":" + password;
|
||||
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
|
||||
String authHeader = "Basic " + encodedAuth;
|
||||
|
||||
HttpGet request = new HttpGet(url);
|
||||
request.setHeader("Authorization", authHeader);
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
|
||||
logger.debug("Response status: {}, body: {}", statusCode, responseBody);
|
||||
|
||||
if (statusCode == 200) {
|
||||
return objectMapper.readValue(responseBody, ClientInfo.class);
|
||||
} else if (statusCode == 404) {
|
||||
throw new RuntimeException("客户端不存在: " + clientId);
|
||||
} else {
|
||||
throw new RuntimeException("API 请求失败,状态码: " + statusCode + ", 响应: " + responseBody);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("获取客户端信息失败: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("获取客户端信息失败: " + e.getMessage(), e);
|
||||
} finally {
|
||||
request.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有客户端列表
|
||||
*/
|
||||
public String getAllClients() {
|
||||
String url = baseUrl + "/api/v5/clients";
|
||||
logger.info("Requesting all clients from: {}", url);
|
||||
|
||||
|
||||
String auth = username + ":" + password;
|
||||
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
|
||||
String authHeader = "Basic " + encodedAuth;
|
||||
|
||||
HttpGet request = new HttpGet(url);
|
||||
request.setHeader("Authorization", authHeader);
|
||||
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
|
||||
if (statusCode == 200) {
|
||||
return responseBody;
|
||||
} else {
|
||||
throw new RuntimeException("获取客户端列表失败,状态码: " + statusCode + ", 响应: " + responseBody);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("获取客户端列表失败: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("获取客户端列表失败: " + e.getMessage(), e);
|
||||
} finally {
|
||||
request.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查客户端是否在线
|
||||
*/
|
||||
public boolean isClientOnline(String clientId) {
|
||||
try {
|
||||
ClientInfo clientInfo = getClientInfo(clientId);
|
||||
return clientInfo.getConnected() != null && clientInfo.getConnected();
|
||||
} catch (Exception e) {
|
||||
logger.warn("检查客户端在线状态失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端连接状态详情
|
||||
*/
|
||||
public ClientStatusResponse getClientStatus(String clientId) {
|
||||
try {
|
||||
ClientInfo clientInfo = getClientInfo(clientId);
|
||||
return new ClientStatusResponse(clientId,
|
||||
clientInfo.getConnected() != null && clientInfo.getConnected(),
|
||||
clientInfo.getIpAddress(),
|
||||
clientInfo.getConnectedAt(),
|
||||
clientInfo.getDisconnectedAt());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("获取客户端状态失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 内部状态响应类
|
||||
public static class ClientStatusResponse {
|
||||
private String clientId;
|
||||
private boolean online;
|
||||
private String ipAddress;
|
||||
private Date connectedAt;
|
||||
private Date disconnectedAt;
|
||||
|
||||
public ClientStatusResponse(String clientId, boolean online, String ipAddress,
|
||||
Date connectedAt, Date disconnectedAt) {
|
||||
this.clientId = clientId;
|
||||
this.online = online;
|
||||
this.ipAddress = ipAddress;
|
||||
this.connectedAt = connectedAt;
|
||||
this.disconnectedAt = disconnectedAt;
|
||||
}
|
||||
|
||||
// getters and setters
|
||||
public String getClientId() { return clientId; }
|
||||
public void setClientId(String clientId) { this.clientId = clientId; }
|
||||
|
||||
public boolean isOnline() { return online; }
|
||||
public void setOnline(boolean online) { this.online = online; }
|
||||
|
||||
public String getIpAddress() { return ipAddress; }
|
||||
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
|
||||
|
||||
public Date getConnectedAt() { return connectedAt; }
|
||||
public void setConnectedAt(Date connectedAt) { this.connectedAt = connectedAt; }
|
||||
|
||||
public Date getDisconnectedAt() { return disconnectedAt; }
|
||||
public void setDisconnectedAt(Date disconnectedAt) { this.disconnectedAt = disconnectedAt; }
|
||||
}
|
||||
}
|
||||
152
src/main/java/com/xzzn/movecheck/service/EventAlertService.java
Normal file
152
src/main/java/com/xzzn/movecheck/service/EventAlertService.java
Normal file
@ -0,0 +1,152 @@
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.xzzn.movecheck.repo.AlertData;
|
||||
import com.xzzn.movecheck.repo.AlertDataRepository;
|
||||
import com.xzzn.movecheck.repo.EventData;
|
||||
import com.xzzn.movecheck.repo.EventDataRepository;
|
||||
import com.xzzn.movecheck.wsd.AlertRequest;
|
||||
import com.xzzn.movecheck.wsd.EventRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class EventAlertService {
|
||||
|
||||
@Autowired
|
||||
private EventDataRepository eventDataRepository;
|
||||
|
||||
@Autowired
|
||||
private AlertDataRepository alertDataRepository;
|
||||
|
||||
// 事件相关方法
|
||||
|
||||
/**
|
||||
* 保存事件数据
|
||||
*/
|
||||
public Map<String, Object> saveEvent(EventRequest request) {
|
||||
try {
|
||||
EventData eventData = new EventData(
|
||||
request.getEventType(),
|
||||
request.getEventTime(),
|
||||
request.getStatus(),
|
||||
request.getDescription(),
|
||||
request.getDeviceId()
|
||||
);
|
||||
|
||||
EventData saved = eventDataRepository.save(eventData);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("status", "success");
|
||||
result.put("message", "事件保存成功");
|
||||
result.put("id", saved.getId());
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("status", "error");
|
||||
result.put("message", "事件保存失败: " + e.getMessage());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新10条事件
|
||||
*/
|
||||
public List<EventData> getLatestEvents() {
|
||||
return eventDataRepository.findTop10ByOrderByCreateTimeDesc();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取事件
|
||||
*/
|
||||
public Page<EventData> getEventsByPage(int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
return eventDataRepository.findAllByOrderByCreateTimeDesc(pageable);
|
||||
}
|
||||
|
||||
// 告警相关方法
|
||||
|
||||
/**
|
||||
* 保存告警数据
|
||||
*/
|
||||
public Map<String, Object> saveAlert(AlertRequest request) {
|
||||
try {
|
||||
AlertData alertData = new AlertData(
|
||||
request.getContent(),
|
||||
request.getCategory(),
|
||||
request.getAlertTime(),
|
||||
request.getLevel(),
|
||||
request.getAction(),
|
||||
request.getActionTime(),
|
||||
request.getDeviceId()
|
||||
);
|
||||
|
||||
AlertData saved = alertDataRepository.save(alertData);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("status", "success");
|
||||
result.put("message", "告警保存成功");
|
||||
result.put("id", saved.getId());
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("status", "error");
|
||||
result.put("message", "告警保存失败: " + e.getMessage());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 在 EventAlertService 类中需要添加的方法签名
|
||||
|
||||
public Page<EventData> getEventsByCreateTime(LocalDateTime startTime, LocalDateTime endTime, int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
|
||||
if (startTime != null && endTime != null) {
|
||||
return eventDataRepository.findByCreateTimeBetween(startTime, endTime, pageable);
|
||||
} else if (startTime != null) {
|
||||
return eventDataRepository.findByCreateTimeAfter(startTime, pageable);
|
||||
} else if (endTime != null) {
|
||||
return eventDataRepository.findByCreateTimeBefore(endTime, pageable);
|
||||
} else {
|
||||
return eventDataRepository.findAllByOrderByCreateTimeDesc(pageable);
|
||||
}
|
||||
}
|
||||
|
||||
public Page<AlertData> getAlertsByCreateTime(LocalDateTime startTime, LocalDateTime endTime, int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
|
||||
if (startTime != null && endTime != null) {
|
||||
return alertDataRepository.findByCreateTimeBetween(startTime, endTime, pageable);
|
||||
} else if (startTime != null) {
|
||||
return alertDataRepository.findByCreateTimeAfter(startTime, pageable);
|
||||
} else if (endTime != null) {
|
||||
return alertDataRepository.findByCreateTimeBefore(endTime, pageable);
|
||||
} else {
|
||||
return alertDataRepository.findAllByOrderByCreateTimeDesc(pageable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新10条告警
|
||||
*/
|
||||
public List<AlertData> getLatestAlerts() {
|
||||
return alertDataRepository.findTop10ByOrderByCreateTimeDesc();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取告警
|
||||
*/
|
||||
public Page<AlertData> getAlertsByPage(int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
return alertDataRepository.findAllByOrderByCreateTimeDesc(pageable);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
// service/HealthDeviceService.java
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
|
||||
import com.xzzn.movecheck.repo.HealthDevice;
|
||||
import com.xzzn.movecheck.repo.HealthDeviceRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class HealthDeviceService {
|
||||
|
||||
@Autowired
|
||||
private HealthDeviceRepository healthDeviceRepository;
|
||||
|
||||
// 获取最新记录
|
||||
public List<HealthDevice> findLatestRecord() {
|
||||
return healthDeviceRepository.findLatestRecord();
|
||||
}
|
||||
}
|
||||
143
src/main/java/com/xzzn/movecheck/service/MqttMessageHandler.java
Normal file
143
src/main/java/com/xzzn/movecheck/service/MqttMessageHandler.java
Normal file
@ -0,0 +1,143 @@
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.xzzn.movecheck.repo.HealthDevice;
|
||||
import com.xzzn.movecheck.repo.HealthDeviceRepository;
|
||||
import com.xzzn.movecheck.repo.SensorData;
|
||||
import com.xzzn.movecheck.repo.SensorDataRepository;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||
import org.eclipse.paho.client.mqttv3.MqttCallback;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class MqttMessageHandler implements MqttCallback {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DataProcessingService.class);
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
|
||||
@Autowired
|
||||
private HealthDeviceRepository healthDeviceRepository;
|
||||
|
||||
@Autowired
|
||||
private SensorDataRepository sensorDataRepository;
|
||||
/**
|
||||
* 接收到消息时的回调
|
||||
*/
|
||||
@Override
|
||||
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||
String payload = new String(message.getPayload());
|
||||
System.out.println("收到消息 - Topic: " + topic + ", QoS: " + message.getQos());
|
||||
|
||||
try {
|
||||
if ("HDYDCJ_01_UP".equals(topic)) {
|
||||
processSensorData(payload);
|
||||
} else if ("HDYDCJ_01_DEVICE".equals(topic)) {
|
||||
processDeviceData(payload);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("处理MQTT消息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接丢失时的回调
|
||||
*/
|
||||
@Override
|
||||
public void connectionLost(Throwable cause) {
|
||||
System.err.println("MQTT连接丢失: " + cause.getMessage());
|
||||
// 可以在这里添加重连逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息传递完成时的回调
|
||||
*/
|
||||
@Override
|
||||
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||
// 用于发布消息时的回调,订阅场景下一般不需要处理
|
||||
System.out.println("消息传递完成");
|
||||
}
|
||||
|
||||
private void processSensorData(String payload) throws Exception {
|
||||
logger.debug("开始处理数据: {}", payload);
|
||||
JSONArray jsonArray = JSONArray.parseArray(payload);
|
||||
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JSONObject item = jsonArray.getJSONObject(i);
|
||||
|
||||
// 获取Device类型
|
||||
String device = item.getString("Device");
|
||||
Long timestamp = item.getLong("timestamp");
|
||||
|
||||
// 如果是PM25设备
|
||||
if ("PM25".equals(device)) {
|
||||
|
||||
List<SensorData> list = sensorDataRepository.findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
JSONObject data = item.getJSONObject("Data");
|
||||
|
||||
// 获取PM25值,如果为null则转为0
|
||||
Double pm25Value = data.getDouble("PM25");
|
||||
if (pm25Value == null) {
|
||||
pm25Value = list.get(0).getPm();
|
||||
}
|
||||
|
||||
// 获取SD值,如果为null则转为0.0
|
||||
Double sdValue = data.getDouble("SD");
|
||||
if (sdValue == null) {
|
||||
sdValue = list.get(0).getSd();
|
||||
}
|
||||
|
||||
// 获取WD值,如果为null则转为0.0
|
||||
Double wdValue = data.getDouble("WD");
|
||||
if (wdValue == null) {
|
||||
wdValue = list.get(0).getWd();
|
||||
}
|
||||
|
||||
SensorData entity = new SensorData();
|
||||
entity.setWd(wdValue);
|
||||
entity.setPm(pm25Value);
|
||||
entity.setSd(sdValue);
|
||||
|
||||
sensorDataRepository.save(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDeviceData(String payload) {
|
||||
logger.debug("开始处理设备健康数据: {}", payload);
|
||||
|
||||
JSONObject deviceHealthData = JSON.parseObject(payload);
|
||||
JSONObject wsdObject = deviceHealthData.getJSONObject("WSD");
|
||||
String wsdHealth = String.valueOf(wsdObject.getInteger("health"));
|
||||
|
||||
JSONObject acObject = deviceHealthData.getJSONObject("AC");
|
||||
String acHealth = String.valueOf(acObject.getInteger("health"));
|
||||
|
||||
JSONObject pm25Object = deviceHealthData.getJSONObject("PM25");
|
||||
String pm25Health = String.valueOf(pm25Object.getInteger("health"));
|
||||
|
||||
HealthDevice healthDevice = new HealthDevice();
|
||||
healthDevice.setId(1);
|
||||
healthDevice.setAc(acHealth);
|
||||
healthDevice.setWsd(wsdHealth);
|
||||
healthDevice.setPm25(pm25Health);
|
||||
healthDevice.setCreatedTime(LocalDateTime.now());
|
||||
healthDevice.setUpdatedTime(LocalDateTime.now());
|
||||
healthDeviceRepository.save(healthDevice);
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
package com.xzzn.movecheck.service;
|
||||
|
||||
import com.xzzn.movecheck.repo.TemperatureHumidityData;
|
||||
import com.xzzn.movecheck.repo.TemperatureHumidityRepository;
|
||||
import com.xzzn.movecheck.wsd.TemperatureHumidityRequest;
|
||||
import com.xzzn.movecheck.wsd.TemperatureHumidityResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class TemperatureHumidityService {
|
||||
|
||||
@Autowired
|
||||
private TemperatureHumidityRepository repository;
|
||||
|
||||
/**
|
||||
* 保存温湿度数据
|
||||
*/
|
||||
public TemperatureHumidityResponse saveData(TemperatureHumidityRequest request) {
|
||||
try {
|
||||
TemperatureHumidityData data = new TemperatureHumidityData(
|
||||
request.getTemperature(),
|
||||
request.getHumidity(),
|
||||
request.getDeviceId()
|
||||
);
|
||||
|
||||
TemperatureHumidityData saved = repository.save(data);
|
||||
|
||||
return TemperatureHumidityResponse.success("温湿度数据保存成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
return TemperatureHumidityResponse.error("温湿度数据保存失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新温湿度数据
|
||||
*/
|
||||
public TemperatureHumidityResponse getLatestData() {
|
||||
try {
|
||||
Optional<TemperatureHumidityData> dataOpt = repository.findLatestData();
|
||||
|
||||
if (dataOpt.isPresent()) {
|
||||
return TemperatureHumidityResponse.fromEntity(dataOpt.get());
|
||||
} else {
|
||||
return TemperatureHumidityResponse.error("暂无温湿度数据");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
return TemperatureHumidityResponse.error("获取温湿度数据失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID获取最新数据
|
||||
*/
|
||||
public TemperatureHumidityResponse getLatestByDevice(String deviceId) {
|
||||
try {
|
||||
Optional<TemperatureHumidityData> dataOpt = repository.findLatestByDeviceId(deviceId);
|
||||
|
||||
if (dataOpt.isPresent()) {
|
||||
return TemperatureHumidityResponse.fromEntity(dataOpt.get());
|
||||
} else {
|
||||
return TemperatureHumidityResponse.error("未找到设备 " + deviceId + " 的温湿度数据");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
return TemperatureHumidityResponse.error("获取设备温湿度数据失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新10条数据
|
||||
*/
|
||||
public TemperatureHumidityResponse getLatest10Data() {
|
||||
try {
|
||||
List<TemperatureHumidityData> dataList = repository.findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
TemperatureHumidityResponse response = new TemperatureHumidityResponse();
|
||||
response.setStatus("success");
|
||||
response.setMessage("获取成功");
|
||||
response.setDataList(dataList);
|
||||
response.setTotal((long) dataList.size());
|
||||
|
||||
return response;
|
||||
|
||||
} catch (Exception e) {
|
||||
return TemperatureHumidityResponse.error("获取温湿度数据列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID获取最新10条数据
|
||||
*/
|
||||
public TemperatureHumidityResponse getLatest10ByDevice(String deviceId) {
|
||||
try {
|
||||
List<TemperatureHumidityData> dataList = repository.findTop10ByDeviceIdOrderByCreateTimeDesc(deviceId);
|
||||
|
||||
TemperatureHumidityResponse response = new TemperatureHumidityResponse();
|
||||
response.setStatus("success");
|
||||
response.setMessage("获取成功");
|
||||
response.setDataList(dataList);
|
||||
response.setTotal((long) dataList.size());
|
||||
|
||||
return response;
|
||||
|
||||
} catch (Exception e) {
|
||||
return TemperatureHumidityResponse.error("获取设备温湿度数据列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询数据
|
||||
*/
|
||||
public Page<TemperatureHumidityData> getDataByPage(int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
return repository.findAllByOrderByCreateTimeDesc(pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID分页查询
|
||||
*/
|
||||
public Page<TemperatureHumidityData> getDataByDeviceAndPage(String deviceId, int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createTime"));
|
||||
return repository.findByDeviceIdOrderByCreateTimeDesc(deviceId, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有设备ID列表
|
||||
*/
|
||||
public List<String> getAllDeviceIds() {
|
||||
return repository.findAllDeviceIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据总数
|
||||
*/
|
||||
public long getTotalCount() {
|
||||
return repository.count();
|
||||
}
|
||||
}
|
||||
39
src/main/java/com/xzzn/movecheck/util/SimpleTokenUtil.java
Normal file
39
src/main/java/com/xzzn/movecheck/util/SimpleTokenUtil.java
Normal file
@ -0,0 +1,39 @@
|
||||
// SimpleTokenUtil.java
|
||||
package com.xzzn.movecheck.util;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
public class SimpleTokenUtil {
|
||||
|
||||
// 生成简单的token(实际项目中应该更复杂)
|
||||
public String generateToken(String username) {
|
||||
String rawToken = username + ":" + System.currentTimeMillis() + ":" + UUID.randomUUID();
|
||||
return Base64.getEncoder().encodeToString(rawToken.getBytes());
|
||||
}
|
||||
|
||||
// 验证token(这里简单验证,实际项目需要更严格的验证)
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
String decoded = new String(Base64.getDecoder().decode(token));
|
||||
String[] parts = decoded.split(":");
|
||||
return parts.length == 3; // 简单的格式验证
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 从token中获取用户名
|
||||
public String getUsernameFromToken(String token) {
|
||||
try {
|
||||
String decoded = new String(Base64.getDecoder().decode(token));
|
||||
String[] parts = decoded.split(":");
|
||||
return parts.length >= 1 ? parts[0] : null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
src/main/java/com/xzzn/movecheck/wsd/AlertRequest.java
Normal file
81
src/main/java/com/xzzn/movecheck/wsd/AlertRequest.java
Normal file
@ -0,0 +1,81 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class AlertRequest {
|
||||
|
||||
private String content;
|
||||
|
||||
private String category;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime alertTime;
|
||||
|
||||
private String level;
|
||||
|
||||
private String action;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime actionTime;
|
||||
|
||||
private String deviceId;
|
||||
|
||||
// Getter 和 Setter
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public LocalDateTime getAlertTime() {
|
||||
return alertTime;
|
||||
}
|
||||
|
||||
public void setAlertTime(LocalDateTime alertTime) {
|
||||
this.alertTime = alertTime;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public LocalDateTime getActionTime() {
|
||||
return actionTime;
|
||||
}
|
||||
|
||||
public void setActionTime(LocalDateTime actionTime) {
|
||||
this.actionTime = actionTime;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
}
|
||||
69
src/main/java/com/xzzn/movecheck/wsd/AuthController.java
Normal file
69
src/main/java/com/xzzn/movecheck/wsd/AuthController.java
Normal file
@ -0,0 +1,69 @@
|
||||
// AuthController.java
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.repo.User;
|
||||
import com.xzzn.movecheck.service.AuthService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@CrossOrigin(origins = "*", maxAge = 3600)
|
||||
public class AuthController {
|
||||
|
||||
@Autowired
|
||||
private AuthService authService;
|
||||
|
||||
@PostMapping("/login")
|
||||
public LoginResponse login(@RequestBody LoginRequest loginRequest) {
|
||||
return authService.login(loginRequest);
|
||||
}
|
||||
|
||||
@PostMapping("/validate")
|
||||
public LoginResponse validateToken(@RequestHeader(value = "Authorization", required = false) String authHeader) {
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
return new LoginResponse(false, "缺少有效的token");
|
||||
}
|
||||
|
||||
String token = authHeader.substring(7);
|
||||
boolean isValid = authService.validateToken(token);
|
||||
|
||||
if (isValid) {
|
||||
Optional<User> userOpt = authService.getCurrentUser(token);
|
||||
String nickname = userOpt.map(User::getNickname).orElse("");
|
||||
return new LoginResponse(true, "Token有效", token, userOpt.map(User::getUsername).orElse(""), nickname);
|
||||
} else {
|
||||
return new LoginResponse(false, "Token无效或已过期");
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public LoginResponse logout(@RequestHeader(value = "Authorization", required = false) String authHeader) {
|
||||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||||
String token = authHeader.substring(7);
|
||||
authService.logout(token);
|
||||
}
|
||||
return new LoginResponse(true, "登出成功");
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
@GetMapping("/me")
|
||||
public LoginResponse getCurrentUser(@RequestHeader(value = "Authorization", required = false) String authHeader) {
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
return new LoginResponse(false, "未登录");
|
||||
}
|
||||
|
||||
String token = authHeader.substring(7);
|
||||
Optional<User> userOpt = authService.getCurrentUser(token);
|
||||
|
||||
if (userOpt.isPresent()) {
|
||||
User user = userOpt.get();
|
||||
return new LoginResponse(true, "获取成功", token, user.getUsername(), user.getNickname());
|
||||
} else {
|
||||
return new LoginResponse(false, "用户不存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
149
src/main/java/com/xzzn/movecheck/wsd/ClientController.java
Normal file
149
src/main/java/com/xzzn/movecheck/wsd/ClientController.java
Normal file
@ -0,0 +1,149 @@
|
||||
// controller/ClientController.java
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.service.EmqxClientService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/emqx")
|
||||
@CrossOrigin(origins = "*") // 允许跨域访问
|
||||
public class ClientController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClientController.class);
|
||||
|
||||
private final EmqxClientService emqxClientService;
|
||||
|
||||
public ClientController(EmqxClientService emqxClientService) {
|
||||
this.emqxClientService = emqxClientService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端详细信息
|
||||
* GET /api/emqx/clients/{clientId}
|
||||
*/
|
||||
@GetMapping("/clients/{clientId}")
|
||||
public ResponseEntity<?> getClientInfo(@PathVariable String clientId) {
|
||||
try {
|
||||
logger.info("收到获取客户端信息请求: {}", clientId);
|
||||
ClientInfo clientInfo = emqxClientService.getClientInfo(clientId);
|
||||
return ResponseEntity.ok(clientInfo);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取客户端信息失败: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("GET_CLIENT_INFO_FAILED", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查客户端在线状态
|
||||
* GET /api/emqx/clients/{clientId}/status
|
||||
*/
|
||||
@GetMapping("/clients/{clientId}/status")
|
||||
public ResponseEntity<?> getClientStatus(@PathVariable String clientId) {
|
||||
try {
|
||||
logger.info("收到检查客户端状态请求: {}", clientId);
|
||||
boolean isOnline = emqxClientService.isClientOnline(clientId);
|
||||
return ResponseEntity.ok(new StatusResponse(clientId, isOnline));
|
||||
} catch (Exception e) {
|
||||
logger.error("检查客户端状态失败: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("CHECK_CLIENT_STATUS_FAILED", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端详细状态
|
||||
* GET /api/emqx/clients/{clientId}/detail-status
|
||||
*/
|
||||
@GetMapping("/clients/{clientId}/detail-status")
|
||||
public ResponseEntity<?> getClientDetailStatus(@PathVariable String clientId) {
|
||||
try {
|
||||
logger.info("收到获取客户端详细状态请求: {}", clientId);
|
||||
EmqxClientService.ClientStatusResponse status = emqxClientService.getClientStatus(clientId);
|
||||
return ResponseEntity.ok(status);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取客户端详细状态失败: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("GET_CLIENT_DETAIL_STATUS_FAILED", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有客户端列表
|
||||
* GET /api/emqx/clients
|
||||
*/
|
||||
@GetMapping("/clients")
|
||||
public ResponseEntity<?> getAllClients() {
|
||||
try {
|
||||
logger.info("收到获取所有客户端列表请求");
|
||||
String clients = emqxClientService.getAllClients();
|
||||
return ResponseEntity.ok(clients);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取客户端列表失败: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("GET_ALL_CLIENTS_FAILED", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 健康检查接口
|
||||
* GET /api/emqx/health
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<?> healthCheck() {
|
||||
return ResponseEntity.ok(new HealthResponse("OK", "EMQX API Service is running"));
|
||||
}
|
||||
|
||||
// 响应包装类
|
||||
public static class StatusResponse {
|
||||
private String clientId;
|
||||
private boolean online;
|
||||
|
||||
public StatusResponse(String clientId, boolean online) {
|
||||
this.clientId = clientId;
|
||||
this.online = online;
|
||||
}
|
||||
|
||||
public String getClientId() { return clientId; }
|
||||
public void setClientId(String clientId) { this.clientId = clientId; }
|
||||
|
||||
public boolean isOnline() { return online; }
|
||||
public void setOnline(boolean online) { this.online = online; }
|
||||
}
|
||||
|
||||
public static class ErrorResponse {
|
||||
private String error;
|
||||
private String message;
|
||||
|
||||
public ErrorResponse(String error, String message) {
|
||||
this.error = error;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getError() { return error; }
|
||||
public void setError(String error) { this.error = error; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
}
|
||||
|
||||
public static class HealthResponse {
|
||||
private String status;
|
||||
private String message;
|
||||
|
||||
public HealthResponse(String status, String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
}
|
||||
}
|
||||
57
src/main/java/com/xzzn/movecheck/wsd/ClientInfo.java
Normal file
57
src/main/java/com/xzzn/movecheck/wsd/ClientInfo.java
Normal file
@ -0,0 +1,57 @@
|
||||
// model/ClientInfo.java
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ClientInfo {
|
||||
@JsonProperty("clientid")
|
||||
private String clientId;
|
||||
|
||||
@JsonProperty("username")
|
||||
private String username;
|
||||
|
||||
@JsonProperty("connected")
|
||||
private Boolean connected;
|
||||
|
||||
@JsonProperty("ip_address")
|
||||
private String ipAddress;
|
||||
|
||||
@JsonProperty("connected_at")
|
||||
private Date connectedAt;
|
||||
|
||||
@JsonProperty("disconnected_at")
|
||||
private Date disconnectedAt;
|
||||
|
||||
// getters and setters
|
||||
public String getClientId() { return clientId; }
|
||||
public void setClientId(String clientId) { this.clientId = clientId; }
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public Boolean getConnected() { return connected; }
|
||||
public void setConnected(Boolean connected) { this.connected = connected; }
|
||||
|
||||
public String getIpAddress() { return ipAddress; }
|
||||
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
|
||||
|
||||
public Date getConnectedAt() { return connectedAt; }
|
||||
public void setConnectedAt(Date connectedAt) { this.connectedAt = connectedAt; }
|
||||
|
||||
public Date getDisconnectedAt() { return disconnectedAt; }
|
||||
public void setDisconnectedAt(Date disconnectedAt) { this.disconnectedAt = disconnectedAt; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientInfo{" +
|
||||
"clientId='" + clientId + '\'' +
|
||||
", username='" + username + '\'' +
|
||||
", connected=" + connected +
|
||||
", ipAddress='" + ipAddress + '\'' +
|
||||
", connectedAt=" + connectedAt +
|
||||
", disconnectedAt=" + disconnectedAt +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package com.xzzn.movecheck.wsd;// ClimateThresholdController.java
|
||||
|
||||
import com.xzzn.movecheck.repo.ClimateThreshold;
|
||||
import com.xzzn.movecheck.service.ClimateThresholdService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/wsd")
|
||||
public class ClimateThresholdController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClimateThresholdController.class);
|
||||
|
||||
@Autowired
|
||||
private ClimateThresholdService thresholdService;
|
||||
|
||||
// 创建新的阈值设置
|
||||
@PostMapping
|
||||
public ResponseEntity<?> createThreshold(@RequestBody ClimateThreshold threshold) {
|
||||
try {
|
||||
ClimateThreshold saved = thresholdService.saveThreshold(threshold);
|
||||
return ResponseEntity.ok(saved);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有阈值设置
|
||||
@GetMapping
|
||||
public List<ClimateThreshold> getAllThresholds() {
|
||||
return thresholdService.findAll();
|
||||
}
|
||||
|
||||
// 根据ID获取阈值设置
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ClimateThreshold> getThresholdById(@PathVariable Long id) {
|
||||
Optional<ClimateThreshold> threshold = thresholdService.findById(id);
|
||||
|
||||
logger.info("getThresholdById id: {}, threshold: {}", id, threshold);
|
||||
return threshold.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
// 根据名称获取阈值设置
|
||||
@GetMapping("/name/{settingName}")
|
||||
public ResponseEntity<ClimateThreshold> getThresholdByName(@PathVariable String settingName) {
|
||||
Optional<ClimateThreshold> threshold = thresholdService.findBySettingName(settingName);
|
||||
return threshold.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
// 更新阈值设置
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<?> updateThreshold(@PathVariable Long id, @RequestBody ClimateThreshold threshold) {
|
||||
threshold.setId(id);
|
||||
try {
|
||||
ClimateThreshold updated = thresholdService.saveThreshold(threshold);
|
||||
return ResponseEntity.ok(updated);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 删除阈值设置
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Void> deleteThreshold(@PathVariable Long id) {
|
||||
thresholdService.deleteById(id);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
// 检查环境状态
|
||||
@GetMapping("/check-status")
|
||||
public ResponseEntity<String> checkStatus(
|
||||
@RequestParam String settingName,
|
||||
@RequestParam BigDecimal temperature,
|
||||
@RequestParam BigDecimal humidity) {
|
||||
|
||||
String status = thresholdService.checkEnvironmentStatus(settingName, temperature, humidity);
|
||||
return ResponseEntity.ok(status);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
|
||||
public class ClimateThresholdRequest {
|
||||
private Double wdmin;
|
||||
|
||||
private Double wdmax;
|
||||
|
||||
private Double sdmin;
|
||||
|
||||
private Double sdmax;
|
||||
|
||||
public Double getWdmin() {
|
||||
return wdmin;
|
||||
}
|
||||
|
||||
public void setWdmin(Double wdmin) {
|
||||
this.wdmin = wdmin;
|
||||
}
|
||||
|
||||
public Double getWdmax() {
|
||||
return wdmax;
|
||||
}
|
||||
|
||||
public void setWdmax(Double wdmax) {
|
||||
this.wdmax = wdmax;
|
||||
}
|
||||
|
||||
public Double getSdmin() {
|
||||
return sdmin;
|
||||
}
|
||||
|
||||
public void setSdmin(Double sdmin) {
|
||||
this.sdmin = sdmin;
|
||||
}
|
||||
|
||||
public Double getSdmax() {
|
||||
return sdmax;
|
||||
}
|
||||
|
||||
public void setSdmax(Double sdmax) {
|
||||
this.sdmax = sdmax;
|
||||
}
|
||||
}
|
||||
71
src/main/java/com/xzzn/movecheck/wsd/DataController.java
Normal file
71
src/main/java/com/xzzn/movecheck/wsd/DataController.java
Normal file
@ -0,0 +1,71 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.repo.SensorData;
|
||||
import com.xzzn.movecheck.repo.SensorDataRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/data")
|
||||
@CrossOrigin(origins = "*")
|
||||
public class DataController {
|
||||
|
||||
@Autowired
|
||||
private SensorDataRepository sensorDataRepository;
|
||||
|
||||
// 获取最新数据
|
||||
@GetMapping("/latest")
|
||||
public ResponseEntity<Map<String, Object>> getLatestData() {
|
||||
List<SensorData> dataList = sensorDataRepository.findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
if (!dataList.isEmpty()) {
|
||||
SensorData latest = dataList.get(0);
|
||||
response.put("sd", latest.getSd());
|
||||
response.put("wd", latest.getWd());
|
||||
response.put("pm", latest.getPm());
|
||||
response.put("timestamp", latest.getCreateTime());
|
||||
response.put("status", "success");
|
||||
} else {
|
||||
response.put("status", "no_data");
|
||||
response.put("message", "暂无数据");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
// 获取历史数据
|
||||
@PostMapping("/history")
|
||||
public ResponseEntity<List<SensorData>> getHistoryData(@RequestBody TimeRangeRequest request) {
|
||||
List<SensorData> dataList = sensorDataRepository.findByCreateTimeBetween(request.getStartTime(), request.getEndTime());
|
||||
return ResponseEntity.ok(dataList);
|
||||
}
|
||||
|
||||
// 获取指定数据
|
||||
@GetMapping("/current")
|
||||
public ResponseEntity<Map<String, Object>> getCurrentData() {
|
||||
List<SensorData> dataList = sensorDataRepository.findTop10ByOrderByCreateTimeDesc();
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
if (!dataList.isEmpty()) {
|
||||
SensorData current = dataList.get(0);
|
||||
response.put("sd", current.getSd());
|
||||
response.put("wd", current.getWd());
|
||||
response.put("pm", current.getWd());
|
||||
|
||||
} else {
|
||||
response.put("sd", 0);
|
||||
response.put("wd", 0);
|
||||
response.put("pm", 0);
|
||||
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
22
src/main/java/com/xzzn/movecheck/wsd/EmqxApiResponse.java
Normal file
22
src/main/java/com/xzzn/movecheck/wsd/EmqxApiResponse.java
Normal file
@ -0,0 +1,22 @@
|
||||
// EmqxApiResponse.java
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.repo.EmqxClientInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EmqxApiResponse {
|
||||
private Integer code;
|
||||
private String message;
|
||||
private List<EmqxClientInfo> data;
|
||||
|
||||
// Getter和Setter
|
||||
public Integer getCode() { return code; }
|
||||
public void setCode(Integer code) { this.code = code; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public List<EmqxClientInfo> getData() { return data; }
|
||||
public void setData(List<EmqxClientInfo> data) { this.data = data; }
|
||||
}
|
||||
190
src/main/java/com/xzzn/movecheck/wsd/EventAlertController.java
Normal file
190
src/main/java/com/xzzn/movecheck/wsd/EventAlertController.java
Normal file
@ -0,0 +1,190 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.service.EventAlertService;
|
||||
import com.xzzn.movecheck.repo.AlertData;
|
||||
import com.xzzn.movecheck.repo.EventData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
@CrossOrigin(origins = "*")
|
||||
@Validated
|
||||
public class EventAlertController {
|
||||
|
||||
@Autowired
|
||||
private EventAlertService eventAlertService;
|
||||
|
||||
// ==================== 事件相关API ====================
|
||||
|
||||
/**
|
||||
* 保存事件数据
|
||||
*/
|
||||
@PostMapping("/events")
|
||||
public ResponseEntity<Map<String, Object>> saveEvent( @RequestBody EventRequest request) {
|
||||
Map<String, Object> result = eventAlertService.saveEvent(request);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新10条事件
|
||||
*/
|
||||
@GetMapping("/events/latest")
|
||||
public ResponseEntity<Map<String, Object>> getLatestEvents() {
|
||||
List<EventData> events = eventAlertService.getLatestEvents();
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("data", events);
|
||||
response.put("total", events.size());
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取事件数据
|
||||
*/
|
||||
@GetMapping("/events")
|
||||
public ResponseEntity<PageResponse<EventData>> getEventsByPage(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
|
||||
Page<EventData> eventPage = eventAlertService.getEventsByPage(page, size);
|
||||
PageResponse<EventData> response = PageResponse.success(eventPage);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
// ==================== 告警相关API ====================
|
||||
|
||||
/**
|
||||
* 保存告警数据
|
||||
*/
|
||||
@PostMapping("/alerts")
|
||||
public ResponseEntity<Map<String, Object>> saveAlert( @RequestBody AlertRequest request) {
|
||||
Map<String, Object> result = eventAlertService.saveAlert(request);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新10条告警
|
||||
*/
|
||||
@GetMapping("/alerts/latest")
|
||||
public ResponseEntity<Map<String, Object>> getLatestAlerts() {
|
||||
List<AlertData> alerts = eventAlertService.getLatestAlerts();
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("data", alerts);
|
||||
response.put("total", alerts.size());
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取告警数据
|
||||
*/
|
||||
@GetMapping("/alerts")
|
||||
public ResponseEntity<PageResponse<AlertData>> getAlertsByPage(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
|
||||
Page<AlertData> alertPage = eventAlertService.getAlertsByPage(page, size);
|
||||
PageResponse<AlertData> response = PageResponse.success(alertPage);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据创建时间范围查询事件数据
|
||||
*/
|
||||
@GetMapping("/events/byCreateTime")
|
||||
public ResponseEntity<Map<String, Object>> getEventsByCreateTime(
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
// 将字符串时间转换为 LocalDateTime
|
||||
LocalDateTime start = null;
|
||||
LocalDateTime end = null;
|
||||
|
||||
if (startTime != null && !startTime.isEmpty()) {
|
||||
start = parseTimeString(startTime);
|
||||
}
|
||||
|
||||
if (endTime != null && !endTime.isEmpty()) {
|
||||
end = parseTimeString(endTime);
|
||||
}
|
||||
Page<EventData> eventPage = eventAlertService.getEventsByCreateTime(start, end, page, size);
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("data", eventPage.getContent());
|
||||
response.put("total", eventPage.getTotalElements());
|
||||
response.put("currentPage", eventPage.getNumber());
|
||||
response.put("totalPages", eventPage.getTotalPages());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据创建时间范围查询告警数据
|
||||
*/
|
||||
@GetMapping("/alerts/byCreateTime")
|
||||
public ResponseEntity<Map<String, Object>> getAlertsByCreateTime(
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
// 将字符串时间转换为 LocalDateTime
|
||||
LocalDateTime start = null;
|
||||
LocalDateTime end = null;
|
||||
|
||||
if (startTime != null && !startTime.isEmpty()) {
|
||||
start = parseTimeString(startTime);
|
||||
}
|
||||
|
||||
if (endTime != null && !endTime.isEmpty()) {
|
||||
end = parseTimeString(endTime);
|
||||
}
|
||||
Page<AlertData> alertPage = eventAlertService.getAlertsByCreateTime(start, end, page, size);
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("data", alertPage.getContent());
|
||||
response.put("total", alertPage.getTotalElements());
|
||||
response.put("currentPage", alertPage.getNumber());
|
||||
response.put("totalPages", alertPage.getTotalPages());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析时间字符串为 LocalDateTime
|
||||
*/
|
||||
private LocalDateTime parseTimeString(String timeStr) {
|
||||
try {
|
||||
// 支持多种时间格式
|
||||
if (timeStr.contains("T")) {
|
||||
// ISO 格式: 2025-10-10T10:00:00
|
||||
return LocalDateTime.parse(timeStr);
|
||||
} else if (timeStr.contains(":")) {
|
||||
// 格式: 2025-10-10 10:00:00
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
return LocalDateTime.parse(timeStr, formatter);
|
||||
} else {
|
||||
// 日期格式: 2025-10-10
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
LocalDate date = LocalDate.parse(timeStr, formatter);
|
||||
return date.atStartOfDay();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("无效的时间格式: " + timeStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/main/java/com/xzzn/movecheck/wsd/EventRequest.java
Normal file
60
src/main/java/com/xzzn/movecheck/wsd/EventRequest.java
Normal file
@ -0,0 +1,60 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class EventRequest {
|
||||
|
||||
private String eventType;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime eventTime;
|
||||
|
||||
private String status;
|
||||
|
||||
private String description;
|
||||
|
||||
private String deviceId;
|
||||
|
||||
// Getter 和 Setter
|
||||
public String getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(String eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
public LocalDateTime getEventTime() {
|
||||
return eventTime;
|
||||
}
|
||||
|
||||
public void setEventTime(LocalDateTime eventTime) {
|
||||
this.eventTime = eventTime;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.repo.HealthDevice;
|
||||
import com.xzzn.movecheck.service.HealthDeviceService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
// 在Controller中使用
|
||||
@RestController
|
||||
@RequestMapping("/api/health")
|
||||
public class HealthDeviceController {
|
||||
|
||||
@Autowired
|
||||
private HealthDeviceService healthDeviceService;
|
||||
|
||||
/**
|
||||
* 获取最新的设备数据
|
||||
*/
|
||||
@GetMapping("/latest")
|
||||
public ResponseEntity<?> getLatestRecord() {
|
||||
List<HealthDevice> latestRecord = healthDeviceService.findLatestRecord();
|
||||
|
||||
if (latestRecord != null && !latestRecord.isEmpty()) {
|
||||
return ResponseEntity.ok(latestRecord.get(0));
|
||||
} else {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body("未找到设备数据");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
21
src/main/java/com/xzzn/movecheck/wsd/LoginRequest.java
Normal file
21
src/main/java/com/xzzn/movecheck/wsd/LoginRequest.java
Normal file
@ -0,0 +1,21 @@
|
||||
// LoginRequest.java
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
public class LoginRequest {
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public LoginRequest() {}
|
||||
|
||||
public LoginRequest(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
// Getter和Setter
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
}
|
||||
44
src/main/java/com/xzzn/movecheck/wsd/LoginResponse.java
Normal file
44
src/main/java/com/xzzn/movecheck/wsd/LoginResponse.java
Normal file
@ -0,0 +1,44 @@
|
||||
// LoginResponse.java
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
public class LoginResponse {
|
||||
private boolean success;
|
||||
private String message;
|
||||
private String token;
|
||||
private String username;
|
||||
private String nickname;
|
||||
|
||||
// 无参构造
|
||||
public LoginResponse() {}
|
||||
|
||||
// 只有success和message的构造
|
||||
public LoginResponse(boolean success, String message) {
|
||||
this.success = success;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
// 包含所有字段的构造
|
||||
public LoginResponse(boolean success, String message, String token, String username, String nickname) {
|
||||
this.success = success;
|
||||
this.message = message;
|
||||
this.token = token;
|
||||
this.username = username;
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
// Getter和Setter
|
||||
public boolean isSuccess() { return success; }
|
||||
public void setSuccess(boolean success) { this.success = success; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public String getToken() { return token; }
|
||||
public void setToken(String token) { this.token = token; }
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getNickname() { return nickname; }
|
||||
public void setNickname(String nickname) { this.nickname = nickname; }
|
||||
}
|
||||
116
src/main/java/com/xzzn/movecheck/wsd/PageResponse.java
Normal file
116
src/main/java/com/xzzn/movecheck/wsd/PageResponse.java
Normal file
@ -0,0 +1,116 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import java.util.List;
|
||||
|
||||
public class PageResponse<T> {
|
||||
private String status;
|
||||
private String message;
|
||||
private List<T> data;
|
||||
private int currentPage;
|
||||
private int pageSize;
|
||||
private long totalElements;
|
||||
private int totalPages;
|
||||
private boolean hasNext;
|
||||
private boolean hasPrevious;
|
||||
|
||||
// 构造函数
|
||||
public PageResponse() {}
|
||||
|
||||
public PageResponse(String status, String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
// 从Spring Page对象创建响应
|
||||
public static <T> PageResponse<T> success(Page<T> page) {
|
||||
PageResponse<T> response = new PageResponse<>();
|
||||
response.status = "success";
|
||||
response.message = "查询成功";
|
||||
response.data = page.getContent();
|
||||
response.currentPage = page.getNumber();
|
||||
response.pageSize = page.getSize();
|
||||
response.totalElements = page.getTotalElements();
|
||||
response.totalPages = page.getTotalPages();
|
||||
response.hasNext = page.hasNext();
|
||||
response.hasPrevious = page.hasPrevious();
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> PageResponse<T> error(String message) {
|
||||
return new PageResponse<>("error", message);
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public List<T> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<T> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getCurrentPage() {
|
||||
return currentPage;
|
||||
}
|
||||
|
||||
public void setCurrentPage(int currentPage) {
|
||||
this.currentPage = currentPage;
|
||||
}
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public long getTotalElements() {
|
||||
return totalElements;
|
||||
}
|
||||
|
||||
public void setTotalElements(long totalElements) {
|
||||
this.totalElements = totalElements;
|
||||
}
|
||||
|
||||
public int getTotalPages() {
|
||||
return totalPages;
|
||||
}
|
||||
|
||||
public void setTotalPages(int totalPages) {
|
||||
this.totalPages = totalPages;
|
||||
}
|
||||
|
||||
public boolean isHasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
public void setHasNext(boolean hasNext) {
|
||||
this.hasNext = hasNext;
|
||||
}
|
||||
|
||||
public boolean isHasPrevious() {
|
||||
return hasPrevious;
|
||||
}
|
||||
|
||||
public void setHasPrevious(boolean hasPrevious) {
|
||||
this.hasPrevious = hasPrevious;
|
||||
}
|
||||
}
|
||||
52
src/main/java/com/xzzn/movecheck/wsd/SubscriptionStatus.java
Normal file
52
src/main/java/com/xzzn/movecheck/wsd/SubscriptionStatus.java
Normal file
@ -0,0 +1,52 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
// 订阅状态数据模型
|
||||
public class SubscriptionStatus {
|
||||
private String topic;
|
||||
private boolean subscribed;
|
||||
private int qos;
|
||||
private long subscribeTime;
|
||||
private String errorMessage;
|
||||
|
||||
// getters and setters
|
||||
|
||||
public String getTopic() {
|
||||
return topic;
|
||||
}
|
||||
|
||||
public void setTopic(String topic) {
|
||||
this.topic = topic;
|
||||
}
|
||||
|
||||
public boolean isSubscribed() {
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
public void setSubscribed(boolean subscribed) {
|
||||
this.subscribed = subscribed;
|
||||
}
|
||||
|
||||
public int getQos() {
|
||||
return qos;
|
||||
}
|
||||
|
||||
public void setQos(int qos) {
|
||||
this.qos = qos;
|
||||
}
|
||||
|
||||
public long getSubscribeTime() {
|
||||
return subscribeTime;
|
||||
}
|
||||
|
||||
public void setSubscribeTime(long subscribeTime) {
|
||||
this.subscribeTime = subscribeTime;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.xzzn.movecheck.service.TemperatureHumidityService;
|
||||
import com.xzzn.movecheck.repo.TemperatureHumidityData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/ac")
|
||||
@CrossOrigin(origins = "*")
|
||||
@Validated
|
||||
public class TemperatureHumidityController {
|
||||
|
||||
@Autowired
|
||||
private TemperatureHumidityService temperatureHumidityService;
|
||||
|
||||
/**
|
||||
* 保存温湿度数据
|
||||
*/
|
||||
@PostMapping("/data")
|
||||
public ResponseEntity<TemperatureHumidityResponse> saveTemperatureHumidity(
|
||||
@RequestBody TemperatureHumidityRequest request) {
|
||||
|
||||
TemperatureHumidityResponse response = temperatureHumidityService.saveData(request);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新温湿度数据
|
||||
*/
|
||||
@GetMapping("/data/latest")
|
||||
public ResponseEntity<TemperatureHumidityResponse> getLatestTemperatureHumidity() {
|
||||
TemperatureHumidityResponse response = temperatureHumidityService.getLatestData();
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID获取最新数据
|
||||
*/
|
||||
@GetMapping("/data/latest/device/{deviceId}")
|
||||
public ResponseEntity<TemperatureHumidityResponse> getLatestTemperatureHumidityByDevice(
|
||||
@PathVariable String deviceId) {
|
||||
|
||||
TemperatureHumidityResponse response = temperatureHumidityService.getLatestByDevice(deviceId);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新10条温湿度数据
|
||||
*/
|
||||
@GetMapping("/data/recent")
|
||||
public ResponseEntity<TemperatureHumidityResponse> getRecentTemperatureHumidity() {
|
||||
TemperatureHumidityResponse response = temperatureHumidityService.getLatest10Data();
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID获取最新10条数据
|
||||
*/
|
||||
@GetMapping("/data/recent/device/{deviceId}")
|
||||
public ResponseEntity<TemperatureHumidityResponse> getRecentTemperatureHumidityByDevice(
|
||||
@PathVariable String deviceId) {
|
||||
|
||||
TemperatureHumidityResponse response = temperatureHumidityService.getLatest10ByDevice(deviceId);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询温湿度数据
|
||||
*/
|
||||
@GetMapping("/data")
|
||||
public ResponseEntity<Map<String, Object>> getTemperatureHumidityByPage(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
|
||||
Page<TemperatureHumidityData> dataPage = temperatureHumidityService.getDataByPage(page, size);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("data", dataPage.getContent());
|
||||
response.put("currentPage", dataPage.getNumber());
|
||||
response.put("pageSize", dataPage.getSize());
|
||||
response.put("totalElements", dataPage.getTotalElements());
|
||||
response.put("totalPages", dataPage.getTotalPages());
|
||||
response.put("hasNext", dataPage.hasNext());
|
||||
response.put("hasPrevious", dataPage.hasPrevious());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID分页查询
|
||||
*/
|
||||
@GetMapping("/data/device/{deviceId}")
|
||||
public ResponseEntity<Map<String, Object>> getTemperatureHumidityByDeviceAndPage(
|
||||
@PathVariable String deviceId,
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "10") int size) {
|
||||
|
||||
Page<TemperatureHumidityData> dataPage = temperatureHumidityService.getDataByDeviceAndPage(deviceId, page, size);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("deviceId", deviceId);
|
||||
response.put("data", dataPage.getContent());
|
||||
response.put("currentPage", dataPage.getNumber());
|
||||
response.put("pageSize", dataPage.getSize());
|
||||
response.put("totalElements", dataPage.getTotalElements());
|
||||
response.put("totalPages", dataPage.getTotalPages());
|
||||
response.put("hasNext", dataPage.hasNext());
|
||||
response.put("hasPrevious", dataPage.hasPrevious());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有设备ID列表
|
||||
*/
|
||||
@GetMapping("/devices")
|
||||
public ResponseEntity<Map<String, Object>> getAllDevices() {
|
||||
List<String> deviceIds = temperatureHumidityService.getAllDeviceIds();
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("devices", deviceIds);
|
||||
response.put("total", deviceIds.size());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据统计
|
||||
*/
|
||||
@GetMapping("/stats")
|
||||
public ResponseEntity<Map<String, Object>> getStats() {
|
||||
long totalCount = temperatureHumidityService.getTotalCount();
|
||||
List<String> deviceIds = temperatureHumidityService.getAllDeviceIds();
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("status", "success");
|
||||
response.put("totalRecords", totalCount);
|
||||
response.put("totalDevices", deviceIds.size());
|
||||
response.put("devices", deviceIds);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
|
||||
public class TemperatureHumidityRequest {
|
||||
|
||||
private Double temperature;
|
||||
|
||||
private Double humidity;
|
||||
|
||||
private String deviceId;
|
||||
|
||||
// Getter 和 Setter
|
||||
public Double getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(Double temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public Double getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(Double humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.xzzn.movecheck.repo.TemperatureHumidityData;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class TemperatureHumidityResponse {
|
||||
private String status;
|
||||
private String message;
|
||||
private Double temperature;
|
||||
private Double humidity;
|
||||
private String deviceId;
|
||||
private LocalDateTime createTime;
|
||||
private List<TemperatureHumidityData> dataList;
|
||||
private Long total;
|
||||
|
||||
// 构造函数
|
||||
public TemperatureHumidityResponse() {}
|
||||
|
||||
public TemperatureHumidityResponse(String status, String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
// 从实体创建响应
|
||||
public static TemperatureHumidityResponse fromEntity(TemperatureHumidityData entity) {
|
||||
TemperatureHumidityResponse response = new TemperatureHumidityResponse();
|
||||
response.status = "success";
|
||||
response.message = "获取成功";
|
||||
response.temperature = entity.getTemperature();
|
||||
response.humidity = entity.getHumidity();
|
||||
response.deviceId = entity.getDeviceId();
|
||||
response.createTime = entity.getCreateTime();
|
||||
return response;
|
||||
}
|
||||
|
||||
public static TemperatureHumidityResponse success(String message) {
|
||||
return new TemperatureHumidityResponse("success", message);
|
||||
}
|
||||
|
||||
public static TemperatureHumidityResponse error(String message) {
|
||||
return new TemperatureHumidityResponse("error", message);
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Double getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(Double temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public Double getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(Double humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public List<TemperatureHumidityData> getDataList() {
|
||||
return dataList;
|
||||
}
|
||||
|
||||
public void setDataList(List<TemperatureHumidityData> dataList) {
|
||||
this.dataList = dataList;
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(Long total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
64
src/main/java/com/xzzn/movecheck/wsd/TimeRangeRequest.java
Normal file
64
src/main/java/com/xzzn/movecheck/wsd/TimeRangeRequest.java
Normal file
@ -0,0 +1,64 @@
|
||||
package com.xzzn.movecheck.wsd;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class TimeRangeRequest {
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
private String deviceId;
|
||||
|
||||
// 构造函数
|
||||
public TimeRangeRequest() {}
|
||||
|
||||
public TimeRangeRequest(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public TimeRangeRequest(LocalDateTime startTime, LocalDateTime endTime, String deviceId) {
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public LocalDateTime getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(LocalDateTime startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(LocalDateTime endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
// 验证时间范围是否有效
|
||||
public boolean isValid() {
|
||||
return startTime != null && endTime != null && !startTime.isAfter(endTime);
|
||||
}
|
||||
|
||||
// 获取时间范围描述
|
||||
public String getTimeRangeDescription() {
|
||||
return String.format("%s 至 %s", startTime, endTime);
|
||||
}
|
||||
}
|
||||
23
src/main/resources/application.yml
Normal file
23
src/main/resources/application.yml
Normal file
@ -0,0 +1,23 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://122.51.194.184:13306/movecheck?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: movecheck
|
||||
password: 8a7c97e5c31c
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQL5Dialect
|
||||
|
||||
mqtt:
|
||||
broker: tcp://122.51.194.184:1883
|
||||
clientId: movecheck-client
|
||||
topics: HDYDCJ_01_DEVICE,HDYDCJ_01_UP
|
||||
username: dmbroker
|
||||
password: qwer1234
|
||||
qos: 1,1
|
||||
server:
|
||||
port: 7999
|
||||
100
src/main/resources/logback-spring.xml
Normal file
100
src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="30 seconds">
|
||||
|
||||
<!-- 定义日志文件输出路径 -->
|
||||
<property name="LOG_HOME" value="./logs"/>
|
||||
<property name="APP_NAME" value="mqtt-config-api"/>
|
||||
|
||||
<!-- 控制台输出格式 -->
|
||||
<property name="CONSOLE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger{36} - %msg%n"/>
|
||||
|
||||
<!-- 文件输出格式 -->
|
||||
<property name="FILE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 信息日志文件 -->
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${APP_NAME}-info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/archive/${APP_NAME}-info-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>1GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FILE_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 错误日志文件 -->
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${APP_NAME}-error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/archive/${APP_NAME}-error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>1GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FILE_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>ERROR</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- API调用详细日志 -->
|
||||
<appender name="API_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${APP_NAME}-api.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/archive/${APP_NAME}-api-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<maxHistory>7</maxHistory>
|
||||
<totalSizeCap>500MB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FILE_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 特定包级别的日志配置 -->
|
||||
<logger name="com.xzzn.movecheck.controller" level="INFO" additivity="false">
|
||||
<appender-ref ref="API_FILE"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="com.xzzn.movecheck" level="INFO" additivity="false">
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</logger>
|
||||
|
||||
<!-- Spring框架日志级别 -->
|
||||
<logger name="org.springframework" level="WARN"/>
|
||||
<logger name="org.apache" level="WARN"/>
|
||||
<logger name="com.zaxxer" level="WARN"/>
|
||||
|
||||
<!-- 根日志配置 -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user