SpringBoot與InfluxDB整合,實現(xiàn)智能電表數(shù)據(jù)采集系統(tǒng)
作者:Java知識日歷
InfluxDB是一個分布式時序數(shù)據(jù)庫,專門用于存儲和查詢大規(guī)模的時間序列數(shù)據(jù)。廣泛應用于監(jiān)控系統(tǒng)、物聯(lián)網(wǎng)(IoT)、金融數(shù)據(jù)分析等領域。
InfluxDB是一個分布式時序數(shù)據(jù)庫,專門用于存儲和查詢大規(guī)模的時間序列數(shù)據(jù)。廣泛應用于監(jiān)控系統(tǒng)、物聯(lián)網(wǎng)(IoT)、金融數(shù)據(jù)分析等領域。
這個項目為什么使用InfluxDB?
- InfluxDB采用優(yōu)化的數(shù)據(jù)結構和壓縮算法,能夠在高并發(fā)情況下保持高效的寫入性能。
- 支持復雜的查詢語言(如Flux),可以輕松進行聚合、過濾和分析操作。
- InfluxDB 提供了內(nèi)置的數(shù)據(jù)保留策略(Retention Policies),可以根據(jù)需要自動刪除舊數(shù)據(jù),從而有效地管理存儲空間。
- InfluxDB 支持多種高級數(shù)據(jù)分析功能,可以更好分析利用電表數(shù)據(jù)。
哪些公司使用了InfluxDB?
- Netflix 使用 InfluxDB 來監(jiān)控其全球流媒體服務的性能指標。
- 特斯拉使用 InfluxDB 來存儲和分析電動汽車的各種傳感器數(shù)據(jù)。
- Spotify 使用 InfluxDB 來監(jiān)控其音頻流媒體平臺的各項指標。
- 思科使用 InfluxDB 來收集和分析網(wǎng)絡設備的日志和性能數(shù)據(jù)。
- Airbnb 使用 InfluxDB 來收集和分析用戶活動數(shù)據(jù)。
- Bosch使用 InfluxDB 來收集和分析工業(yè)自動化系統(tǒng)的數(shù)據(jù)。
- 西門子使用 InfluxDB 來處理工業(yè)控制系統(tǒng)的數(shù)據(jù)。
代碼實操
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- InfluxDB Client Library -->
<dependency>
<groupId>com.influxdb</groupId>
<artifactId>influxdb-client-java</artifactId>
<version>6.8.0</version>
</dependency>
<!-- Lombok for concise code -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Jackson Databind for JSON processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
application.properties
# InfluxDB Configuration
influx.url=http://localhost:8086
influx.token=my-token
influx.org=my-org
influx.bucket=my-bucket
電表數(shù)據(jù)的數(shù)據(jù)模型
package com.example.smartmeter.model;
import lombok.Data;
import java.time.Instant;
/**
* 表示電表數(shù)據(jù)的數(shù)據(jù)模型
*/
@Data
public class ElectricMeterData {
private String meterId; // 電表ID
private double energyConsumption; // 能耗(單位:千瓦時)
private Instant timestamp; // 時間戳
}
費率配置的數(shù)據(jù)模型
package com.example.smartmeter.model;
import lombok.Data;
import java.util.Map;
/**
* 表示費率配置的數(shù)據(jù)模型
*/
@Data
public class RateConfig {
private Map<String, Double> peakRates; // 峰時段費率,鍵為小時數(shù)(例如:"07", "08"),值為每千瓦時費率
private Map<String, Double> offPeakRates; // 谷時段費率,鍵為小時數(shù)(例如:"23", "00"),值為每千瓦時費率
private Map<String, Double> holidayRates; // 節(jié)假日費率,鍵為日期(例如:"2025-12-25"),值為每千瓦時費率
}
加載費率配置
我只是做個Demo出來,給大家感受一下,就簡單一點吧。使用一個JSON文件中加載費率配置,位置就隨手放在resources/rates.json
{
"peakRates": {
"07": 0.15,
"08": 0.15,
"09": 0.15,
"10": 0.15,
"11": 0.15,
"12": 0.15,
"13": 0.15,
"14": 0.15,
"15": 0.15,
"16": 0.15,
"17": 0.15,
"18": 0.15,
"19": 0.15,
"20": 0.15,
"21": 0.15,
"22": 0.15
},
"offPeakRates": {
"00": 0.10,
"01": 0.10,
"02": 0.10,
"03": 0.10,
"04": 0.10,
"05": 0.10,
"06": 0.10,
"23": 0.10
},
"holidayRates": {
"2025-12-25": 0.05,
"2025-01-01": 0.05
}
}
加載和管理費率配置的服務類
package com.example.smartmeter.service;
import com.example.smartmeter.model.RateConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException;
/**
* 用于加載和管理費率配置的服務類
*/
@Service
public class RateConfigService {
@Value("classpath:rates.json")
private Resource ratesResource; // 指定費率配置文件路徑
private RateConfig rateConfig; // 存儲費率配置的對象
/**
* 在Bean初始化后加載費率配置文件
*/
@PostConstruct
public void init() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(); // 使用Jackson解析JSON
rateConfig = objectMapper.readValue(ratesResource.getInputStream(), RateConfig.class); // 讀取并解析JSON文件
}
/**
* 獲取當前的費率配置
*
* @return 當前的費率配置對象
*/
public RateConfig getRateConfig() {
return rateConfig;
}
}
處理電表數(shù)據(jù)采集和服務的服務類
package com.example.smartmeter.service;
import com.example.smartmeter.model.ElectricMeterData;
import com.example.smartmeter.model.RateConfig;
import com.influxdb.client.InfluxDBClientFactory;
import com.influxdb.client.WriteApiBlocking;
import com.influxdb.client.domain.WritePrecision;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
/**
* 用于處理電表數(shù)據(jù)采集和服務的服務類
*/
@Service
public class ElectricMeterService {
@Value("${influx.url}")
private String influxUrl; // InfluxDB URL
@Value("${influx.token}")
private String token; // InfluxDB Token
@Value("${influx.org}")
private String org; // InfluxDB Organization
@Value("${influx.bucket}")
private String bucket; // InfluxDB Bucket
@Autowired
private RateConfigService rateConfigService; // 注入費率配置服務
/**
* 將電表數(shù)據(jù)保存到InfluxDB
*
* @param data 電表數(shù)據(jù)對象
*/
public void saveData(ElectricMeterData data) {
try (var client = InfluxDBClientFactory.create(influxUrl, token.toCharArray())) { // 創(chuàng)建InfluxDB客戶端
WriteApiBlocking writeApi = client.getWriteApiBlocking(); // 獲取寫API
var point = com.influxdb.client.write.Point.measurement("electric_meter") // 創(chuàng)建數(shù)據(jù)點
.addTag("meter_id", data.getMeterId()) // 添加標簽
.addField("energy_consumption", data.getEnergyConsumption()) // 添加字段
.time(data.getTimestamp(), WritePrecision.S); // 設置時間戳
writeApi.writePoint(bucket, org, point); // 寫入數(shù)據(jù)
}
}
/**
* 根據(jù)時間和能耗計算動態(tài)費率
*
* @param energyConsumption 能耗(單位:千瓦時)
* @param date 日期
* @param hourOfDay 小時數(shù)(0-23)
* @return 計算出的費用
*/
public double calculateDynamicRate(double energyConsumption, LocalDate date, int hourOfDay) {
RateConfig rateConfig = rateConfigService.getRateConfig(); // 獲取費率配置
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 日期格式化器
String dateString = date.format(formatter); // 格式化日期字符串
if (rateConfig.getHolidayRates().containsKey(dateString)) {
// 如果是節(jié)假日,使用節(jié)假日費率
return energyConsumption * rateConfig.getHolidayRates().get(dateString);
} elseif (rateConfig.getPeakRates().containsKey(String.format("%02d", hourOfDay))) {
// 如果是峰時段,使用峰時段費率
return energyConsumption * rateConfig.getPeakRates().get(String.format("%02d", hourOfDay));
} elseif (rateConfig.getOffPeakRates().containsKey(String.format("%02d", hourOfDay))) {
// 如果是谷時段,使用谷時段費率
return energyConsumption * rateConfig.getOffPeakRates().get(String.format("%02d", hourOfDay));
} else {
throw new IllegalArgumentException("No rate configuration found for the given time."); // 拋出異常
}
}
}
Controller
package com.example.smartmeter.controller;
import com.example.smartmeter.model.ElectricMeterData;
import com.example.smartmeter.service.ElectricMeterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
@RestController
@RequestMapping("/api/meters")
public class ElectricMeterController {
@Autowired
private ElectricMeterService electricMeterService; // 注入電表服務
/**
* 接收POST請求保存電表數(shù)據(jù)并計算費用
*
* @param data 電表數(shù)據(jù)對象
* @return 成功消息及計算出的費用
*/
@PostMapping("/data")
public String saveMeterData(@RequestBody ElectricMeterData data) {
electricMeterService.saveData(data); // 保存數(shù)據(jù)到InfluxDB
LocalDate date = Instant.ofEpochSecond(data.getTimestamp().getEpochSecond()).atZone(ZoneId.systemDefault()).toLocalDate(); // 獲取日期
int hourOfDay = data.getTimestamp().get(ChronoField.HOUR_OF_DAY); // 獲取小時數(shù)
double rate = electricMeterService.calculateDynamicRate(data.getEnergyConsumption(), date, hourOfDay); // 計算費用
return"Data saved successfully! Calculated rate: $" + rate; // 返回成功消息及費用
}
}
Application
package com.example.smartmeter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SmartMeterApplication {
public static void main(String[] args) {
SpringApplication.run(SmartMeterApplication.class, args);
}
}
測試
curl -X POST http://localhost:8080/api/meters/data \
-H "Content-Type: application/json" \
-d '{
"meterId": "METER123",
"energyConsumption": 5.5,
"timestamp": 1696074000
}'
Respons
Data saved successfully! Calculated rate: $0.825
責任編輯:武曉燕
來源:
Java知識日歷