Compare commits
14 Commits
jingquan
...
dyf-device
| Author | SHA1 | Date | |
|---|---|---|---|
| 04cb699081 | |||
| 0f0dd4c6b1 | |||
| 2db37a75d2 | |||
| 696bbb4aa4 | |||
| ee445dc0d2 | |||
| 897561ba89 | |||
| 2e575f78b1 | |||
| 6fd7f8ca94 | |||
| 9936a5ad13 | |||
| c267fe0c14 | |||
| e80830e76c | |||
| 437ab110b7 | |||
| 88650c3d9f | |||
| ec28ab1092 |
@ -133,6 +133,25 @@
|
||||
<version>1.5.7</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Java音频转换库 -->
|
||||
<dependency>
|
||||
<groupId>ws.schild</groupId>
|
||||
<artifactId>jave-core</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>
|
||||
<groupId>ws.schild</groupId>
|
||||
<artifactId>jave-nativebin-all</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>ws.schild</groupId>
|
||||
<artifactId>jave-all-deps</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- skywalking 整合 logback -->
|
||||
<!-- <dependency>-->
|
||||
|
||||
81
fys-admin/src/main/java/com/fuyuanshen/SimpleQR.java
Normal file
81
fys-admin/src/main/java/com/fuyuanshen/SimpleQR.java
Normal file
@ -0,0 +1,81 @@
|
||||
package com.fuyuanshen;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
|
||||
public class SimpleQR {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String text = "HELLO";
|
||||
int size = 21; // 版本1的大小
|
||||
boolean[][] qr = new boolean[size][size];
|
||||
|
||||
// 1. 三个定位标记
|
||||
for (int i = 0; i < 7; i++)
|
||||
for (int j = 0; j < 7; j++) {
|
||||
boolean black = i == 0 || i == 6 || j == 0 || j == 6 || (i > 1 && i < 5 && j > 1 && j < 5);
|
||||
qr[i][j] = qr[i][size - 1 - j] = qr[size - 1 - i][j] = black;
|
||||
}
|
||||
|
||||
// 2. 定时图案(简化)
|
||||
for (int i = 8; i < 13; i++) qr[i][6] = qr[6][i] = (i % 2 == 0);
|
||||
|
||||
// 3. 编码数据(极简编码)
|
||||
byte[] data = text.getBytes();
|
||||
int x = 20, y = 20, up = 1; // 从右下角开始
|
||||
for (byte b : data)
|
||||
for (int bit = 7; bit >= 0; bit--) {
|
||||
while (qr[x][y] || (x == 6 && y < 9) || (y == 6 && x < 9) || (x < 9 && y < 9) ||
|
||||
(x < 9 && y > size - 10) || (y < 9 && x > size - 10)) {
|
||||
if (up > 0) {
|
||||
if (--y < 0) {
|
||||
y = 0;
|
||||
x -= 2;
|
||||
up = -1;
|
||||
}
|
||||
} else {
|
||||
if (++y >= size) {
|
||||
y = size - 1;
|
||||
x -= 2;
|
||||
up = 1;
|
||||
}
|
||||
}
|
||||
if (x == 6) x--;
|
||||
}
|
||||
qr[x][y] = ((b >> bit) & 1) == 1;
|
||||
if (up > 0) {
|
||||
if (--y < 0) {
|
||||
y = 0;
|
||||
x -= 2;
|
||||
up = -1;
|
||||
}
|
||||
} else {
|
||||
if (++y >= size) {
|
||||
y = size - 1;
|
||||
x -= 2;
|
||||
up = 1;
|
||||
}
|
||||
}
|
||||
if (x == 6) x--;
|
||||
}
|
||||
|
||||
// 4. 保存图像
|
||||
int scale = 10, margin = 4;
|
||||
BufferedImage img = new BufferedImage(
|
||||
size * scale + margin * 2, size * scale + margin * 2, BufferedImage.TYPE_INT_RGB);
|
||||
for (int i = 0; i < img.getWidth(); i++)
|
||||
for (int j = 0; j < img.getHeight(); j++)
|
||||
img.setRGB(i, j, 0xFFFFFF); // 白色背景
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
for (int j = 0; j < size; j++)
|
||||
if (qr[i][j])
|
||||
for (int di = 0; di < scale; di++)
|
||||
for (int dj = 0; dj < scale; dj++)
|
||||
img.setRGB(margin + i * scale + di, margin + j * scale + dj, 0x000000);
|
||||
|
||||
ImageIO.write(img, "PNG", new File("qr.png"));
|
||||
System.out.println("二维码已生成");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
package com.fuyuanshen.app.controller;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.service.AppFileService;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package com.fuyuanshen.app.controller;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
package com.fuyuanshen.app.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppAudioFileDto;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileRenameDto;
|
||||
import com.fuyuanshen.app.domain.dto.TextToSpeechRequest;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.service.AudioProcessService;
|
||||
import com.fuyuanshen.app.service.VideoProcessService;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
@ -8,6 +14,7 @@ import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@ -56,6 +63,7 @@ public class AppVideoController extends BaseController {
|
||||
return R.ok(audioProcessService.generateStandardPcmData(text));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提取文本内容(只支持txt/docx)
|
||||
*/
|
||||
@ -65,4 +73,68 @@ public class AppVideoController extends BaseController {
|
||||
return R.ok("Success",audioProcessService.extract(file));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 上传音频文件进行处理
|
||||
* 支持MP3、WAV、PCM格式
|
||||
*/
|
||||
@PostMapping("/uploadAudioToOss")
|
||||
public R<String> uploadAudioToOss(@ModelAttribute AppAudioFileDto bo) {
|
||||
try {
|
||||
String result = audioProcessService.uploadAudioToOss(bo);
|
||||
return R.ok(result);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return R.fail("文件格式错误: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
|
||||
return R.fail("上传处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本转语音
|
||||
* 支持MP3、WAV、PCM格式
|
||||
*/
|
||||
@PostMapping("/ttsToOss")
|
||||
public R<String> textToSpeech(@RequestBody TextToSpeechRequest request) {
|
||||
try {
|
||||
if (request.getDeviceId() == null) {
|
||||
return R.fail("设备ID不能为空");
|
||||
}
|
||||
|
||||
String result = audioProcessService.textToSpeech(
|
||||
request.getDeviceId(),
|
||||
request.getText(),
|
||||
request.getFileSuffix()
|
||||
);
|
||||
return R.ok(result);
|
||||
} catch (Exception e) {
|
||||
return R.fail("文本转语音失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询语音文件列表
|
||||
*/
|
||||
@GetMapping("/queryAudioFileList")
|
||||
public R<List<AppFileVo>> queryAudioFileList(Long deviceId) {
|
||||
return R.ok(audioProcessService.queryAudioFileList(deviceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除语音文件
|
||||
*/
|
||||
@GetMapping("/deleteAudioFile")
|
||||
public R<Void> deleteAudioFile(Long fileId,Long deviceId) {
|
||||
return audioProcessService.deleteAudioFile(fileId,deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件重命名
|
||||
*/
|
||||
@PostMapping("/renameAudioFile")
|
||||
public R<Void> renameAudioFile(@RequestBody AppFileRenameDto bo) {
|
||||
return audioProcessService.renameAudioFile(bo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,191 @@
|
||||
package com.fuyuanshen.app.controller.device.bjq;
|
||||
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceHBY100JDetailVo;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.web.service.device.DeviceHBY100JBizService;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* HBY100J设备控制类
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/hby100j/device")
|
||||
public class AppDeviceHBY100JController extends BaseController {
|
||||
|
||||
private final DeviceHBY100JBizService deviceHBY100JBizService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取设备详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public R<AppDeviceHBY100JDetailVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(deviceHBY100JBizService.getInfo(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新语音
|
||||
*/
|
||||
@PostMapping("/updateVoice")
|
||||
public R<Void> updateVoice(@RequestBody HBY100JUpdateVoiceDto dto) {
|
||||
deviceHBY100JBizService.updateVoice(dto);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制报警
|
||||
*
|
||||
*/
|
||||
|
||||
@PostMapping("/forceAlarmActivation")
|
||||
public R<Void> forceAlarmActivation(@RequestBody HBY100JForceAlarmActivationDto bo) {
|
||||
deviceHBY100JBizService.forceAlarmActivation(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 爆闪模式
|
||||
*/
|
||||
@PostMapping("/strobeMode")
|
||||
public R<Void> strobeMode(@RequestBody HBY100JStrobeModeDto params) {
|
||||
deviceHBY100JBizService.strobeMode(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 灯光调节
|
||||
*/
|
||||
@PostMapping("/lightAdjustment")
|
||||
public R<Void> lightAdjustment(@RequestBody HBY100JLightAdjustmentDto params) {
|
||||
deviceHBY100JBizService.lightAdjustment(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 爆闪频率
|
||||
*/
|
||||
@PostMapping("/strobeFrequency")
|
||||
public R<Void> strobeFrequency(@RequestBody HBY100JStrobeFrequencyDto params) {
|
||||
deviceHBY100JBizService.strobeFrequency(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改音量
|
||||
*/
|
||||
@PostMapping("/updateVolume")
|
||||
public R<Void> updateVolume(@RequestBody HBY100JUpdateVolumeDto params) {
|
||||
deviceHBY100JBizService.updateVolume(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HBY100JUpdateVoiceDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HBY100JForceAlarmActivationDto {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
List<Long> deviceIds;
|
||||
/**
|
||||
* 0 关闭, 1开启
|
||||
*/
|
||||
private Integer voiceStrobeAlarm;
|
||||
/**
|
||||
* 0 公安,1消防,2应急,3交警,4 市政,5 铁路,6 医疗,7部队,8 水利,9 语音
|
||||
*/
|
||||
private Integer mode;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HBY100JUpdateVolumeDto{
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* "volume": 1-100(app端可根据需求把40作为低音量, 70作为中音量,100作为高音量)
|
||||
*/
|
||||
private Integer volume;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HBY100JStrobeFrequencyDto{
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* "frequency": 1-12
|
||||
*/
|
||||
private Integer frequency;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HBY100JLightAdjustmentDto{
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 亮度值0-100
|
||||
*/
|
||||
private Integer brightness;
|
||||
// /**
|
||||
// * 红色LED亮度值0-100
|
||||
// */
|
||||
// private Integer red;
|
||||
//
|
||||
// /**
|
||||
// * 蓝色LED亮度值0-100
|
||||
// */
|
||||
// private Integer blue;
|
||||
//
|
||||
// /**
|
||||
// * 黄色LED亮度值0-100
|
||||
// */
|
||||
// private Integer yellow;
|
||||
|
||||
}
|
||||
@Data
|
||||
public static class HBY100JStrobeModeDto{
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* 0 关闭 1 开启
|
||||
*/
|
||||
private Integer enable;
|
||||
|
||||
/**
|
||||
* 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||
*/
|
||||
private Integer mode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.fuyuanshen.app.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Data
|
||||
public class AppAudioFileDto {
|
||||
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 文件
|
||||
*/
|
||||
private MultipartFile file;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.fuyuanshen.app.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Data
|
||||
public class AppFileRenameDto {
|
||||
|
||||
/**
|
||||
* 文件id
|
||||
*/
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 设备id
|
||||
*/
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.fuyuanshen.app.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* PCM生成请求实体
|
||||
*/
|
||||
@Data
|
||||
public class PcmGenerationRequest {
|
||||
private String text;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.fuyuanshen.app.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文本转语音请求实体
|
||||
*/
|
||||
@Data
|
||||
public class TextToSpeechRequest {
|
||||
|
||||
private Long deviceId;
|
||||
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* 文件后缀格式
|
||||
*/
|
||||
private String fileSuffix;
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
package com.fuyuanshen.app.http;
|
||||
|
||||
import com.alibaba.nls.client.AccessToken;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import static cn.dev33.satoken.SaManager.log;
|
||||
|
||||
public class HttpTtsClient {
|
||||
|
||||
private String accessKeyId;
|
||||
private String accessKeySecret;
|
||||
private String appKey;
|
||||
/**
|
||||
* 阿里云TTS服务基础URL
|
||||
*/
|
||||
private static final String BASE_URL = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
|
||||
|
||||
public HttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) {
|
||||
this.accessKeyId = accessKeyId;
|
||||
this.accessKeySecret = accessKeySecret;
|
||||
this.appKey = appKey;
|
||||
}
|
||||
private String refreshAccessToken() {
|
||||
try {
|
||||
// 调用阿里云API获取访问令牌
|
||||
AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
|
||||
accessToken.apply();
|
||||
String token = accessToken.getToken();
|
||||
log.info("访问令牌刷新成功");
|
||||
|
||||
return token;
|
||||
} catch (Exception e) {
|
||||
log.error("刷新访问令牌失败: {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 使用HTTP POST方式调用阿里云TTS服务生成MP3格式语音
|
||||
*/
|
||||
public byte[] synthesizeTextToMp3(String text) throws IOException {
|
||||
String endpoint = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
|
||||
|
||||
// 构建请求体
|
||||
// String requestBody = String.format(
|
||||
// "{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}",
|
||||
// appKey,
|
||||
// text.replace("\"", "\\\"")
|
||||
// );
|
||||
|
||||
String token = refreshAccessToken();
|
||||
String requestBody = " {\n" +
|
||||
" \"appkey\":\""+appKey+"\",\n" +
|
||||
" \"text\":\""+text+"\",\n" +
|
||||
" \"token\":\""+token+"\",\n" +
|
||||
" \"format\":\"mp3\"\n" +
|
||||
" }";
|
||||
|
||||
URL url = new URL(endpoint);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 设置请求方法和头部
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Authorization", buildAuthorization());
|
||||
conn.setRequestProperty("Content-Length", String.valueOf(requestBody.getBytes().length));
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// 发送请求体
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(requestBody.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
// 读取音频数据
|
||||
try (InputStream is = conn.getInputStream()) {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int nRead;
|
||||
byte[] data = new byte[1024];
|
||||
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
} else {
|
||||
throw new IOException("HTTP请求失败,状态码: " + responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建授权头部
|
||||
*/
|
||||
private String buildAuthorization() {
|
||||
// 实际实现需要根据阿里云API规范构建签名
|
||||
// 这里是简化示例
|
||||
return "Bearer " + generateAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成访问令牌
|
||||
*/
|
||||
private String generateAccessToken() {
|
||||
// 实际实现需要调用阿里云获取token的API
|
||||
return "your-access-token";
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存MP3到文件
|
||||
*/
|
||||
public String saveMp3ToFile(String text, String outputPath) throws IOException {
|
||||
byte[] mp3Data = synthesizeTextToMp3(text);
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
|
||||
fos.write(mp3Data);
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.fuyuanshen.app.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HttpTtsExample {
|
||||
|
||||
/**
|
||||
* appKey: lbGuq5K5bEH4uxmT
|
||||
* akId: LTAI5t66moCkhNC32TDJ5ReP
|
||||
* akSecret: 2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP";
|
||||
String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH";
|
||||
String appKey = "lbGuq5K5bEH4uxmT";
|
||||
|
||||
try {
|
||||
// 使用HTTP方式调用
|
||||
HttpTtsClient httpClient = new HttpTtsClient(accessKeyId, accessKeySecret, appKey);
|
||||
|
||||
String text = "大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。";
|
||||
String outputPath = "D:\\http_output9.mp3";
|
||||
|
||||
String resultFile = httpClient.saveMp3ToFile(text, outputPath);
|
||||
System.out.println("MP3音频已保存至: " + resultFile);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.fuyuanshen.app.http;
|
||||
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class OkHttpTtsClient {
|
||||
|
||||
private OkHttpClient client = new OkHttpClient();
|
||||
private String accessKeyId;
|
||||
private String accessKeySecret;
|
||||
private String appKey;
|
||||
|
||||
public OkHttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) {
|
||||
this.accessKeyId = accessKeyId;
|
||||
this.accessKeySecret = accessKeySecret;
|
||||
this.appKey = appKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用OkHttp调用TTS服务
|
||||
*/
|
||||
public byte[] synthesizeTextToMp3(String text) throws IOException {
|
||||
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||
|
||||
String jsonPayload = String.format(
|
||||
"{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}",
|
||||
appKey,
|
||||
text.replace("\"", "\\\"")
|
||||
);
|
||||
|
||||
RequestBody body = RequestBody.create(JSON,jsonPayload);
|
||||
Request request = new Request.Builder()
|
||||
.url("https://nls-gateway.cn-shanghai.aliyuncs.com/v1/tts")
|
||||
.post(body)
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.addHeader("Authorization", "Bearer " + getAccessToken())
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new IOException("HTTP请求失败: " + response.code());
|
||||
}
|
||||
|
||||
ResponseBody responseBody = response.body();
|
||||
if (responseBody != null) {
|
||||
return responseBody.bytes();
|
||||
} else {
|
||||
throw new IOException("响应体为空");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getAccessToken() {
|
||||
// 实现获取访问令牌的逻辑
|
||||
return "your-access-token";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.fuyuanshen.app.http;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* 获取阿里云TTS服务访问令牌
|
||||
*/
|
||||
public class TokenClient {
|
||||
|
||||
public static String getAccessToken(String accessKeyId, String accessKeySecret) throws IOException {
|
||||
String endpoint = "https://nls-meta.cn-shanghai.aliyuncs.com/v1/token";
|
||||
|
||||
URL url = new URL(endpoint);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// 发送认证信息
|
||||
String params = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s",
|
||||
accessKeyId, accessKeySecret);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(params.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
try (InputStream is = conn.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
|
||||
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
|
||||
// 解析响应获取token(实际需要使用JSON解析库)
|
||||
return response.toString().replaceAll(".*\"access_token\":\"([^\"]+)\".*", "$1");
|
||||
}
|
||||
} else {
|
||||
throw new IOException("获取令牌失败,状态码: " + responseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,13 @@
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.oss.core.OssClient;
|
||||
import com.fuyuanshen.common.oss.factory.OssFactory;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.service.ISysOssService;
|
||||
@ -97,5 +96,4 @@ public class AppFileService {
|
||||
}
|
||||
return appBusinessFileService.deleteWithValidByIds(List.of(ids), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,21 @@
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppAudioFileDto;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileRenameDto;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.http.HttpTtsClient;
|
||||
import com.fuyuanshen.app.mapper.AppBusinessFileMapper;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.equipment.utils.AlibabaTTSUtil;
|
||||
import com.fuyuanshen.equipment.utils.AudioProcessUtil;
|
||||
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
||||
import com.fuyuanshen.equipment.utils.Mp3Duration;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.service.ISysOssService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -17,8 +31,12 @@ import javax.xml.stream.XMLStreamReader;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
@ -39,6 +57,11 @@ public class AudioProcessService {
|
||||
private final AudioProcessUtil audioProcessUtil;
|
||||
private final AlibabaTTSUtil alibabaTTSUtil;
|
||||
|
||||
private final FileHashUtil fileHashUtil;
|
||||
private final ISysOssService ossService;
|
||||
private final IAppBusinessFileService appBusinessFileService;
|
||||
private final AppBusinessFileMapper appBusinessFileMapper;
|
||||
|
||||
/**
|
||||
* 处理上传的音频文件
|
||||
*/
|
||||
@ -175,6 +198,28 @@ public class AudioProcessService {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
private String saveByteArrayToFile(InputStream inputStream, String filename) throws IOException {
|
||||
// 确定保存路径(可以是临时目录或指定目录)
|
||||
String directory = System.getProperty("java.io.tmpdir"); // 使用系统临时目录
|
||||
File dir = new File(directory);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// 创建完整文件路径
|
||||
File file = new File(dir, filename);
|
||||
|
||||
// 从输入流读取数据并写入文件
|
||||
try (FileOutputStream fos = new FileOutputStream(file);
|
||||
InputStream is = inputStream) {
|
||||
byte[] buffer = new byte[8192]; // 8KB缓冲区
|
||||
int bytesRead;
|
||||
while ((bytesRead = is.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -305,4 +350,191 @@ public class AudioProcessService {
|
||||
}
|
||||
|
||||
|
||||
public String uploadAudioToOss(AppAudioFileDto bo) {
|
||||
MultipartFile file = bo.getFile();
|
||||
// 校验文件格式和大小
|
||||
validateAudioFileForRestful(file);
|
||||
// 上传文件
|
||||
// SysOssVo upload = sysOssService.upload(file);
|
||||
String filename = file.getOriginalFilename();
|
||||
String savedPath = null;
|
||||
try {
|
||||
String fileHash = fileHashUtil.hash(file);
|
||||
SysOssVo upload = ossService.updateHash(file, fileHash);
|
||||
// 强制将HTTP替换为HTTPS
|
||||
if (upload.getUrl() != null && upload.getUrl().startsWith("http://")) {
|
||||
upload.setUrl(upload.getUrl().replaceFirst("^http://", "https://"));
|
||||
}
|
||||
String fileSuffix = filename.substring(filename.lastIndexOf('.')).toLowerCase();
|
||||
AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo();
|
||||
appBusinessFileBo.setFileId(upload.getOssId());
|
||||
appBusinessFileBo.setBusinessId(bo.getDeviceId());
|
||||
appBusinessFileBo.setFileType(3L);
|
||||
appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId());
|
||||
savedPath = saveByteArrayToFile(file.getInputStream(), generateRandomFileName(fileSuffix));
|
||||
if (savedPath != null) {
|
||||
log.info("MP3文件已保存: {}", savedPath);
|
||||
Integer mp3Duration = Mp3Duration.getMp3Duration(savedPath);
|
||||
log.info("MP3文件时长: {} 秒", mp3Duration);
|
||||
appBusinessFileBo.setDuration(mp3Duration);
|
||||
}
|
||||
appBusinessFileService.insertByBo(appBusinessFileBo);
|
||||
if (upload != null) {
|
||||
return upload.getUrl();
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("上传音频文件失败", e);
|
||||
}finally {
|
||||
log.info("删除临时文件: {}", savedPath);
|
||||
if(savedPath != null){
|
||||
deleteTempFile(new File(savedPath));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验音频文件格式
|
||||
*/
|
||||
private void validateAudioFileForRestful(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new IllegalArgumentException("上传文件不能为空");
|
||||
}
|
||||
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename == null) {
|
||||
throw new IllegalArgumentException("文件名不能为空");
|
||||
}
|
||||
List<String> SUPPORTED_FORMATS = Arrays.asList(
|
||||
".wav", ".mp3", ".pcm"
|
||||
);
|
||||
|
||||
String ext = originalFilename.substring(originalFilename.lastIndexOf('.')).toLowerCase();
|
||||
// 检查文件扩展名
|
||||
if (!SUPPORTED_FORMATS.contains(ext)) {
|
||||
throw new IllegalArgumentException("只允许上传MP3、WAV、PCM格式的音频文件");
|
||||
}
|
||||
|
||||
// 检查文件大小
|
||||
if (file.getSize() > MAX_AUDIO_SIZE) {
|
||||
throw new IllegalArgumentException("音频大小不能超过5MB");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否为支持的音频格式
|
||||
*/
|
||||
private boolean isSupportedFormat(String filename) {
|
||||
if (filename == null || filename.lastIndexOf('.') == -1) {
|
||||
return false;
|
||||
}
|
||||
String ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
|
||||
return SUPPORTED_FORMATS.contains(ext);
|
||||
}
|
||||
|
||||
public String textToSpeech(Long deviceId,String text, String fileSuffix) {
|
||||
//支持PCM/WAV/MP3格式
|
||||
if (fileSuffix == null || fileSuffix.isEmpty()) {
|
||||
fileSuffix = "mp3";
|
||||
}
|
||||
fileSuffix = fileSuffix.toLowerCase();
|
||||
List<String> SUPPORTED_FORMATS = Arrays.asList(
|
||||
"wav", "mp3", "pcm"
|
||||
);
|
||||
boolean contains = SUPPORTED_FORMATS.contains(fileSuffix);
|
||||
if (!contains) {
|
||||
throw new IllegalArgumentException("不支持的音频格式");
|
||||
}
|
||||
String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP";
|
||||
String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH";
|
||||
String appKey = "lbGuq5K5bEH4uxmT";
|
||||
String savedPath = null;
|
||||
try {
|
||||
// 使用HTTP方式调用
|
||||
HttpTtsClient httpClient = new HttpTtsClient(accessKeyId, accessKeySecret, appKey);
|
||||
//
|
||||
byte[] mp3Data = httpClient.synthesizeTextToMp3(text);
|
||||
// byte[] mp3Data = alibabaTTSUtil.synthesizeTextToMp3(text);
|
||||
|
||||
SysOssVo upload = ossService.upload(mp3Data, generateRandomFileName(fileSuffix));
|
||||
|
||||
// 强制将HTTP替换为HTTPS
|
||||
if (upload.getUrl() != null && upload.getUrl().startsWith("http://")) {
|
||||
upload.setUrl(upload.getUrl().replaceFirst("^http://", "https://"));
|
||||
}
|
||||
|
||||
|
||||
AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo();
|
||||
appBusinessFileBo.setFileId(upload.getOssId());
|
||||
appBusinessFileBo.setBusinessId(deviceId);
|
||||
appBusinessFileBo.setFileType(3L);
|
||||
appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId());
|
||||
savedPath = saveByteArrayToFile(mp3Data, generateRandomFileName(fileSuffix));
|
||||
if (savedPath != null) {
|
||||
log.info("MP3文件已保存: {}", savedPath);
|
||||
Integer mp3Duration = Mp3Duration.getMp3Duration(savedPath);
|
||||
log.info("MP3文件时长: {} 秒", mp3Duration);
|
||||
appBusinessFileBo.setDuration(mp3Duration);
|
||||
}
|
||||
appBusinessFileService.insertByBo(appBusinessFileBo);
|
||||
if (upload != null) {
|
||||
return upload.getUrl();
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("上传音频文件失败", e);
|
||||
} finally {
|
||||
log.info("删除临时文件: {}", savedPath);
|
||||
if(savedPath != null){
|
||||
deleteTempFile(new File(savedPath));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final Random random = new Random();
|
||||
private static final DateTimeFormatter formatter =
|
||||
DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||
/**
|
||||
* 生成纯随机文件名(无原文件名依赖)
|
||||
*/
|
||||
public static String generateRandomFileName(String extension) {
|
||||
String timestamp = LocalDateTime.now().format(formatter);
|
||||
int randomNum = random.nextInt(10000);
|
||||
String uuidPart = UUID.randomUUID().toString().substring(0, 8);
|
||||
|
||||
if (!extension.startsWith(".")) {
|
||||
extension = "." + extension;
|
||||
}
|
||||
|
||||
return timestamp + "_" + String.format("%04d", randomNum) + "_" + uuidPart + extension;
|
||||
}
|
||||
|
||||
public List<AppFileVo> queryAudioFileList(Long deviceId) {
|
||||
if(deviceId == null){
|
||||
return null;
|
||||
}
|
||||
AppBusinessFileBo bo = new AppBusinessFileBo();
|
||||
bo.setBusinessId(deviceId);
|
||||
bo.setFileType(3L);
|
||||
List<AppFileVo> appFileVos = appBusinessFileService.queryAppFileList(bo);
|
||||
return appFileVos;
|
||||
}
|
||||
|
||||
public R<Void> deleteAudioFile(Long fileId,Long deviceId) {
|
||||
UpdateWrapper<AppBusinessFile> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("file_id",fileId);
|
||||
updateWrapper.eq("business_id",deviceId);
|
||||
appBusinessFileMapper.delete(updateWrapper);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
public R<Void> renameAudioFile(AppFileRenameDto bo) {
|
||||
UpdateWrapper<AppBusinessFile> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("file_id",bo.getFileId());
|
||||
updateWrapper.eq("business_id",bo.getDeviceId());
|
||||
updateWrapper.set("re_name",bo.getFileName());
|
||||
appBusinessFileMapper.update(updateWrapper);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,5 @@
|
||||
package com.fuyuanshen.global.mqtt.base;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Comparator;
|
||||
@ -16,9 +12,9 @@ import java.util.List;
|
||||
@Component
|
||||
public class MqttRuleEngine {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("threadPoolTaskExecutor")
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
// @Autowired
|
||||
// @Qualifier("threadPoolTaskExecutor")
|
||||
// private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
|
||||
private final LinkedHashMap<String, MqttMessageRule> rulesMap = new LinkedHashMap<>();
|
||||
|
||||
@ -41,7 +37,8 @@ public class MqttRuleEngine {
|
||||
int commandType = context.getCommandType();
|
||||
MqttMessageRule mqttMessageRule = rulesMap.get("Light_" + commandType);
|
||||
if (mqttMessageRule != null) {
|
||||
threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context));
|
||||
// threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context));
|
||||
mqttMessageRule.execute(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package com.fuyuanshen.global.mqtt.base;
|
||||
|
||||
/**
|
||||
* MQTT消息处理接口
|
||||
*/
|
||||
public interface NewMqttMessageRule {
|
||||
|
||||
/**
|
||||
* 获取命令类型
|
||||
* @return 命令类型
|
||||
*/
|
||||
String getCommandType();
|
||||
/**
|
||||
* 执行处理
|
||||
* @param context 处理上下文
|
||||
*/
|
||||
void execute(NewMqttRuleContext context);
|
||||
|
||||
/**
|
||||
* 获取优先级,数值越小优先级越高
|
||||
* @return 优先级
|
||||
*/
|
||||
default int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.fuyuanshen.global.mqtt.base;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MQTT消息处理上下文
|
||||
*/
|
||||
@Data
|
||||
public class NewMqttRuleContext {
|
||||
/**
|
||||
* 命令类型
|
||||
*/
|
||||
private String commandType;
|
||||
/**
|
||||
* 设备IMEI
|
||||
*/
|
||||
private String deviceImei;
|
||||
|
||||
/**
|
||||
* MQTT消息负载字典
|
||||
*/
|
||||
private Map<String, Object> payloadDict;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.fuyuanshen.global.mqtt.base;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MQTT消息引擎
|
||||
*/
|
||||
@Component
|
||||
public class NewMqttRuleEngine {
|
||||
|
||||
// @Autowired
|
||||
// @Qualifier("threadPoolTaskExecutor")
|
||||
// private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
|
||||
private final LinkedHashMap<String, NewMqttMessageRule> rulesMap = new LinkedHashMap<>();
|
||||
public NewMqttRuleEngine(List<NewMqttMessageRule> rules) {
|
||||
// 按优先级排序
|
||||
rules.sort(Comparator.comparing(NewMqttMessageRule::getPriority));
|
||||
rules.forEach(rule -> rulesMap.put(rule.getCommandType(), rule)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行匹配
|
||||
* @param context 处理上下文
|
||||
* @return
|
||||
*/
|
||||
public boolean executeRule(NewMqttRuleContext context) {
|
||||
String commandType = context.getCommandType();
|
||||
// String funcType = context.getFuncType();
|
||||
NewMqttMessageRule mqttMessageRule = rulesMap.get(commandType);
|
||||
if (mqttMessageRule != null) {
|
||||
// threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context));
|
||||
mqttMessageRule.execute(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -44,12 +44,12 @@ public class MqttInboundConfiguration {
|
||||
if (url == null) {
|
||||
throw new IllegalStateException("MQTT服务器URL未配置");
|
||||
}
|
||||
|
||||
String subTopic = mqttPropertiesConfig.getSubTopic();
|
||||
MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
|
||||
url,
|
||||
clientId,
|
||||
mqttPahoClientFactory,
|
||||
mqttPropertiesConfig.getSubTopic().split(",")
|
||||
subTopic.split(",")
|
||||
);
|
||||
mqttPahoMessageDrivenChannelAdapter.setQos(1);
|
||||
mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
|
||||
|
||||
@ -47,7 +47,7 @@ public class MqttOutboundConfiguration {
|
||||
mqttPahoClientFactory
|
||||
);
|
||||
mqttPahoMessageHandler.setDefaultQos(1);
|
||||
mqttPahoMessageHandler.setDefaultTopic("B/#");
|
||||
mqttPahoMessageHandler.setDefaultTopic(mqttPropertiesConfig.getPubTopic());
|
||||
mqttPahoMessageHandler.setAsync(true);
|
||||
return mqttPahoMessageHandler;
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ public class MqttPropertiesConfig {
|
||||
private String url;
|
||||
private String subClientId;
|
||||
private String subTopic;
|
||||
private String subTopic2;
|
||||
private String pubClientId;
|
||||
private String pubTopic;
|
||||
private String pubTopic2;
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package com.fuyuanshen.global.mqtt.config;
|
||||
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import com.fuyuanshen.global.mqtt.receiver.NewReceiverMessageHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
|
||||
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class NewMqttInboundConfiguration {
|
||||
@Autowired
|
||||
private MqttPropertiesConfig mqttPropertiesConfig;
|
||||
@Autowired
|
||||
private MqttPahoClientFactory mqttPahoClientFactory;
|
||||
@Autowired
|
||||
private NewReceiverMessageHandler receiverMessageHandler2;
|
||||
//消息通道
|
||||
@Bean
|
||||
public MessageChannel messageInboundChannel2(){
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置入站适配器
|
||||
* 作用: 设置订阅主题,以及指定消息的通道 等相关属性
|
||||
* */
|
||||
@Bean
|
||||
public MessageProducer messageProducer2(){
|
||||
// 生成一个不重复的随机数
|
||||
String clientId = mqttPropertiesConfig.getSubClientId() + "_" + UUID.fastUUID();
|
||||
String subTopic = mqttPropertiesConfig.getSubTopic2();
|
||||
log.info("订阅主题:{}", subTopic);
|
||||
MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
|
||||
mqttPropertiesConfig.getUrl(),
|
||||
clientId,
|
||||
mqttPahoClientFactory,
|
||||
subTopic.split(",")
|
||||
);
|
||||
mqttPahoMessageDrivenChannelAdapter.setQos(1);
|
||||
mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
|
||||
mqttPahoMessageDrivenChannelAdapter.setOutputChannel(messageInboundChannel2());
|
||||
return mqttPahoMessageDrivenChannelAdapter;
|
||||
}
|
||||
/** 指定处理消息来自哪个通道 */
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "messageInboundChannel2")
|
||||
public MessageHandler messageHandler2(){
|
||||
return receiverMessageHandler2;
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// @ServiceActivator(inputChannel = "messageInboundChannel") // 确保通道名称正确
|
||||
// public MessageHandler deviceAlarmMessageHandler() {
|
||||
// return new DeviceAlrmMessageHandler();
|
||||
// }
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.fuyuanshen.global.mqtt.config;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class NewMqttOutboundConfiguration {
|
||||
@Autowired
|
||||
private MqttPropertiesConfig mqttPropertiesConfig;
|
||||
@Autowired
|
||||
private MqttPahoClientFactory mqttPahoClientFactory;
|
||||
|
||||
// 消息通道
|
||||
@Bean
|
||||
public MessageChannel mqttOutboundChannel2(){
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
|
||||
/** 配置出站消息处理器 */
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "mqttOutboundChannel2") // 指定处理器针对哪个通道的消息进行处理
|
||||
public MessageHandler mqttOutboundMessageHandler2(){
|
||||
String clientId = mqttPropertiesConfig.getPubClientId() + "_" + UUID.fastUUID();
|
||||
MqttPahoMessageHandler mqttPahoMessageHandler = new MqttPahoMessageHandler(
|
||||
mqttPropertiesConfig.getUrl(),
|
||||
clientId,
|
||||
mqttPahoClientFactory
|
||||
);
|
||||
mqttPahoMessageHandler.setDefaultQos(1);
|
||||
mqttPahoMessageHandler.setDefaultTopic(mqttPropertiesConfig.getPubTopic2());
|
||||
mqttPahoMessageHandler.setAsync(true);
|
||||
return mqttPahoMessageHandler;
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,4 +13,5 @@ public interface MqttConstants {
|
||||
*/
|
||||
String GLOBAL_SUB_KEY = "A/";
|
||||
|
||||
String GLOBAL_PUB_KEY2 = "command/";
|
||||
}
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
package com.fuyuanshen.global.mqtt.publish;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/")
|
||||
@RequestMapping("/api")
|
||||
@SaIgnore
|
||||
@Slf4j
|
||||
public class DeviceDataController {
|
||||
|
||||
@Autowired
|
||||
private MqttClientTest mqttClientTest;
|
||||
|
||||
// @PostMapping("/{deviceId}/command")
|
||||
@GetMapping("/command")
|
||||
public ResponseEntity<String> sendCommand() {
|
||||
|
||||
mqttClientTest.sendMsg();
|
||||
|
||||
@ -13,10 +13,10 @@ public class MqttClientTest {
|
||||
private MqttGateway mqttGateway;
|
||||
|
||||
public void sendMsg() {
|
||||
mqttGateway.sendMsgToMqtt("worker/location/1", "hello mqtt spring boot");
|
||||
mqttGateway.sendMsgToMqtt("command/894078/HBY670/864865082081523", "hello mqtt spring boot");
|
||||
log.info("message is send");
|
||||
|
||||
mqttGateway.sendMsgToMqtt("worker/alert/2", "hello mqtt spring boot2");
|
||||
mqttGateway.sendMsgToMqtt("report/894078/HBY670/864865082081523", "hello mqtt spring boot2");
|
||||
log.info("message is send2");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
package com.fuyuanshen.global.mqtt.receiver;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleEngine;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class NewReceiverMessageHandler implements MessageHandler {
|
||||
|
||||
@Autowired
|
||||
private NewMqttRuleEngine newRuleEngine;
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message<?> message) throws MessagingException {
|
||||
|
||||
Object payload = message.getPayload();
|
||||
MessageHeaders headers = message.getHeaders();
|
||||
String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
|
||||
String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString();
|
||||
String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString();
|
||||
|
||||
log.info("MQTT2 payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}",
|
||||
payload, receivedTopic, receivedQos, timestamp);
|
||||
|
||||
Dict payloadDict = JsonUtils.parseMap(payload.toString());
|
||||
if (receivedTopic == null || payloadDict == null) {
|
||||
return;
|
||||
}
|
||||
String imei = payloadDict.getStr("imei");
|
||||
String funcType = payloadDict.getStr("funcType");
|
||||
// 执行业务逻辑
|
||||
if(StringUtils.isNotBlank(imei)){
|
||||
String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||
RedisUtils.offerDeduplicated(queueKey,dedupKey,imei, Duration.ofSeconds(900));
|
||||
//在线状态
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ imei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||
}
|
||||
|
||||
String[] topicArr = receivedTopic.split("/");
|
||||
|
||||
NewMqttRuleContext context = new NewMqttRuleContext();
|
||||
context.setCommandType(topicArr[2]+"_"+funcType);
|
||||
context.setDeviceImei(imei);
|
||||
context.setPayloadDict(payloadDict);
|
||||
|
||||
boolean ruleExecuted = newRuleEngine.executeRule(context);
|
||||
|
||||
if (!ruleExecuted) {
|
||||
log.warn("未找到匹配的规则来处理命令类型: {}", topicArr[2] + " : " +funcType);
|
||||
}
|
||||
// final LockInfo lockInfo = lockTemplate.lock(GlobalConstants.GLOBAL_REDIS_KEY + lockKey + imei, 100L, 3000L, RedissonLockExecutor.class);
|
||||
// if (null == lockInfo) {
|
||||
// log.info("MQTT3业务处理中,请稍后再试:funcType=>{},imei=>{}",funcType,imei);
|
||||
// return;
|
||||
// }
|
||||
//// 获取锁成功,处理业务
|
||||
// try {
|
||||
// if(StringUtils.isNotBlank(imei)){
|
||||
// String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
// String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||
// RedisUtils.offerDeduplicated(queueKey,dedupKey,imei, Duration.ofSeconds(900));
|
||||
// //在线状态
|
||||
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ imei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||
// }
|
||||
//
|
||||
// String[] topicArr = receivedTopic.split("/");
|
||||
//
|
||||
// NewMqttRuleContext context = new NewMqttRuleContext();
|
||||
// context.setCommandType(topicArr[2]+"_"+funcType);
|
||||
// context.setDeviceImei(imei);
|
||||
// context.setPayloadDict(payloadDict);
|
||||
//
|
||||
// boolean ruleExecuted = newRuleEngine.executeRule(context);
|
||||
//
|
||||
// if (!ruleExecuted) {
|
||||
// log.warn("未找到匹配的规则来处理命令类型: {}", topicArr[2] + " : " +funcType);
|
||||
// }
|
||||
// } finally {
|
||||
// //释放锁
|
||||
// lockTemplate.releaseLock(lockInfo);
|
||||
// }
|
||||
|
||||
|
||||
/* ===== 追加:根据报文内容识别格式并统一解析 ===== */
|
||||
// int intType = MqttXinghanCommandType.computeVirtualCommandType(payloadDict);
|
||||
// if (intType > 0) {
|
||||
// MqttRuleContext newCtx = new MqttRuleContext();
|
||||
// String commandType = "Light_"+intType;
|
||||
// newCtx.setCommandType(commandType);
|
||||
// newCtx.setDeviceImei(imei);
|
||||
// newCtx.setPayloadDict(payloadDict);
|
||||
//
|
||||
// boolean ok = ruleEngine.executeRule(newCtx);
|
||||
// if (!ok) {
|
||||
// log.warn("新规则引擎未命中, imei={}", imei);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -9,9 +9,12 @@ import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
|
||||
import com.fuyuanshen.global.mqtt.base.MqttRuleEngine;
|
||||
import com.fuyuanshen.global.mqtt.base.MqttXinghanCommandType;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
@ -21,6 +24,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
@ -38,55 +42,77 @@ public class ReceiverMessageHandler implements MessageHandler {
|
||||
String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
|
||||
String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString();
|
||||
String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString();
|
||||
|
||||
|
||||
log.info("MQTT payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}",
|
||||
payload, receivedTopic, receivedQos, timestamp);
|
||||
|
||||
|
||||
Dict payloadDict = JsonUtils.parseMap(payload.toString());
|
||||
if (receivedTopic == null || payloadDict == null) {
|
||||
return;
|
||||
}
|
||||
String[] subStr = receivedTopic.split("/");
|
||||
String deviceImei = subStr[1];
|
||||
String state = payloadDict.getStr("state");
|
||||
Object[] convertArr = ImageToCArrayConverter.convertByteStringToMixedObjectArray(state);
|
||||
if(StringUtils.isNotBlank(deviceImei)){
|
||||
String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||
RedisUtils.offerDeduplicated(queueKey,dedupKey,deviceImei, Duration.ofSeconds(900));
|
||||
//在线状态
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (convertArr.length > 0) {
|
||||
Byte val1 = (Byte) convertArr[0];
|
||||
MqttRuleContext context = new MqttRuleContext();
|
||||
context.setCommandType(val1);
|
||||
context.setConvertArr(convertArr);
|
||||
context.setDeviceImei(deviceImei);
|
||||
context.setPayloadDict(payloadDict);
|
||||
RedissonClient client = RedisUtils.getClient();
|
||||
String lockKey = "mqtt:consumer:lock:";
|
||||
String KEY = GlobalConstants.GLOBAL_REDIS_KEY + lockKey + deviceImei;
|
||||
RLock lock = client.getLock(KEY);
|
||||
|
||||
boolean ruleExecuted = ruleEngine.executeRule(context);
|
||||
|
||||
if (!ruleExecuted) {
|
||||
log.warn("未找到匹配的规则来处理命令类型: {}", val1);
|
||||
try {
|
||||
// 尝试获取锁,
|
||||
boolean isLocked = lock.tryLock(60, 3000, TimeUnit.MILLISECONDS);
|
||||
if (isLocked) {
|
||||
String state = payloadDict.getStr("state");
|
||||
Object[] convertArr = ImageToCArrayConverter.convertByteStringToMixedObjectArray(state);
|
||||
if(StringUtils.isNotBlank(deviceImei)){
|
||||
String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||
RedisUtils.offerDeduplicated(queueKey,dedupKey,deviceImei, Duration.ofSeconds(900));
|
||||
//在线状态
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (convertArr.length > 0) {
|
||||
Byte val1 = (Byte) convertArr[0];
|
||||
MqttRuleContext context = new MqttRuleContext();
|
||||
context.setCommandType(val1);
|
||||
context.setConvertArr(convertArr);
|
||||
context.setDeviceImei(deviceImei);
|
||||
context.setPayloadDict(payloadDict);
|
||||
|
||||
boolean ruleExecuted = ruleEngine.executeRule(context);
|
||||
|
||||
if (!ruleExecuted) {
|
||||
log.warn("未找到匹配的规则来处理命令类型: {}", val1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 追加:根据报文内容识别格式并统一解析 ===== */
|
||||
int intType = MqttXinghanCommandType.computeVirtualCommandType(payloadDict);
|
||||
if (intType > 0) {
|
||||
MqttRuleContext newCtx = new MqttRuleContext();
|
||||
newCtx.setCommandType((byte) intType);
|
||||
newCtx.setDeviceImei(deviceImei);
|
||||
newCtx.setPayloadDict(payloadDict);
|
||||
|
||||
boolean ok = ruleEngine.executeRule(newCtx);
|
||||
if (!ok) {
|
||||
log.warn("新规则引擎未命中, imei={}", deviceImei);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
log.warn("MQTT获取锁失败,请稍后再试");
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 追加:根据报文内容识别格式并统一解析 ===== */
|
||||
int intType = MqttXinghanCommandType.computeVirtualCommandType(payloadDict);
|
||||
if (intType > 0) {
|
||||
MqttRuleContext newCtx = new MqttRuleContext();
|
||||
newCtx.setCommandType((byte) intType);
|
||||
newCtx.setDeviceImei(deviceImei);
|
||||
newCtx.setPayloadDict(payloadDict);
|
||||
|
||||
boolean ok = ruleEngine.executeRule(newCtx);
|
||||
if (!ok) {
|
||||
log.warn("新规则引擎未命中, imei={}", deviceImei);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
// 释放锁
|
||||
if (lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,18 +38,18 @@ public class BjqActiveReportingDeviceDataRule implements MqttMessageRule {
|
||||
@Override
|
||||
public void execute(MqttRuleContext context) {
|
||||
try {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
// Latitude, longitude
|
||||
//主灯档位,激光灯档位,电量百分比,充电状态,电池剩余续航时间
|
||||
String mainLightMode = convertArr[1].toString();
|
||||
String laserLightMode = convertArr[2].toString();
|
||||
String batteryPercentage = convertArr[3].toString();
|
||||
String chargeState = convertArr[4].toString();
|
||||
String batteryRemainingTime = convertArr[5].toString();
|
||||
|
||||
// 发送设备状态和位置信息到Redis
|
||||
asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(), mainLightMode, laserLightMode,
|
||||
batteryPercentage, chargeState, batteryRemainingTime);
|
||||
// Object[] convertArr = context.getConvertArr();
|
||||
// // Latitude, longitude
|
||||
// //主灯档位,激光灯档位,电量百分比,充电状态,电池剩余续航时间
|
||||
// String mainLightMode = convertArr[1].toString();
|
||||
// String laserLightMode = convertArr[2].toString();
|
||||
// String batteryPercentage = convertArr[3].toString();
|
||||
// String chargeState = convertArr[4].toString();
|
||||
// String batteryRemainingTime = convertArr[5].toString();
|
||||
//
|
||||
// // 发送设备状态和位置信息到Redis
|
||||
// asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(), mainLightMode, laserLightMode,
|
||||
// batteryPercentage, chargeState, batteryRemainingTime);
|
||||
} catch (Exception e) {
|
||||
log.error("处理上报数据命令时出错", e);
|
||||
}
|
||||
@ -67,31 +67,29 @@ public class BjqActiveReportingDeviceDataRule implements MqttMessageRule {
|
||||
*/
|
||||
public void asyncSendDeviceDataToRedisWithFuture(String deviceImei, String mainLightMode, String laserLightMode,
|
||||
String batteryPercentage, String chargeState, String batteryRemainingTime) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
// 构造设备状态信息对象
|
||||
Map<String, Object> deviceInfo = new LinkedHashMap<>();
|
||||
deviceInfo.put("deviceImei", deviceImei);
|
||||
deviceInfo.put("mainLightMode", mainLightMode);
|
||||
deviceInfo.put("laserLightMode", laserLightMode);
|
||||
deviceInfo.put("batteryPercentage", batteryPercentage);
|
||||
deviceInfo.put("chargeState", chargeState);
|
||||
deviceInfo.put("batteryRemainingTime", batteryRemainingTime);
|
||||
deviceInfo.put("timestamp", System.currentTimeMillis());
|
||||
try {
|
||||
// 构造设备状态信息对象
|
||||
Map<String, Object> deviceInfo = new LinkedHashMap<>();
|
||||
deviceInfo.put("deviceImei", deviceImei);
|
||||
deviceInfo.put("mainLightMode", mainLightMode);
|
||||
deviceInfo.put("laserLightMode", laserLightMode);
|
||||
deviceInfo.put("batteryPercentage", batteryPercentage);
|
||||
deviceInfo.put("chargeState", chargeState);
|
||||
deviceInfo.put("batteryRemainingTime", batteryRemainingTime);
|
||||
deviceInfo.put("timestamp", System.currentTimeMillis());
|
||||
|
||||
// 将设备状态信息存储到Redis中
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_STATUS_KEY_PREFIX;
|
||||
String deviceInfoJson = JsonUtils.toJsonString(deviceInfo);
|
||||
// 将设备状态信息存储到Redis中
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_STATUS_KEY_PREFIX;
|
||||
String deviceInfoJson = JsonUtils.toJsonString(deviceInfo);
|
||||
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(deviceRedisKey, deviceInfoJson);
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(deviceRedisKey, deviceInfoJson);
|
||||
|
||||
log.info("设备状态信息已异步发送到Redis: device={}, mainLightMode={}, laserLightMode={}, batteryPercentage={}",
|
||||
deviceImei, mainLightMode, laserLightMode, batteryPercentage);
|
||||
} catch (Exception e) {
|
||||
log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
log.info("设备状态信息已异步发送到Redis: device={}, mainLightMode={}, laserLightMode={}, batteryPercentage={}",
|
||||
deviceImei, mainLightMode, laserLightMode, batteryPercentage);
|
||||
} catch (Exception e) {
|
||||
log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -44,37 +44,37 @@ public class BjqBootLogoRule implements MqttMessageRule {
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
try {
|
||||
Byte val2 = (Byte) context.getConvertArr()[1];
|
||||
if (val2 == 100) {
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
return;
|
||||
}
|
||||
|
||||
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() +DEVICE_BOOT_LOGO_KEY_PREFIX);
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
|
||||
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512);
|
||||
log.info("第{}块数据大小: {} 字节", val2, specificChunk.length);
|
||||
|
||||
ArrayList<Integer> intData = new ArrayList<>();
|
||||
intData.add(3);
|
||||
intData.add((int) val2);
|
||||
ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData);
|
||||
intData.add(0);
|
||||
intData.add(0);
|
||||
intData.add(0);
|
||||
intData.add(0);
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("instruct", intData);
|
||||
|
||||
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
log.info("发送开机LOGO点阵数据到设备消息=>topic:{},payload:{}",
|
||||
MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
|
||||
JsonUtils.toJsonString(map));
|
||||
// Byte val2 = (Byte) context.getConvertArr()[1];
|
||||
// if (val2 == 100) {
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() +DEVICE_BOOT_LOGO_KEY_PREFIX);
|
||||
// if (StringUtils.isEmpty(data)) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
|
||||
// byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512);
|
||||
// log.info("第{}块数据大小: {} 字节", val2, specificChunk.length);
|
||||
//
|
||||
// ArrayList<Integer> intData = new ArrayList<>();
|
||||
// intData.add(3);
|
||||
// intData.add((int) val2);
|
||||
// ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData);
|
||||
// intData.add(0);
|
||||
// intData.add(0);
|
||||
// intData.add(0);
|
||||
// intData.add(0);
|
||||
//
|
||||
// Map<String, Object> map = new HashMap<>();
|
||||
// map.put("instruct", intData);
|
||||
//
|
||||
// mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
// log.info("发送开机LOGO点阵数据到设备消息=>topic:{},payload:{}",
|
||||
// MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
|
||||
// JsonUtils.toJsonString(map));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理开机LOGO时出错", e);
|
||||
|
||||
@ -34,15 +34,15 @@ public class BjqLaserModeSettingsRule implements MqttMessageRule {
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
try {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
|
||||
String mode = convertArr[1].toString();
|
||||
if(StringUtils.isNotBlank(mode)){
|
||||
// 发送设备状态和位置信息到Redis
|
||||
syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mode);
|
||||
}
|
||||
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
||||
// Object[] convertArr = context.getConvertArr();
|
||||
//
|
||||
// String mode = convertArr[1].toString();
|
||||
// if(StringUtils.isNotBlank(mode)){
|
||||
// // 发送设备状态和位置信息到Redis
|
||||
// syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mode);
|
||||
// }
|
||||
//
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
||||
} catch (Exception e) {
|
||||
log.error("处理激光模式命令时出错", e);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(30));
|
||||
|
||||
@ -34,15 +34,15 @@ public class BjqLightBrightnessRule implements MqttMessageRule {
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
try {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
|
||||
String convertValue = convertArr[1].toString();
|
||||
// 将设备状态信息存储到Redis中
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX;
|
||||
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(deviceRedisKey, convertValue);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
// Object[] convertArr = context.getConvertArr();
|
||||
//
|
||||
// String convertValue = convertArr[1].toString();
|
||||
// // 将设备状态信息存储到Redis中
|
||||
// String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX;
|
||||
//
|
||||
// // 存储到Redis
|
||||
// RedisUtils.setCacheObject(deviceRedisKey, convertValue);
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
} catch (Exception e) {
|
||||
log.error("处理灯光亮度命令时出错", e);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
|
||||
|
||||
@ -52,26 +52,26 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
try {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
// Latitude, longitude
|
||||
String latitude = convertArr[1].toString();
|
||||
String longitude = convertArr[2].toString();
|
||||
// 判断 latitude 和 longitude 是否都为 0
|
||||
if ("0".equals(latitude) && "0".equals(longitude)) {
|
||||
log.info("位置信息为0,不存储到Redis: device={}, lat={}, lon={}", context.getDeviceImei(), latitude, longitude);
|
||||
return;
|
||||
}
|
||||
// 异步发送经纬度到Redis
|
||||
asyncSendLocationToRedisWithFuture(context.getDeviceImei(), latitude, longitude);
|
||||
// 异步保存数据
|
||||
asyncSaveLocationToMySQLWithFuture(context.getDeviceImei(), latitude, longitude);
|
||||
|
||||
Map<String, Object> map = buildLocationDataMap(latitude, longitude);
|
||||
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
log.info("发送定位数据到设备=>topic:{},payload:{}",
|
||||
MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
|
||||
JsonUtils.toJsonString(map));
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
// Object[] convertArr = context.getConvertArr();
|
||||
// // Latitude, longitude
|
||||
// String latitude = convertArr[1].toString();
|
||||
// String longitude = convertArr[2].toString();
|
||||
// // 判断 latitude 和 longitude 是否都为 0
|
||||
// if ("0".equals(latitude) && "0".equals(longitude)) {
|
||||
// log.info("位置信息为0,不存储到Redis: device={}, lat={}, lon={}", context.getDeviceImei(), latitude, longitude);
|
||||
// return;
|
||||
// }
|
||||
// // 异步发送经纬度到Redis
|
||||
// asyncSendLocationToRedisWithFuture(context.getDeviceImei(), latitude, longitude);
|
||||
// // 异步保存数据
|
||||
// asyncSaveLocationToMySQLWithFuture(context.getDeviceImei(), latitude, longitude);
|
||||
//
|
||||
// Map<String, Object> map = buildLocationDataMap(latitude, longitude);
|
||||
// mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
// log.info("发送定位数据到设备=>topic:{},payload:{}",
|
||||
// MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
|
||||
// JsonUtils.toJsonString(map));
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
} catch (Exception e) {
|
||||
log.error("处理定位数据命令时出错", e);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
|
||||
@ -121,16 +121,15 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
* @param longitude 经度
|
||||
*/
|
||||
public void asyncSendLocationToRedisWithFuture(String deviceImei, String latitude, String longitude) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// String[] latArr = latitude.split("\\.");
|
||||
// String[] lonArr = longitude.split("\\.");
|
||||
// // 将位置信息存储到Redis中
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
|
||||
// String redisObj = RedisUtils.getCacheObject(redisKey);
|
||||
// JSONObject jsonOBj = JSONObject.parseObject(redisObj);
|
||||
// if(jsonOBj != null){
|
||||
@ -150,34 +149,33 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
// }
|
||||
// }
|
||||
|
||||
// 构造位置信息对象
|
||||
Map<String, Object> locationInfo = new LinkedHashMap<>();
|
||||
double[] doubles = LngLonUtil.gps84_To_Gcj02(Double.parseDouble(latitude), Double.parseDouble(longitude));
|
||||
locationInfo.put("deviceImei", deviceImei);
|
||||
locationInfo.put("latitude", doubles[0]);
|
||||
locationInfo.put("longitude", doubles[1]);
|
||||
locationInfo.put("wgs84_latitude", latitude);
|
||||
locationInfo.put("wgs84_longitude", longitude);
|
||||
String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
|
||||
locationInfo.put("address", address);
|
||||
locationInfo.put("timestamp", System.currentTimeMillis());
|
||||
// 构造位置信息对象
|
||||
Map<String, Object> locationInfo = new LinkedHashMap<>();
|
||||
double[] doubles = LngLonUtil.gps84_To_Gcj02(Double.parseDouble(latitude), Double.parseDouble(longitude));
|
||||
locationInfo.put("deviceImei", deviceImei);
|
||||
locationInfo.put("latitude", doubles[0]);
|
||||
locationInfo.put("longitude", doubles[1]);
|
||||
locationInfo.put("wgs84_latitude", latitude);
|
||||
locationInfo.put("wgs84_longitude", longitude);
|
||||
String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
|
||||
locationInfo.put("address", address);
|
||||
locationInfo.put("timestamp", System.currentTimeMillis());
|
||||
|
||||
|
||||
String locationJson = JsonUtils.toJsonString(locationInfo);
|
||||
String locationJson = JsonUtils.toJsonString(locationInfo);
|
||||
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(redisKey, locationJson);
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(redisKey, locationJson);
|
||||
|
||||
// 存储到一个列表中,保留历史位置信息
|
||||
// 存储到一个列表中,保留历史位置信息
|
||||
// String locationHistoryKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX + deviceImei;
|
||||
// RedisUtils.addCacheList(locationHistoryKey, locationJson);
|
||||
// RedisUtils.expire(locationHistoryKey, Duration.ofDays(90));
|
||||
storeDeviceTrajectoryWithSortedSet(deviceImei, locationJson);
|
||||
log.info("位置信息已异步发送到Redis: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||
} catch (Exception e) {
|
||||
log.error("异步发送位置信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
storeDeviceTrajectoryWithSortedSet(deviceImei, locationJson);
|
||||
log.info("位置信息已异步发送到Redis: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||
} catch (Exception e) {
|
||||
log.error("异步发送位置信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -189,20 +187,18 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
* @param longitude 经度
|
||||
*/
|
||||
public void asyncSaveLocationToMySQLWithFuture(String deviceImei, String latitude, String longitude) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用服务层方法更新设备位置信息
|
||||
deviceService.updateDeviceLocationByImei(deviceImei, longitude, latitude);
|
||||
|
||||
log.info("位置信息已异步保存到MySQL: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||
} catch (Exception e) {
|
||||
log.error("异步保存位置信息到MySQL时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
try {
|
||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// 调用服务层方法更新设备位置信息
|
||||
deviceService.updateDeviceLocationByImei(deviceImei, longitude, latitude);
|
||||
|
||||
log.info("位置信息已异步保存到MySQL: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||
} catch (Exception e) {
|
||||
log.error("异步保存位置信息到MySQL时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -50,45 +50,47 @@ public class BjqModeRule implements MqttMessageRule {
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
try {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
|
||||
String mainLightMode = convertArr[1].toString();
|
||||
String batteryRemainingTime = convertArr[2].toString();
|
||||
if (StringUtils.isNotBlank(mainLightMode)) {
|
||||
log.info("设备离线mainLightMode:{}", mainLightMode);
|
||||
if ("0".equals(mainLightMode)) {
|
||||
|
||||
// 设备离线
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + context.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX;
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "0");
|
||||
|
||||
String sendMessageIng = GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + context.getDeviceImei() + ":messageSending";
|
||||
String messageSendingValue = RedisUtils.getCacheObject(sendMessageIng);
|
||||
if ("1".equals(messageSendingValue)) {
|
||||
// 设置为故障状态
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "2");
|
||||
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("device_imei", context.getDeviceImei());
|
||||
updateWrapper.set("online_status", 2);
|
||||
deviceService.update(updateWrapper);
|
||||
RedisUtils.deleteObject(sendMessageIng);
|
||||
|
||||
// 解除告警
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX;
|
||||
if (RedisUtils.getCacheObject(deviceRedisKey) != null) {
|
||||
RedisUtils.deleteObject(deviceRedisKey);
|
||||
}
|
||||
cancelAlarm(context.getDeviceImei());
|
||||
}
|
||||
}
|
||||
// 发送设备状态和位置信息到Redis
|
||||
syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(), mainLightMode);
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX;
|
||||
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(deviceRedisKey, batteryRemainingTime);
|
||||
}
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
log.info("处理灯光模式命令");
|
||||
log.info("MQTT消息负载字典:{}", context.getPayloadDict());
|
||||
// Object[] convertArr = context.getConvertArr();
|
||||
//
|
||||
// String mainLightMode = convertArr[1].toString();
|
||||
// String batteryRemainingTime = convertArr[2].toString();
|
||||
// if (StringUtils.isNotBlank(mainLightMode)) {
|
||||
// log.info("设备离线mainLightMode:{}", mainLightMode);
|
||||
// if ("0".equals(mainLightMode)) {
|
||||
//
|
||||
// // 设备离线
|
||||
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + context.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX;
|
||||
// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "0");
|
||||
//
|
||||
// String sendMessageIng = GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + context.getDeviceImei() + ":messageSending";
|
||||
// String messageSendingValue = RedisUtils.getCacheObject(sendMessageIng);
|
||||
// if ("1".equals(messageSendingValue)) {
|
||||
// // 设置为故障状态
|
||||
// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "2");
|
||||
// UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
// updateWrapper.eq("device_imei", context.getDeviceImei());
|
||||
// updateWrapper.set("online_status", 2);
|
||||
// deviceService.update(updateWrapper);
|
||||
// RedisUtils.deleteObject(sendMessageIng);
|
||||
//
|
||||
// // 解除告警
|
||||
// String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX;
|
||||
// if (RedisUtils.getCacheObject(deviceRedisKey) != null) {
|
||||
// RedisUtils.deleteObject(deviceRedisKey);
|
||||
// }
|
||||
// cancelAlarm(context.getDeviceImei());
|
||||
// }
|
||||
// }
|
||||
// // 发送设备状态和位置信息到Redis
|
||||
// syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(), mainLightMode);
|
||||
// String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX;
|
||||
//
|
||||
// // 存储到Redis
|
||||
// RedisUtils.setCacheObject(deviceRedisKey, batteryRemainingTime);
|
||||
// }
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
} catch (Exception e) {
|
||||
log.error("处理灯光模式命令时出错", e);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
|
||||
|
||||
@ -34,8 +34,8 @@ public class BjqPersonnelInfoDataRule implements MqttMessageRule {
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
try {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
||||
// Object[] convertArr = context.getConvertArr();
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
||||
} catch (Exception e) {
|
||||
log.error("处理定位数据命令时出错", e);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(30));
|
||||
|
||||
@ -45,47 +45,47 @@ public class BjqSendMessageRule implements MqttMessageRule {
|
||||
try {
|
||||
|
||||
// Byte val2 = (Byte) context.getConvertArr()[1];
|
||||
String val2Str = context.getConvertArr()[1].toString();
|
||||
int val2 = Integer.parseInt(val2Str);
|
||||
System.out.println("收到设备信息命令:"+val2);
|
||||
if (val2 == 100) {
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
return;
|
||||
}
|
||||
|
||||
if(val2==200){
|
||||
String sendMessageIng = GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() + ":messageSending";
|
||||
RedisUtils.deleteObject(sendMessageIng);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() + ":app_send_message_data");
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
|
||||
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512);
|
||||
log.info("第{}块数据大小: {} 字节", val2, specificChunk.length);
|
||||
// System.out.println("第" + val2 + "块数据: " + Arrays.toString(specificChunk));
|
||||
|
||||
ArrayList<Integer> intData = new ArrayList<>();
|
||||
intData.add(6);
|
||||
intData.add(val2);
|
||||
ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData);
|
||||
intData.add(0);
|
||||
intData.add(0);
|
||||
intData.add(0);
|
||||
intData.add(0);
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("instruct", intData);
|
||||
|
||||
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
log.info("发送设备信息数据到设备消息=>topic:{},payload:{}",
|
||||
MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
|
||||
JsonUtils.toJsonString(map));
|
||||
// String val2Str = context.getConvertArr()[1].toString();
|
||||
// int val2 = Integer.parseInt(val2Str);
|
||||
// System.out.println("收到设备信息命令:"+val2);
|
||||
// if (val2 == 100) {
|
||||
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if(val2==200){
|
||||
// String sendMessageIng = GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() + ":messageSending";
|
||||
// RedisUtils.deleteObject(sendMessageIng);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() + ":app_send_message_data");
|
||||
// if (StringUtils.isEmpty(data)) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
|
||||
// byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512);
|
||||
// log.info("第{}块数据大小: {} 字节", val2, specificChunk.length);
|
||||
//// System.out.println("第" + val2 + "块数据: " + Arrays.toString(specificChunk));
|
||||
//
|
||||
// ArrayList<Integer> intData = new ArrayList<>();
|
||||
// intData.add(6);
|
||||
// intData.add(val2);
|
||||
// ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData);
|
||||
// intData.add(0);
|
||||
// intData.add(0);
|
||||
// intData.add(0);
|
||||
// intData.add(0);
|
||||
//
|
||||
// Map<String, Object> map = new HashMap<>();
|
||||
// map.put("instruct", intData);
|
||||
//
|
||||
// mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
// log.info("发送设备信息数据到设备消息=>topic:{},payload:{}",
|
||||
// MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
|
||||
// JsonUtils.toJsonString(map));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理发送设备信息时出错", e);
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 爆闪模式开启/关闭
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType10StrobeMode implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_10";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J爆闪模式开启/关闭,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":strobeMode";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J爆闪模式开启/关闭失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 修改警示灯爆闪频率
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType11Frequency implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_11";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J修改警示灯爆闪频率,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":frequency";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J修改警示灯爆闪频率失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 强制声光报警开启/关闭
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType12ForceAudio implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_12";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J强制声光报警开启/关闭,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// 构建强制声光报警开关的Redis键
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":forceAudio";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// // 存储强制声光报警开关状态到Redis
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J强制声光报警开启/关闭失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 警示灯LED亮度调节
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType13Brightness implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_13";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J警示灯LED亮度调节,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":brightness";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J警示灯LED亮度调节失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 获取警示灯的当前工作方式(设备下发返回响应数据、设备定时主动上报)
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType14Report implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_14";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J设备定时主动上报,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
context.getDeviceImei() + ":report";
|
||||
|
||||
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
if (payloadDict != null) {
|
||||
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J设备定时主动上报失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
//package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
//
|
||||
//import com.alibaba.fastjson2.JSONObject;
|
||||
//import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
//import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
//import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
//import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//
|
||||
//import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
//
|
||||
///**
|
||||
// * 设备复位
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//public class FuncType1Rest implements NewMqttMessageRule {
|
||||
//
|
||||
// @Override
|
||||
// public String getCommandType() {
|
||||
// return "HBY100_1";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void execute(NewMqttRuleContext context) {
|
||||
// log.info("开始处理设备复位,消息负载:{}", context.getPayloadDict());
|
||||
//
|
||||
// try {
|
||||
// // 构建强制声光报警开关的Redis键
|
||||
//// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
//// context.getDeviceImei() + ":force_audio_visual_alarm_switch";
|
||||
////
|
||||
//// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
//// if (payloadDict != null) {
|
||||
//// // 存储强制声光报警开关状态到Redis
|
||||
//// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
//// }
|
||||
// log.info("设备复位,设备ID:{}", context.getDeviceImei());
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理设备复位失败", e);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,46 @@
|
||||
//package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
//
|
||||
//import com.alibaba.fastjson2.JSONObject;
|
||||
//import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
//import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
//import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
//import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//
|
||||
//import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
//
|
||||
///**
|
||||
// * 获取设备基础信息
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//public class FuncType2BaseInfo implements NewMqttMessageRule {
|
||||
//
|
||||
// @Override
|
||||
// public String getCommandType() {
|
||||
// return "HBY100_2";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void execute(NewMqttRuleContext context) {
|
||||
// log.info("开始处理强制声光报警开关,消息负载:{}", context.getPayloadDict());
|
||||
//
|
||||
// try {
|
||||
// // 构建强制声光报警开关的Redis键
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":force_audio_visual_alarm_switch";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// // 存储强制声光报警开关状态到Redis
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
// log.info("强制声光报警开关处理完成,设备ID:{}", context.getDeviceImei());
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理强制声光报警开关失败", e);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 获取设备位置信息(设备下发返回响应数据、设备定时主动上报)
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType3Location implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_3";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J获取设备位置信息,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
context.getDeviceImei() + ":location";
|
||||
|
||||
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
if (payloadDict != null) {
|
||||
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J获取设备位置信息失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 获取设备电源状态(设备下发返回响应数据、设备定时主动上报)
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType4PowerStatus implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_4";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J获取设备电源状态,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
context.getDeviceImei() + ":powerStatus";
|
||||
|
||||
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
if (payloadDict != null) {
|
||||
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J获取设备电源状态失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 更新语音
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType5UpdateVoice implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_5";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J更新语音,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":updateVoice";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J更新语音失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 语音播报开启/关闭
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType6VoicePlay implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_9";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J语音播报开启/关闭,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":VoicePlay";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J语音播报开启/关闭失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
/**
|
||||
* 修改音量
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FuncType9UpdateVolume implements NewMqttMessageRule {
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return "HBY100_9";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(NewMqttRuleContext context) {
|
||||
log.info("HBY100J修改音量,消息负载:{}", context.getPayloadDict());
|
||||
|
||||
try {
|
||||
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||
// context.getDeviceImei() + ":updateVolume";
|
||||
//
|
||||
// Map<String, Object> payloadDict = context.getPayloadDict();
|
||||
// if (payloadDict != null) {
|
||||
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
log.error("HBY100J修改音量失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 爆闪模式开启/关闭
|
||||
* 对应 funcType="10"
|
||||
* mode:
|
||||
* 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||
*/
|
||||
@Data
|
||||
public class FuncType10StrobeModeRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* 爆闪模式是否启用
|
||||
* 0 - 禁用
|
||||
* 1 - 启用
|
||||
*/
|
||||
private Integer enable;
|
||||
/**
|
||||
* 爆闪模式类型 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||
**/
|
||||
private Integer mode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 修改警示灯爆闪频率
|
||||
* 对应 funcType="11"
|
||||
*/
|
||||
@Data
|
||||
public class FuncType11FrequencyRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
//"frequency": 1-12
|
||||
private Integer frequency;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 强制声光报警开启/关闭
|
||||
* 对应 funcType="12"
|
||||
*/
|
||||
@Data
|
||||
public class FuncType12ForceAudioRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
/**
|
||||
* 语音报警0关闭,1开启
|
||||
*/
|
||||
private Integer voiceStrobeAlarm;
|
||||
//语音模式0公安,1消防,2应急,3交警,4市政,5铁路,6医疗,7部队,8水利
|
||||
private Integer mode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 警示灯LED亮度调节
|
||||
* 对应 funcType="13"
|
||||
*/
|
||||
@Data
|
||||
public class FuncType13BrightnessRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
/**
|
||||
* 红色LED亮度值0-100
|
||||
*/
|
||||
private Integer red;
|
||||
|
||||
/**
|
||||
* 蓝色LED亮度值0-100
|
||||
*/
|
||||
private Integer blue;
|
||||
|
||||
/**
|
||||
* 黄色LED亮度值0-100
|
||||
*/
|
||||
private Integer yellow;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,143 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 设备状态上报数据DTO
|
||||
* 对应MQTT消息中设备上报的完整状态数据结构
|
||||
*/
|
||||
@Data
|
||||
public class FuncType14StatusReport {
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码(如"14"表示特定功能指令)
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 响应状态码(如"200"表示成功)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 设备详细状态数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 设备详细状态数据内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* 语音播报开关:0-关闭,1-开启
|
||||
*/
|
||||
@JsonProperty("voice_broadcast")
|
||||
private Integer voiceBroadcast;
|
||||
|
||||
/**
|
||||
* 警报器(警笛)设置
|
||||
*/
|
||||
@JsonProperty("siren_alarm")
|
||||
private SirenAlarm sirenAlarm;
|
||||
|
||||
/**
|
||||
* LED爆闪设置
|
||||
*/
|
||||
@JsonProperty("led_strobe")
|
||||
private LedStrobe ledStrobe;
|
||||
|
||||
/**
|
||||
* 音量设置(0-100范围)
|
||||
*/
|
||||
@JsonProperty("volume")
|
||||
private Integer volume;
|
||||
|
||||
/**
|
||||
* 亮度设置(RGB三色亮度值)
|
||||
*/
|
||||
@JsonProperty("brightness")
|
||||
private Brightness brightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* 警报器(警笛)设置
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class SirenAlarm {
|
||||
|
||||
/**
|
||||
* 是否启用:0-禁用,1-启用
|
||||
*/
|
||||
@JsonProperty("enable")
|
||||
private Integer enable;
|
||||
|
||||
/**
|
||||
* 工作模式:0-默认模式,其他值表示不同报警模式
|
||||
*/
|
||||
@JsonProperty("mode")
|
||||
private Integer mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* LED爆闪设置
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class LedStrobe {
|
||||
|
||||
/**
|
||||
* 是否启用:0-禁用,1-启用
|
||||
*/
|
||||
@JsonProperty("enable")
|
||||
private Integer enable;
|
||||
|
||||
/**
|
||||
* 工作模式:0-默认模式,其他值表示不同爆闪模式
|
||||
*/
|
||||
@JsonProperty("mode")
|
||||
private Integer mode;
|
||||
|
||||
/**
|
||||
* 爆闪频率(单位:Hz或自定义单位)
|
||||
*/
|
||||
@JsonProperty("frequency")
|
||||
private Integer frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* 亮度设置(RGB三色)
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Brightness {
|
||||
|
||||
/**
|
||||
* 红色通道亮度值(0-255或百分比)
|
||||
*/
|
||||
@JsonProperty("red")
|
||||
private Integer red;
|
||||
|
||||
/**
|
||||
* 绿色通道亮度值(0-255或百分比)
|
||||
*/
|
||||
@JsonProperty("green")
|
||||
private Integer green;
|
||||
|
||||
/**
|
||||
* 蓝色通道亮度值(0-255或百分比)
|
||||
*/
|
||||
@JsonProperty("blue")
|
||||
private Integer blue;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 更新设备语音
|
||||
*/
|
||||
@Data
|
||||
public class FuncType5UpdateVoiceReport {
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码("5" 表示操作状态上报)
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 响应状态码("200" 表示请求成功)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 操作详细状态数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 操作状态数据内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* 操作执行状态:
|
||||
* 0 - 未开始 / 失败
|
||||
* 1 - 执行中
|
||||
* 2 - 成功完成
|
||||
* (具体含义需结合业务协议定义)
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 操作进度百分比(0-100),仅在 status=1(执行中)时有效
|
||||
*/
|
||||
@JsonProperty("progress")
|
||||
private Integer progress;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 语音资源配置请求DTO
|
||||
* 对应 funcType="5" 的语音资源下发指令(如语音播报文件配置)
|
||||
*/
|
||||
@Data
|
||||
public class FuncType5UpdateVoiceRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码("5" 表示语音资源配置)
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* 语音类型:
|
||||
* 0 - 默认语音(如标准提示音)
|
||||
* 1 - 自定义语音
|
||||
* 2 - 紧急语音
|
||||
* (具体含义需依据设备协议定义)
|
||||
*/
|
||||
private Integer voiceType;
|
||||
|
||||
/**
|
||||
* 语音资源URL(MP3等音频文件地址)
|
||||
* 示例:http://8.129.5.250:10001/voice/01.mp3
|
||||
*/
|
||||
private String voiceResource;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 语音播报开启/关闭
|
||||
* 对应 funcType="6"
|
||||
*/
|
||||
@Data
|
||||
public class FuncType6VoicePlayRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
/**
|
||||
* 语音报警0关闭,1开启
|
||||
*/
|
||||
private Integer voiceBroadcast;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 修改音量
|
||||
* 对应 funcType="9"
|
||||
*/
|
||||
@Data
|
||||
public class FuncType9UpdateVolumeRequest {
|
||||
|
||||
/**
|
||||
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||
*/
|
||||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 语音配置数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 语音配置详情内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
//"volume": 1-100(app端可根据需求把40作为低音量, 70作为中音量,100作为高音量)
|
||||
private Integer volume;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 设备位置上报DTO
|
||||
* 对应MQTT消息中设备上报的地理位置数据
|
||||
*/
|
||||
@Data
|
||||
public class FunctionType3LocationReport {
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码(如"3"表示位置上报)
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 响应状态码(如"200"表示成功)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 位置详细数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 位置详细数据内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* 经度(WGS-84坐标系,如22.543100)
|
||||
*/
|
||||
@JsonProperty("longitude")
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 纬度(WGS-84坐标系,如114.057900)
|
||||
*/
|
||||
@JsonProperty("latitude")
|
||||
private Double latitude;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 设备电源状态上报DTO
|
||||
* 对应MQTT消息中设备上报的电源相关状态数据
|
||||
*/
|
||||
@Data
|
||||
public class FunctionType4PowerStatusReport {
|
||||
|
||||
/**
|
||||
* 设备IMEI号(国际移动设备识别码)
|
||||
*/
|
||||
private String imei;
|
||||
|
||||
/**
|
||||
* 功能类型编码(如"4"表示电源状态上报)
|
||||
*/
|
||||
private String funcType;
|
||||
|
||||
/**
|
||||
* 响应状态码(如"200"表示成功)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 时间戳(毫秒级Unix时间戳)
|
||||
*/
|
||||
private Long timestamp;
|
||||
|
||||
/**
|
||||
* 电源详细状态数据
|
||||
*/
|
||||
private Data data;
|
||||
|
||||
/**
|
||||
* 电源详细状态数据内部类
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* 电池容量(如"5000mAh")
|
||||
*/
|
||||
@JsonProperty("capacity")
|
||||
private String capacity;
|
||||
|
||||
/**
|
||||
* 电压值(单位:V,0表示未检测或无电)
|
||||
*/
|
||||
@JsonProperty("voltage")
|
||||
private Integer voltage;
|
||||
|
||||
/**
|
||||
* 电量百分比(0-100,0表示低电量或未检测)
|
||||
*/
|
||||
@JsonProperty("level")
|
||||
private Integer level;
|
||||
|
||||
/**
|
||||
* 充电状态:0-未充电,1-正在充电
|
||||
*/
|
||||
@JsonProperty("charge")
|
||||
private Integer charge;
|
||||
|
||||
/**
|
||||
* 12V电源状态:0-关闭/无输出,1-开启/有输出
|
||||
*/
|
||||
@JsonProperty("12v_power")
|
||||
private Integer twelveVPower;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.fuyuanshen.global.mqtt.utils;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GenerateIdUtil {
|
||||
/**
|
||||
* 生成数字唯一ID - 基于UUID
|
||||
*/
|
||||
public static String generateNumericId() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
return Math.abs(uuid.toString().hashCode()) + "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成数字唯一ID - 基于时间戳+随机数
|
||||
*/
|
||||
public static long generateTimestampBasedId() {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
int random = new Random().nextInt(1000); // 0-999随机数
|
||||
return timestamp * 1000 + random;
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,14 +7,18 @@ import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -95,40 +99,18 @@ public class MqttMessageConsumer {
|
||||
}
|
||||
|
||||
// 处理具体业务逻辑的方法
|
||||
private void processMessage(String message) {
|
||||
private void processMessage(String imei) {
|
||||
String threadName = Thread.currentThread().getName();
|
||||
try {
|
||||
log.info("业务处理线程 {} 开始处理消息: {}", threadName, message);
|
||||
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ message + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
// String deviceOnlineStatusRedis = RedisUtils.getCacheObject(deviceOnlineStatusRedisKey);
|
||||
// if(StringUtils.isBlank(deviceOnlineStatusRedis)){
|
||||
// UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
// updateWrapper.eq("device_imei", message)
|
||||
// .set("online_status", 1);
|
||||
// deviceMapper.update(updateWrapper);
|
||||
// }
|
||||
// QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
|
||||
// queryWrapper.eq("device_imei", message);
|
||||
// queryWrapper.eq("online_status", 1);
|
||||
// Long count = deviceMapper.selectCount(queryWrapper);
|
||||
// if(count == 0){
|
||||
// UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
// updateWrapper.eq("device_imei", message)
|
||||
// .eq("online_status", 0)
|
||||
// .set("online_status", 1);
|
||||
// deviceMapper.update(updateWrapper);
|
||||
// }
|
||||
// 执行业务逻辑
|
||||
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("device_imei", message)
|
||||
updateWrapper.eq("device_imei", imei)
|
||||
.in("online_status", 0,2)
|
||||
.set("online_status", 1);
|
||||
int update = deviceMapper.update(updateWrapper);
|
||||
// 模拟业务处理耗时
|
||||
// Thread.sleep(200);
|
||||
|
||||
log.info("业务处理线程 {} 完成消息处理: {}", threadName, message);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("业务处理线程 {} 处理消息时发生错误: {}", threadName, message, e);
|
||||
log.error("业务处理线程 {} 处理消息时发生错误: {}", threadName, imei, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
package com.fuyuanshen.web.controller.device;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugEditDto;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||
@ -24,6 +28,8 @@ import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 联调中心
|
||||
@ -119,7 +125,7 @@ public class DeviceDebugController extends BaseController {
|
||||
}
|
||||
deviceDebugService.delFile(bo.getFileIds());
|
||||
// 修改操作视频
|
||||
if (!bo.getVideoUrl().isEmpty()) {
|
||||
if (bo.getVideoUrl().isEmpty()) {
|
||||
AppOperationVideoBo appOperationVideoBo = new AppOperationVideoBo();
|
||||
appOperationVideoBo.setDeviceIds(new Long[]{ bo.getDeviceId() });
|
||||
appOperationVideoBo.setVideoUrl(bo.getVideoUrl());
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package com.fuyuanshen.web.domain.vo;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package com.fuyuanshen.web.service.device;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
|
||||
@ -0,0 +1,340 @@
|
||||
package com.fuyuanshen.web.service.device;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.fuyuanshen.app.controller.device.bjq.AppDeviceHBY100JController;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppPersonnelInfo;
|
||||
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceHBY100JDetailVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
|
||||
import com.fuyuanshen.app.mapper.AppBusinessFileMapper;
|
||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper;
|
||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.utils.*;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.DeviceType;
|
||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
|
||||
import com.fuyuanshen.equipment.enums.LightModeEnum;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
|
||||
import com.fuyuanshen.global.mqtt.rule.hby100j.domin.*;
|
||||
import com.fuyuanshen.global.mqtt.utils.GenerateIdUtil;
|
||||
import com.fuyuanshen.system.domain.SysOss;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.mapper.SysOssMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.buildArr;
|
||||
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.generateFixedBitmapData;
|
||||
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceHBY100JBizService {
|
||||
|
||||
private final DeviceMapper deviceMapper;
|
||||
private final DeviceTypeMapper deviceTypeMapper;
|
||||
private final MqttGateway mqttGateway;
|
||||
private final DeviceLogMapper deviceLogMapper;
|
||||
private final IAppBusinessFileService appBusinessFileService;
|
||||
private final AppBusinessFileMapper appBusinessFileMapper;
|
||||
private final SysOssMapper sysOssMapper;
|
||||
|
||||
|
||||
private static final String DEVICE_TYPE = "HBY100/";
|
||||
/**
|
||||
* 记录设备操作日志
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param content 日志内容
|
||||
* @param operator 操作人
|
||||
*/
|
||||
private void recordDeviceLog(Long deviceId, String deviceName, String deviceAction, String content, Long operator) {
|
||||
try {
|
||||
// 创建设备日志实体
|
||||
com.fuyuanshen.equipment.domain.DeviceLog deviceLog = new com.fuyuanshen.equipment.domain.DeviceLog();
|
||||
deviceLog.setDeviceId(deviceId);
|
||||
deviceLog.setDeviceAction(deviceAction);
|
||||
deviceLog.setContent(content);
|
||||
deviceLog.setCreateBy(operator);
|
||||
deviceLog.setDeviceName(deviceName);
|
||||
deviceLog.setCreateTime(new Date());
|
||||
|
||||
// 插入日志记录
|
||||
deviceLogMapper.insert(deviceLog);
|
||||
} catch (Exception e) {
|
||||
log.error("记录设备操作日志失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AppDeviceHBY100JDetailVo getInfo(Long id) {
|
||||
Device device = deviceMapper.selectById(id);
|
||||
if (device == null) {
|
||||
throw new RuntimeException("请先将设备入库!!!");
|
||||
}
|
||||
|
||||
AppDeviceHBY100JDetailVo vo = new AppDeviceHBY100JDetailVo();
|
||||
vo.setDeviceId(device.getId());
|
||||
vo.setDeviceName(device.getDeviceName());
|
||||
vo.setDevicePic(device.getDevicePic());
|
||||
vo.setDeviceImei(device.getDeviceImei());
|
||||
vo.setDeviceMac(device.getDeviceMac());
|
||||
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
|
||||
if (deviceType != null) {
|
||||
vo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode()));
|
||||
vo.setTypeName(deviceType.getTypeName());
|
||||
}
|
||||
vo.setBluetoothName(device.getBluetoothName());
|
||||
|
||||
// 设备在线状态
|
||||
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
|
||||
// 设备在线状态
|
||||
if ("1".equals(onlineStatus)) {
|
||||
vo.setOnlineStatus(1);
|
||||
} else if ("2".equals(onlineStatus)) {
|
||||
vo.setOnlineStatus(2);
|
||||
} else {
|
||||
vo.setOnlineStatus(0);
|
||||
}
|
||||
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX);
|
||||
// 获取电量
|
||||
if (StringUtils.isNotBlank(deviceStatus)) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
|
||||
vo.setBatteryPercentage(jsonObject.getString("batteryPercentage"));
|
||||
vo.setChargeState(jsonObject.getString("chargeState"));
|
||||
} else {
|
||||
vo.setBatteryPercentage("0");
|
||||
}
|
||||
|
||||
String lightModeStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX);
|
||||
|
||||
|
||||
String lightBrightnessStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(lightBrightnessStatus)) {
|
||||
vo.setLightBrightness(lightBrightnessStatus);
|
||||
}
|
||||
|
||||
// 获取经度纬度
|
||||
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
|
||||
String locationInfo = RedisUtils.getCacheObject(locationKey);
|
||||
// if (StringUtils.isNotBlank(locationInfo)) {
|
||||
// JSONObject jsonObject = JSONObject.parseObject(locationInfo);
|
||||
// vo.setLongitude(jsonObject.get("longitude").toString());
|
||||
// vo.setLatitude(jsonObject.get("latitude").toString());
|
||||
// vo.setAddress((String) jsonObject.get("address"));
|
||||
// }
|
||||
|
||||
String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(alarmStatus)) {
|
||||
vo.setVoiceStrobeAlarm(alarmStatus);
|
||||
}
|
||||
|
||||
String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(lightBrightness)) {
|
||||
vo.setLightBrightness(lightBrightness);
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
|
||||
private boolean getDeviceStatus(String deviceImei) {
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX;
|
||||
return RedisUtils.getCacheObject(deviceOnlineStatusRedisKey) == null;
|
||||
}
|
||||
|
||||
|
||||
public void forceAlarmActivation(AppDeviceHBY100JController.HBY100JForceAlarmActivationDto bo) {
|
||||
List<Long> deviceIds = bo.getDeviceIds();
|
||||
if (deviceIds == null || deviceIds.isEmpty()) {
|
||||
throw new ServiceException("请选择设备");
|
||||
}
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
bo.getDeviceIds().forEach(deviceId -> {
|
||||
Device deviceObj = deviceMapper.selectById(deviceId);
|
||||
// if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||
// throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||
// }
|
||||
|
||||
// 语音播报
|
||||
if(bo.getMode() == 9){
|
||||
FuncType6VoicePlayRequest request = new FuncType6VoicePlayRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("6");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType6VoicePlayRequest.Data data = new FuncType6VoicePlayRequest.Data();
|
||||
data.setVoiceBroadcast(bo.getVoiceStrobeAlarm());
|
||||
request.setData(data);
|
||||
log.info("HBY100J更新语音,参数:{}", request);
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
}else{
|
||||
FuncType12ForceAudioRequest request = new FuncType12ForceAudioRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("12");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType12ForceAudioRequest.Data data = new FuncType12ForceAudioRequest.Data();
|
||||
data.setVoiceStrobeAlarm(bo.getVoiceStrobeAlarm());
|
||||
data.setMode(bo.getMode());
|
||||
request.setData(data);
|
||||
log.info("HBY100J更新语音,参数:{}", request);
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
}
|
||||
|
||||
|
||||
// recordDeviceLog(deviceId, deviceObj.getDeviceName(), "强制报警激活", "强制报警激活", loginUser.getUserId());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void updateVoice(AppDeviceHBY100JController.HBY100JUpdateVoiceDto dto) {
|
||||
AppBusinessFileVo appBusinessFileVo = appBusinessFileMapper.selectVoById(dto.getId());
|
||||
if(appBusinessFileVo == null){
|
||||
throw new ServiceException("文件不存在");
|
||||
}
|
||||
Device deviceObj = deviceMapper.selectById(appBusinessFileVo.getBusinessId());
|
||||
// if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||
// throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||
// }
|
||||
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
SysOssVo sysOssVo = sysOssMapper.selectVoById(appBusinessFileVo.getFileId());
|
||||
FuncType5UpdateVoiceRequest request = new FuncType5UpdateVoiceRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("5");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType5UpdateVoiceRequest.Data data = new FuncType5UpdateVoiceRequest.Data();
|
||||
data.setVoiceResource(sysOssVo.getUrl());
|
||||
data.setVoiceType(0);
|
||||
request.setData(data);
|
||||
log.info("HBY100J更新语音,参数:{}", request);
|
||||
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
|
||||
UpdateWrapper<AppBusinessFile> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("business_id", appBusinessFileVo.getBusinessId());
|
||||
updateWrapper.set("use_status", 0);
|
||||
appBusinessFileMapper.update(updateWrapper);
|
||||
|
||||
UpdateWrapper<AppBusinessFile> updateWrapper2 = new UpdateWrapper<>();
|
||||
updateWrapper2.eq("id", appBusinessFileVo.getId());
|
||||
updateWrapper2.set("use_status", 1);
|
||||
appBusinessFileMapper.update(updateWrapper2);
|
||||
}
|
||||
|
||||
private String buildMqttTopic(String deviceImei) {
|
||||
String tenantId = LoginHelper.getTenantId();
|
||||
return MqttConstants.GLOBAL_PUB_KEY2 +tenantId + "/" + DEVICE_TYPE + deviceImei;
|
||||
}
|
||||
|
||||
public void strobeMode(AppDeviceHBY100JController.HBY100JStrobeModeDto params) {
|
||||
log.info("HBY100J爆闪模式开启/关闭,请求参数:{}", params);
|
||||
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||
// if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||
// throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||
// }
|
||||
FuncType10StrobeModeRequest request = new FuncType10StrobeModeRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("10");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType10StrobeModeRequest.Data data = new FuncType10StrobeModeRequest.Data();
|
||||
data.setMode(params.getMode());
|
||||
data.setEnable(params.getEnable());
|
||||
request.setData(data);
|
||||
log.info("HBY100J爆闪模式开启/关闭,下发设备参数:{}", request);
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
}
|
||||
|
||||
public void lightAdjustment(AppDeviceHBY100JController.HBY100JLightAdjustmentDto params) {
|
||||
log.info("HBY100J灯光调节,请求参数:{}", params);
|
||||
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||
// if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||
// throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||
// }
|
||||
FuncType13BrightnessRequest request = new FuncType13BrightnessRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("13");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType13BrightnessRequest.Data data = new FuncType13BrightnessRequest.Data();
|
||||
data.setRed(params.getBrightness());
|
||||
data.setBlue(params.getBrightness());
|
||||
data.setYellow(params.getBrightness());
|
||||
request.setData(data);
|
||||
log.info("HBY100J灯光调节,下发设备参数:{}", request);
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
}
|
||||
|
||||
public void strobeFrequency(AppDeviceHBY100JController.HBY100JStrobeFrequencyDto params) {
|
||||
log.info("HBY100J爆闪频率,请求参数:{}", params);
|
||||
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||
// if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||
// throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||
// }
|
||||
FuncType11FrequencyRequest request = new FuncType11FrequencyRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("11");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType11FrequencyRequest.Data data = new FuncType11FrequencyRequest.Data();
|
||||
data.setFrequency(params.getFrequency());
|
||||
request.setData(data);
|
||||
log.info("HBY100J灯光调节,下发设备参数:{}", request);
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
}
|
||||
|
||||
public void updateVolume(AppDeviceHBY100JController.HBY100JUpdateVolumeDto params) {
|
||||
log.info("HBY100J更新音量,请求参数:{}", params);
|
||||
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||
// if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||
// throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||
// }
|
||||
FuncType9UpdateVolumeRequest request = new FuncType9UpdateVolumeRequest();
|
||||
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||
request.setImei(deviceObj.getDeviceImei());
|
||||
request.setFuncType("9");
|
||||
request.setTimestamp(System.currentTimeMillis());
|
||||
FuncType9UpdateVolumeRequest.Data data = new FuncType9UpdateVolumeRequest.Data();
|
||||
data.setVolume(params.getVolume());
|
||||
request.setData(data);
|
||||
log.info("HBY100J更新音量,下发设备参数:{}", JSON.toJSONString(request));
|
||||
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
package com.fuyuanshen.web.service.device;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
@ -15,17 +15,20 @@ import com.fuyuanshen.app.domain.AppPersonnelInfo;
|
||||
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
||||
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
|
||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper;
|
||||
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
||||
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
||||
import com.fuyuanshen.common.core.exception.BadRequestException;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.core.utils.ObjectUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
@ -37,6 +40,7 @@ import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
|
||||
import com.fuyuanshen.equipment.domain.form.DeviceForm;
|
||||
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
|
||||
import com.fuyuanshen.equipment.enums.DeviceActiveStatusEnum;
|
||||
import com.fuyuanshen.equipment.enums.LightModeEnum;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeGrantsMapper;
|
||||
@ -47,6 +51,8 @@ import com.fuyuanshen.global.mqtt.base.MqttXinghanJson;
|
||||
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.domain.vo.SysRoleVo;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto;
|
||||
import com.fuyuanshen.web.domain.vo.DeviceXinghanDetailVo;
|
||||
@ -58,12 +64,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
|
||||
@ -84,8 +93,6 @@ public class DeviceXinghanBizService {
|
||||
private final IDeviceAlarmService deviceAlarmService;
|
||||
private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;
|
||||
private final DeviceAssignmentsService deviceAssignmentsService;
|
||||
private final IAppBusinessFileService appBusinessFileService;
|
||||
private final IAppOperationVideoService appOperationVideoService;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
private final AliyunVoiceUtil voiceUtil;
|
||||
@ -714,31 +721,20 @@ public class DeviceXinghanBizService {
|
||||
return deviceTypeMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验唯一性约束
|
||||
*/
|
||||
private void validateDeviceUnique(DeviceForm form) {
|
||||
if (form.getDeviceMac() != null && form.getBluetoothName() == null) {
|
||||
// @Log("新增设备")
|
||||
public void addDevice(DeviceForm deviceForm) {
|
||||
if (deviceForm.getDeviceMac() != null && deviceForm.getBluetoothName() == null) {
|
||||
throw new BadRequestException("请填写蓝牙名称!!!");
|
||||
}
|
||||
|
||||
// 使用 QueryWrapper 替代 lambdaQuery()
|
||||
Long macCount = deviceMapper.selectCount(new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getDeviceMac, form.getDeviceMac()));
|
||||
if (macCount > 0) {
|
||||
Device device1 = deviceMapper.selectOne(new QueryWrapper<Device>().eq("device_mac", deviceForm.getDeviceMac()));
|
||||
if (device1 != null) {
|
||||
throw new BadRequestException("设备MAC已存在!!!");
|
||||
}
|
||||
|
||||
Long imeiCount = deviceMapper.selectCount(new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getDeviceImei, form.getDeviceImei()));
|
||||
if (imeiCount > 0) {
|
||||
Device device2 = deviceMapper.selectOne(new QueryWrapper<Device>().eq("device_imei", deviceForm.getDeviceImei()));
|
||||
if (device2 != null) {
|
||||
throw new BadRequestException("设备IMEI已存在!!!");
|
||||
}
|
||||
}
|
||||
|
||||
// @Log("新增设备")
|
||||
public void addDevice(DeviceForm deviceForm) {
|
||||
validateDeviceUnique(deviceForm);
|
||||
|
||||
DeviceTypeQueryCriteria queryCriteria = new DeviceTypeQueryCriteria();
|
||||
queryCriteria.setDeviceTypeId(deviceForm.getDeviceType());
|
||||
@ -772,14 +768,6 @@ public class DeviceXinghanBizService {
|
||||
device.setBindingStatus(0);
|
||||
deviceMapper.insert(device);
|
||||
|
||||
Long deviceId = device.getDeviceId();
|
||||
|
||||
// 查询设备类型的文件列表
|
||||
// 4. 核心优化:同步设备类型的文件列表 (一行代码)
|
||||
appBusinessFileService.cloneFiles(deviceTypes.getId(), device.getId());
|
||||
//同步设备类型的视频列表
|
||||
appOperationVideoService.cloneFiles(deviceTypes.getId(), device.getId());
|
||||
|
||||
// 新增设备类型记录
|
||||
DeviceAssignments assignments = new DeviceAssignments();
|
||||
assignments.setDeviceId(device.getId());
|
||||
|
||||
@ -279,11 +279,13 @@ justauth:
|
||||
# MQTT配置
|
||||
mqtt:
|
||||
username: admin
|
||||
password: fys123456
|
||||
url: tcp://47.107.152.87:1883
|
||||
password: #YtvpSfCNG
|
||||
url: tcp://47.120.79.150:2883
|
||||
subClientId: fys_subClient
|
||||
subTopic: A/#,status/tenantCode/#,report/tenantCode/#
|
||||
pubTopic: B/#,command/tenantCode/#
|
||||
subTopic: A/#
|
||||
pubTopic: B/#
|
||||
subTopic2: command/894078/#
|
||||
pubTopic2: status/894078/#
|
||||
pubClientId: fys_pubClient
|
||||
|
||||
|
||||
|
||||
@ -283,14 +283,16 @@ mqtt:
|
||||
password: #YtvpSfCNG
|
||||
url: tcp://47.120.79.150:3883
|
||||
subClientId: fys_subClient
|
||||
subTopic: A/#,status/tenantCode/#,report/tenantCode/#
|
||||
pubTopic: B/#,command/tenantCode/#
|
||||
subTopic: A/#
|
||||
pubTopic: B/#
|
||||
subTopic2: status/894078/#
|
||||
pubTopic2: command/894078/#
|
||||
pubClientId: fys_pubClient
|
||||
|
||||
# TTS语音交互配置
|
||||
alibaba:
|
||||
tts:
|
||||
appKey: KTwSUKMrf2olFfjC
|
||||
akId: LTAI5t6RsfCvQh57qojzbEoe
|
||||
akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R
|
||||
appKey: lbGuq5K5bEH4uxmT
|
||||
akId: LTAI5t66moCkhNC32TDJ5ReP
|
||||
akSecret: 2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH
|
||||
|
||||
|
||||
@ -39,8 +39,8 @@ public class EncryptUtilsTest {
|
||||
loginBody.setClientId("e5cd7e4891bf95d1d19206ce24a7b32e");
|
||||
loginBody.setGrantType("password");
|
||||
loginBody.setTenantId("894078");
|
||||
loginBody.setCode("15");
|
||||
loginBody.setUuid("28ecf3d396ce4e6db8eb414992235fad");
|
||||
loginBody.setCode("6");
|
||||
loginBody.setUuid("399d45194f3d4c7e9cbfb3294b198a9b");
|
||||
// loginBody.setUsername("admin");
|
||||
// loginBody.setPassword("admin123");
|
||||
loginBody.setUsername("dyf");
|
||||
|
||||
@ -17,9 +17,9 @@ import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
|
||||
@ -17,9 +17,9 @@ import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.fuyuanshen.equipment.domain;
|
||||
package com.fuyuanshen.app.domain;
|
||||
|
||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
@ -47,5 +47,18 @@ public class AppBusinessFile extends TenantEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 文件时长
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 重命名
|
||||
*/
|
||||
private String reName;
|
||||
|
||||
/**
|
||||
* 是否使用语音播报(0-否,1-是)
|
||||
*/
|
||||
private Integer useStatus;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.fuyuanshen.equipment.domain;
|
||||
package com.fuyuanshen.app.domain;
|
||||
|
||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
@ -1,6 +1,6 @@
|
||||
package com.fuyuanshen.equipment.domain.bo;
|
||||
package com.fuyuanshen.app.domain.bo;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
@ -38,7 +38,7 @@ public class AppBusinessFileBo extends BaseEntity {
|
||||
private Long businessId;
|
||||
|
||||
/**
|
||||
* 文件类型(1:操作说明,2:产品参数)
|
||||
* 文件类型(1:操作说明,2:产品参数,3:语音管理)
|
||||
*/
|
||||
private Long fileType;
|
||||
|
||||
@ -49,4 +49,11 @@ public class AppBusinessFileBo extends BaseEntity {
|
||||
|
||||
|
||||
private List<Long> ids;
|
||||
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 是否使用语音播报(0-否,1-是)
|
||||
*/
|
||||
private Integer useStatus;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package com.fuyuanshen.equipment.domain.bo;
|
||||
package com.fuyuanshen.app.domain.bo;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
@ -1,13 +1,17 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
package com.fuyuanshen.app.domain.vo;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
|
||||
import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -0,0 +1,104 @@
|
||||
package com.fuyuanshen.app.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class AppDeviceHBY100JDetailVo implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@ExcelProperty(value = "设备ID")
|
||||
private Long deviceId;
|
||||
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备IMEI
|
||||
*/
|
||||
private String deviceImei;
|
||||
|
||||
/**
|
||||
* 设备MAC
|
||||
*/
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private Integer communicationMode;
|
||||
|
||||
/**
|
||||
* 设备图片
|
||||
*/
|
||||
private String devicePic;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 蓝牙名称
|
||||
*/
|
||||
private String bluetoothName;
|
||||
|
||||
//电量百分比
|
||||
private String batteryPercentage;
|
||||
|
||||
//充电状态(0没有充电,1正在充电,2为已充满)
|
||||
private String chargeState;
|
||||
|
||||
/**
|
||||
* 在线状态(0离线,1在线)
|
||||
*/
|
||||
private Integer onlineStatus;
|
||||
|
||||
// 经度
|
||||
private String longitude;
|
||||
|
||||
// 纬度
|
||||
private String latitude;
|
||||
|
||||
// 逆解析地址
|
||||
private String address;
|
||||
|
||||
// 亮度
|
||||
private String lightBrightness;
|
||||
|
||||
// 音量
|
||||
private Integer volume;
|
||||
|
||||
|
||||
/**
|
||||
* 语音资源URL(MP3等音频文件地址)
|
||||
*/
|
||||
private String voiceResource;
|
||||
|
||||
// 报警模式 0公安,1 消防,2应急,3交警,4 市政,5 铁路,6 医疗,7 部队,8 水利,9 语音
|
||||
private String alarmMode;
|
||||
|
||||
// 强制报警开关: 0 关闭, 1开启
|
||||
private String voiceStrobeAlarm;
|
||||
|
||||
/**
|
||||
* 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||
*/
|
||||
private Integer strobeMode;
|
||||
|
||||
/**
|
||||
* 爆闪频率
|
||||
*/
|
||||
private Integer strobeFrequency;
|
||||
|
||||
}
|
||||
@ -51,6 +51,11 @@ public class AppDeviceShareVo implements Serializable {
|
||||
@ExcelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备mac地址
|
||||
*/
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
package com.fuyuanshen.app.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@ -27,4 +27,16 @@ public class AppFileVo {
|
||||
* 文件url
|
||||
*/
|
||||
private String fileUrl;
|
||||
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 扩展文件名称
|
||||
*/
|
||||
private String fileNameExt;
|
||||
|
||||
/***
|
||||
* 是否使用语音播报(0-否,1-是)
|
||||
*/
|
||||
private Integer useStatus;
|
||||
}
|
||||
@ -1,13 +1,17 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
package com.fuyuanshen.app.domain.vo;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
|
||||
import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -1,10 +1,10 @@
|
||||
package com.fuyuanshen.equipment.mapper;
|
||||
package com.fuyuanshen.app.mapper;
|
||||
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package com.fuyuanshen.equipment.mapper;
|
||||
package com.fuyuanshen.app.mapper;
|
||||
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
@ -1,11 +1,11 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -57,9 +57,7 @@ public interface IAppBusinessFileService {
|
||||
* @param bo 批量新增app业务文件
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertBatch(Collection<AppBusinessFile> bo, Boolean isBatch);
|
||||
|
||||
void cloneFiles(Long sourceId, Long targetId);
|
||||
Boolean insertBatch(Collection<AppBusinessFile> bo,Boolean isBatch);
|
||||
|
||||
/**
|
||||
* 修改app业务文件
|
||||
@ -80,4 +78,5 @@ public interface IAppBusinessFileService {
|
||||
|
||||
|
||||
List<AppFileVo> queryAppFileList(AppBusinessFileBo bo);
|
||||
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -58,8 +59,6 @@ public interface IAppOperationVideoService {
|
||||
*/
|
||||
Boolean insertBatch(Collection<AppOperationVideo> bo);
|
||||
|
||||
void cloneFiles(Long sourceId, Long targetId);
|
||||
|
||||
/**
|
||||
* 修改操作视频
|
||||
*
|
||||
@ -1,29 +1,27 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
package com.fuyuanshen.app.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.equipment.mapper.AppBusinessFileMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.mapper.AppBusinessFileMapper;
|
||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* app业务文件Service业务层处理
|
||||
@ -119,38 +117,6 @@ public class AppBusinessFileServiceImpl implements IAppBusinessFileService {
|
||||
return baseMapper.insertBatch(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆业务文件列表到新业务ID
|
||||
* @param sourceId 源业务ID(如设备类型ID)
|
||||
* @param targetId 目标业务ID(如新设备ID)
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void cloneFiles(Long sourceId, Long targetId) {
|
||||
// 1. 使用 Wrappers 替代 this.lambdaQuery()
|
||||
List<AppBusinessFile> sourceFiles = baseMapper.selectList(
|
||||
Wrappers.<AppBusinessFile>lambdaQuery().eq(AppBusinessFile::getBusinessId, sourceId)
|
||||
);
|
||||
|
||||
if (CollUtil.isEmpty(sourceFiles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 批量转换并重置ID
|
||||
List<AppBusinessFile> newFiles = sourceFiles.stream().map(file -> {
|
||||
AppBusinessFile entity = new AppBusinessFile();
|
||||
// 建议使用你代码中已有的 MapstructUtils 或 BeanUtil
|
||||
BeanUtil.copyProperties(file, entity);
|
||||
entity.setId(null); // 确保主键自增
|
||||
entity.setBusinessId(targetId); // 绑定到新设备ID
|
||||
return entity;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 3. 使用你已有的 insertBatch 替代 saveBatch
|
||||
// 注意:这里第二个参数传 false,因为是新设备,不需要执行你 insertBatch 里的删除逻辑
|
||||
this.insertBatch(newFiles, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改app业务文件
|
||||
*
|
||||
@ -1,8 +1,7 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
package com.fuyuanshen.app.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
@ -10,20 +9,18 @@ import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.equipment.mapper.AppOperationVideoMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.mapper.AppOperationVideoMapper;
|
||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 操作视频Service业务层处理
|
||||
@ -128,37 +125,6 @@ public class AppOperationVideoServiceImpl implements IAppOperationVideoService {
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆业务文件列表到新业务ID
|
||||
* @param sourceId 源业务ID(如设备类型ID)
|
||||
* @param targetId 目标业务ID(如新设备ID)
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void cloneFiles(Long sourceId, Long targetId) {
|
||||
// 1. 使用 Wrappers 替代 this.lambdaQuery()
|
||||
List<AppOperationVideo> sourceFiles = baseMapper.selectList(
|
||||
Wrappers.<AppOperationVideo>lambdaQuery().eq(AppOperationVideo::getDeviceId, sourceId)
|
||||
);
|
||||
|
||||
if (CollUtil.isEmpty(sourceFiles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 批量转换并重置ID
|
||||
List<AppOperationVideo> newFiles = sourceFiles.stream().map(file -> {
|
||||
AppOperationVideo entity = new AppOperationVideo();
|
||||
// 建议使用你代码中已有的 MapstructUtils 或 BeanUtil
|
||||
BeanUtil.copyProperties(file, entity);
|
||||
entity.setId(null); // 确保主键自增
|
||||
entity.setDeviceId(targetId); // 绑定到新设备ID
|
||||
return entity;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 3. 使用你已有的 insertBatch 替代 saveBatch
|
||||
this.insertBatch(newFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
@ -2,10 +2,17 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.fuyuanshen.equipment.mapper.AppBusinessFileMapper">
|
||||
<mapper namespace="com.fuyuanshen.app.mapper.AppBusinessFileMapper">
|
||||
|
||||
<select id="queryAppFileList" resultType="com.fuyuanshen.equipment.domain.vo.AppFileVo">
|
||||
select a.id,a.business_id,a.file_id,a.file_type,b.file_name,b.url fileUrl from app_business_file a left join sys_oss b on a.file_id = b.oss_id
|
||||
<select id="queryAppFileList" resultType="com.fuyuanshen.app.domain.vo.AppFileVo">
|
||||
select a.id,a.business_id,a.file_id,a.file_type,b.file_name,b.url fileUrl,a.duration,
|
||||
CASE
|
||||
WHEN a.re_name IS NULL THEN
|
||||
SUBSTRING_INDEX(COALESCE(a.re_name, b.original_name), '.', 1)
|
||||
ELSE
|
||||
a.re_name
|
||||
END AS fileNameExt,a.use_status
|
||||
from app_business_file a left join sys_oss b on a.file_id = b.oss_id
|
||||
where 1=1
|
||||
<if test="businessId != null">
|
||||
and a.business_id = #{businessId}
|
||||
@ -2,6 +2,6 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.fuyuanshen.equipment.mapper.AppOperationVideoMapper">
|
||||
<mapper namespace="com.fuyuanshen.app.mapper.AppOperationVideoMapper">
|
||||
|
||||
</mapper>
|
||||
@ -16,10 +16,8 @@ import com.fuyuanshen.customer.domain.vo.ConsumerVo;
|
||||
import com.fuyuanshen.customer.mapper.CustomerMapper;
|
||||
import com.fuyuanshen.customer.service.CustomerService;
|
||||
import com.fuyuanshen.system.domain.SysUserRole;
|
||||
import com.fuyuanshen.system.domain.bo.SysUserBo;
|
||||
import com.fuyuanshen.system.mapper.SysRoleMapper;
|
||||
import com.fuyuanshen.system.mapper.SysUserRoleMapper;
|
||||
import com.fuyuanshen.system.service.ISysUserService;
|
||||
import com.fuyuanshen.system.service.impl.SysUserServiceImpl;
|
||||
import io.undertow.util.BadRequestException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@ -18,6 +18,12 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org</groupId>
|
||||
<artifactId>jaudiotagger</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- <dependency> -->
|
||||
<!-- <groupId>com.fuyuanshen</groupId> -->
|
||||
<!-- <artifactId>fys-app</artifactId> -->
|
||||
|
||||
@ -317,7 +317,8 @@ public class DeviceController extends BaseController {
|
||||
// 定义必需的表头
|
||||
Set<String> requiredHeaders = new HashSet<>(Arrays.asList(
|
||||
"设备名称", "设备类型名称", "设备图片", "设备MAC", "蓝牙名称", "设备IMEI",
|
||||
"备注"
|
||||
"备注", "是否支持蓝牙", "定位方式", "通讯方式",
|
||||
"型号字典用于APP页面跳转", "型号字典用于PC页面跳转"
|
||||
));
|
||||
|
||||
// 检查必需的表头是否都存在
|
||||
|
||||
@ -10,32 +10,36 @@ import lombok.EqualsAndHashCode;
|
||||
/**
|
||||
* 设备维修图片对象 device_repair_images
|
||||
*
|
||||
*
|
||||
* @date 2025-09-02
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("device_repair_images")
|
||||
public class DeviceRepairImages extends TenantEntity {
|
||||
|
||||
/**
|
||||
* 维修图片ID
|
||||
*/
|
||||
@TableId(value = "image_id", type = IdType.AUTO)
|
||||
@TableField(insertStrategy = FieldStrategy.NEVER)
|
||||
private Long imageId;
|
||||
|
||||
/**
|
||||
* 维修记录ID
|
||||
*/
|
||||
@Schema(title = "维修记录ID")
|
||||
private Long recordId;
|
||||
|
||||
/**
|
||||
* 图片类型(维修前/维修后)
|
||||
*/
|
||||
@Schema(title = "图片类型(维修前/维修后)")
|
||||
private RepairImageType imageType;
|
||||
|
||||
/**
|
||||
* 图片存储路径
|
||||
*/
|
||||
@Schema(title = "图片存储路径")
|
||||
private String imageUrl;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
package com.fuyuanshen.equipment.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 绑定设备参数
|
||||
*/
|
||||
@Data
|
||||
public class Hby100jForceAlarmBo {
|
||||
|
||||
private Long deviceId;
|
||||
|
||||
|
||||
}
|
||||
@ -30,7 +30,10 @@ import com.fuyuanshen.equipment.enums.BindingStatusEnum;
|
||||
import com.fuyuanshen.equipment.enums.CommunicationModeEnum;
|
||||
import com.fuyuanshen.equipment.enums.DeviceActiveStatusEnum;
|
||||
import com.fuyuanshen.equipment.mapper.*;
|
||||
import com.fuyuanshen.equipment.service.*;
|
||||
import com.fuyuanshen.equipment.service.DeviceAssignmentsService;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.equipment.service.DeviceTypeGrantsService;
|
||||
import com.fuyuanshen.equipment.service.IDeviceGeoFenceService;
|
||||
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.domain.vo.SysRoleVo;
|
||||
@ -74,8 +77,6 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
|
||||
private final DeviceFenceAccessRecordMapper deviceFenceAccessRecordMapper;
|
||||
private final FileHashUtil fileHashUtil;
|
||||
private final IAppBusinessFileService appBusinessFileService;
|
||||
private final IAppOperationVideoService appOperationVideoService;
|
||||
|
||||
|
||||
/**
|
||||
@ -333,12 +334,6 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
device.setBindingStatus(0);
|
||||
deviceMapper.insert(device);
|
||||
|
||||
// 查询设备类型的文件列表
|
||||
// 4. 核心优化:同步设备类型的文件列表 (一行代码)
|
||||
appBusinessFileService.cloneFiles(deviceType.getId(), device.getId());
|
||||
//同步设备类型的视频列表
|
||||
appOperationVideoService.cloneFiles(deviceType.getId(), device.getId());
|
||||
|
||||
// 新增设备类型记录
|
||||
DeviceAssignments assignments = new DeviceAssignments();
|
||||
assignments.setDeviceId(device.getId());
|
||||
|
||||
@ -244,10 +244,10 @@ public class DeviceTypeServiceImpl extends ServiceImpl<DeviceTypeMapper, DeviceT
|
||||
throw new RuntimeException("设备类型不存在");
|
||||
}
|
||||
|
||||
if (!deviceType.getTypeName().equals(resources.getTypeName())) {
|
||||
if (!deviceType.getTypeName().equals(resources.getTypeName()) || !deviceType.getAppModelDictionary().equals(resources.getAppModelDictionary())) {
|
||||
int count = deviceMapper.countByDeviceTypeId(deviceType.getId());
|
||||
if (count > 0) {
|
||||
throw new RuntimeException("该设备类型下已有设备,无法修改设备类型名称!!!");
|
||||
throw new RuntimeException("该设备类型下已有设备,无法修改设备类型名称和路由跳转!!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -113,6 +113,21 @@ public class AlibabaTTSUtil {
|
||||
DEFAULT_VOLUME, DEFAULT_SPEECH_RATE, DEFAULT_PITCH_RATE);
|
||||
}
|
||||
|
||||
public byte[] synthesizeTextToMp3(String text){
|
||||
try {
|
||||
// 获取访问令牌
|
||||
String token = getValidAccessToken();
|
||||
// 使用HTTP方式调用
|
||||
HttpTtsClient httpClient = new HttpTtsClient(appkey,token);
|
||||
|
||||
return httpClient.synthesizeTextToMp3(text);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成语音文件 - 完整版(支持所有参数调节)
|
||||
*
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
package com.fuyuanshen.equipment.utils;
|
||||
|
||||
import com.alibaba.nls.client.AccessToken;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import static cn.dev33.satoken.SaManager.log;
|
||||
|
||||
public class HttpTtsClient {
|
||||
|
||||
private String appKey;
|
||||
private String token;
|
||||
/**
|
||||
* 阿里云TTS服务基础URL
|
||||
*/
|
||||
private static final String BASE_URL = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
|
||||
|
||||
public HttpTtsClient(String appKey, String token) {
|
||||
this.appKey = appKey;
|
||||
this.token = token;
|
||||
}
|
||||
/**
|
||||
* 使用HTTP POST方式调用阿里云TTS服务生成MP3格式语音
|
||||
*/
|
||||
public byte[] synthesizeTextToMp3(String text) throws IOException {
|
||||
String endpoint = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
|
||||
|
||||
// 构建请求体
|
||||
// String requestBody = String.format(
|
||||
// "{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}",
|
||||
// appKey,
|
||||
// text.replace("\"", "\\\"")
|
||||
// );
|
||||
String requestBody = " {\n" +
|
||||
" \"appkey\":\""+appKey+"\",\n" +
|
||||
" \"text\":\""+text+"\",\n" +
|
||||
" \"token\":\""+token+"\",\n" +
|
||||
" \"format\":\"mp3\"\n" +
|
||||
" }";
|
||||
|
||||
URL url = new URL(endpoint);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 设置请求方法和头部
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
// conn.setRequestProperty("Authorization", buildAuthorization());
|
||||
conn.setRequestProperty("Content-Length", String.valueOf(requestBody.getBytes().length));
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// 发送请求体
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(requestBody.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
// 读取音频数据
|
||||
try (InputStream is = conn.getInputStream()) {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int nRead;
|
||||
byte[] data = new byte[1024];
|
||||
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
} else {
|
||||
throw new IOException("HTTP请求失败,状态码: " + responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存MP3到文件
|
||||
*/
|
||||
public String saveMp3ToFile(String text, String outputPath) throws IOException {
|
||||
byte[] mp3Data = synthesizeTextToMp3(text);
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
|
||||
fos.write(mp3Data);
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.fuyuanshen.equipment.utils;
|
||||
|
||||
import org.jaudiotagger.audio.AudioFileIO;
|
||||
import org.jaudiotagger.audio.mp3.MP3File;
|
||||
import java.io.File;
|
||||
|
||||
public class Mp3Duration {
|
||||
|
||||
/**
|
||||
* 获取MP3文件的播放时长(秒)
|
||||
*
|
||||
* @param filePath MP3文件路径
|
||||
* @return 播放时长(秒)
|
||||
*/
|
||||
public static int getMp3Duration(String filePath) {
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
MP3File mp3File = (MP3File) AudioFileIO.read(file);
|
||||
return mp3File.getMP3AudioHeader().getTrackLength();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1; // 错误时返回-1
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String filePath = "D:\\http_output.mp3"; // 替换为实际路径
|
||||
int duration = getMp3Duration(filePath);
|
||||
if (duration != -1) {
|
||||
System.out.println("MP3时长: " + duration + " 秒");
|
||||
} else {
|
||||
System.out.println("无法获取MP3时长");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user