feat(device): 新增阿里云语音通知功能并扩展设备查询接口
- 集成阿里云语音服务,实现TTS语音拨号功能 - 添加异步报警拨号机制,支持SOS紧急呼叫 - 新增按设备名称查询设备的接口和SQL - 扩展设备类型统计和批量查询功能 - 添加租户ID字段支持多租户设备管理 - 配置阿里云语音API依赖和客户端单例模式
This commit is contained in:
@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HBY670设备控制类
|
||||
@ -144,4 +145,26 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/GetDeviceByName")
|
||||
@Operation(summary = "通过蓝牙名/设备名称查询设备")
|
||||
public R<Object> GetDeviceByName(@RequestBody DeviceForm deviceForm) {
|
||||
Object device = appDeviceService.GetDeviceByName(deviceForm);
|
||||
return R.ok(device);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "/getEquipCountByType")
|
||||
@Operation(summary = "查询某个类型下的设备总数量")
|
||||
public R<Object> getEquipCountByType(@RequestBody DeviceForm deviceForm) {
|
||||
Object device = appDeviceService.getEquipCountByType(deviceForm);
|
||||
return R.ok(device);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/getEquipAllByType")
|
||||
@Operation(summary = "查询某个类型下的设备")
|
||||
public R<List<Map<String,Object>>> getEquipAllByType(@RequestBody DeviceForm deviceForm){
|
||||
List<Map<String,Object>> list=appDeviceService.getEquipAllByType(deviceForm);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -57,9 +57,11 @@ import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto;
|
||||
import com.fuyuanshen.web.domain.vo.DeviceXinghanDetailVo;
|
||||
import com.fuyuanshen.web.enums.AlarmTypeEnum;
|
||||
import com.fuyuanshen.web.util.AliyunVoiceUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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;
|
||||
@ -93,6 +95,7 @@ public class DeviceXinghanBizService {
|
||||
private final DeviceAssignmentsService deviceAssignmentsService;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
private final AliyunVoiceUtil voiceUtil;
|
||||
|
||||
/**
|
||||
* 所有档位的描述表
|
||||
@ -135,7 +138,6 @@ public class DeviceXinghanBizService {
|
||||
public void upSOSGradeSettings(DeviceXinghanInstructDto dto) {
|
||||
if(dto.getIsBluetooth()){
|
||||
long deviceId = dto.getDeviceId();
|
||||
|
||||
// 1. 使用Optional简化空值检查,使代码更简洁
|
||||
Device device = Optional.ofNullable(deviceMapper.selectById(deviceId))
|
||||
.orElseThrow(() -> new ServiceException("设备不存在"));
|
||||
@ -147,6 +149,24 @@ public class DeviceXinghanBizService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发异步报警
|
||||
* Spring 会自动调用 AsyncConfig.getAsyncExecutor() 来执行此方法
|
||||
*/
|
||||
@Async
|
||||
public void executeSosCall(String phone) {
|
||||
log.info("[SOS业务] 准备发起语音拨号 -> 目标: {}", phone);
|
||||
Map<String, String> params = Map.of("device", "670");
|
||||
String callId = voiceUtil.sendTtsSync(phone, "TTS_328730104", params);
|
||||
|
||||
if (callId != null) {
|
||||
log.info("[SOS业务] 拨号指令下发成功, callId: {}", callId);
|
||||
// 这里可以记录拨打日志到数据库
|
||||
} else {
|
||||
log.error("[SOS业务] 拨号指令下发失败,请检查配置或余额");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置强制报警
|
||||
*/
|
||||
@ -768,4 +788,23 @@ public class DeviceXinghanBizService {
|
||||
return uuidStr.replaceAll("-", "");
|
||||
}
|
||||
|
||||
public Map<String, Object> GetDeviceByName(DeviceForm deviceForm){
|
||||
List<Map<String, Object>> list= deviceMapper.GetDeviceByName(deviceForm);
|
||||
Map<String, Object> device=null;
|
||||
if(list!=null && list.size()>0){
|
||||
device=list.get(0);
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
public int getEquipCountByType(DeviceForm form){
|
||||
var res=deviceMapper.getEquipCountByType(form);
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<Map<String,Object>> getEquipAllByType(DeviceForm deviceForm){
|
||||
List<Map<String, Object>> list= deviceMapper.getEquipAllByType(deviceForm);
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
package com.fuyuanshen.web.util;
|
||||
|
||||
import com.aliyun.dyvmsapi20170525.Client;
|
||||
import com.aliyun.dyvmsapi20170525.models.SingleCallByTtsRequest;
|
||||
import com.aliyun.dyvmsapi20170525.models.SingleCallByTtsResponse;
|
||||
import com.aliyun.teaopenapi.models.Config;
|
||||
import com.aliyun.teautil.models.RuntimeOptions;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AliyunVoiceUtil {
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Value("${alibaba.tts.akId}")
|
||||
private String akId;
|
||||
@Value("${alibaba.tts.akSecret}")
|
||||
private String akSecret;
|
||||
// @Value("${alibaba.tts.calledShowNumber:}")
|
||||
private String calledShowNumber;
|
||||
|
||||
// ========== 核心:单例客户端(类似 OkHttpClient) ==========
|
||||
private volatile Client client;
|
||||
|
||||
/**
|
||||
* 获取客户端(双重检查锁实现单例)
|
||||
* 只有在第一次调用时才会根据配置实例化,后续直接返回复用
|
||||
*/
|
||||
private Client getClient() throws Exception {
|
||||
if (client == null) {
|
||||
synchronized (this) {
|
||||
if (client == null) {
|
||||
log.info("[AliyunVoice] 正在初始化阿里云语音客户端...");
|
||||
Config config = new Config()
|
||||
.setAccessKeyId(akId)
|
||||
.setAccessKeySecret(akSecret)
|
||||
.setEndpoint("dyvmsapi.aliyuncs.com");
|
||||
this.client = new Client(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步发送方法:由异步架构调用
|
||||
*/
|
||||
public String sendTtsSync(String phone, String templateCode, Map<String, String> params) {
|
||||
|
||||
try {
|
||||
// 1. 获取(或初始化)单例客户端
|
||||
Client voiceClient = getClient();
|
||||
|
||||
SingleCallByTtsRequest request = new SingleCallByTtsRequest()
|
||||
.setCalledNumber(phone)
|
||||
.setTtsCode(templateCode)
|
||||
.setTtsParam(objectMapper.writeValueAsString(params));
|
||||
|
||||
if (StringUtils.hasText(calledShowNumber)) {
|
||||
request.setCalledShowNumber(calledShowNumber);
|
||||
}
|
||||
|
||||
// 生产级超时配置
|
||||
RuntimeOptions runtime = new RuntimeOptions();
|
||||
runtime.setConnectTimeout(5000);
|
||||
runtime.setReadTimeout(10000);
|
||||
|
||||
SingleCallByTtsResponse response = voiceClient.singleCallByTtsWithOptions(request, runtime);
|
||||
|
||||
if ("OK".equalsIgnoreCase(response.getBody().getCode())) {
|
||||
return response.getBody().getCallId();
|
||||
} else {
|
||||
log.error("[AliyunVoice] 拨号失败: {}", response.getBody().getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[AliyunVoice] 接口异常", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user