Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -80,6 +80,13 @@
|
|||||||
<artifactId>yudao-spring-boot-starter-mq</artifactId>
|
<artifactId>yudao-spring-boot-starter-mq</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- MQTT client -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.paho</groupId>
|
||||||
|
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||||
|
<version>1.2.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Test 测试相关 -->
|
<!-- Test 测试相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
@@ -134,14 +141,10 @@
|
|||||||
<artifactId>spring-websocket</artifactId>
|
<artifactId>spring-websocket</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- MongoDB -->
|
<!-- MongoDB -->
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
<groupId>org.springframework.boot</groupId>
|
||||||
<!-- <artifactId>spring-boot-starter-data-mongodb</artifactId>-->
|
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.springframework.data</groupId>-->
|
|
||||||
<!-- <artifactId>spring-data-mongodb</artifactId>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
<!-- Validation for @Valid/@NotNull etc. -->
|
<!-- Validation for @Valid/@NotNull etc. -->
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.config;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mongo.telemetry.DeviceTelemetryRepository;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable Mongo repositories for the farm module.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableMongoRepositories(basePackageClasses = DeviceTelemetryRepository.class)
|
||||||
|
public class FarmMongoConfiguration {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.config;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
import cn.iocoder.yudao.module.farm.service.mqtt.MqttClientManager;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(MqttProperties.class)
|
||||||
|
@ConditionalOnProperty(prefix = "mqtt", name = "broker")
|
||||||
|
public class MqttAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MqttClient mqttClient(MqttProperties props) throws MqttException {
|
||||||
|
MqttConnectOptions options = new MqttConnectOptions();
|
||||||
|
options.setCleanSession(props.isCleanSession());
|
||||||
|
options.setKeepAliveInterval(props.getKeepAlive());
|
||||||
|
if (props.getUsername() != null && !props.getUsername().isEmpty()) {
|
||||||
|
options.setUserName(props.getUsername());
|
||||||
|
options.setPassword(props.getPassword() != null ? props.getPassword().toCharArray() : new char[0]);
|
||||||
|
}
|
||||||
|
MqttClient client = new MqttClient(props.getBroker(), props.getClientId(), new MemoryPersistence());
|
||||||
|
client.connect(options);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "mqtt", name = "connections")
|
||||||
|
public java.util.Map<String, MqttClient> multipleMqttClients(MqttProperties props, MqttClientManager manager) throws MqttException {
|
||||||
|
java.util.Map<String, MqttClient> map = new java.util.HashMap<>();
|
||||||
|
if (props.getConnections() != null) {
|
||||||
|
for (MqttConnectionProperties c : props.getConnections()) {
|
||||||
|
MqttClient cli = manager.createAndConnect(
|
||||||
|
c.getName(), c.getBroker(), c.getClientId(), c.getUsername(), c.getPassword(), c.isCleanSession(), c.getKeepAlive()
|
||||||
|
);
|
||||||
|
map.put(c.getName(), cli);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.config;
|
||||||
|
|
||||||
|
public class MqttConnectionProperties {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String broker;
|
||||||
|
private String deviceId;
|
||||||
|
private String clientId;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private boolean cleanSession = true;
|
||||||
|
private int keepAlive = 30;
|
||||||
|
private int qos = 1;
|
||||||
|
private boolean reconnect = true;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBroker() {
|
||||||
|
return broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBroker(String broker) {
|
||||||
|
this.broker = broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCleanSession() {
|
||||||
|
return cleanSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCleanSession(boolean cleanSession) {
|
||||||
|
this.cleanSession = cleanSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeepAlive() {
|
||||||
|
return keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeepAlive(int keepAlive) {
|
||||||
|
this.keepAlive = keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getQos() {
|
||||||
|
return qos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQos(int qos) {
|
||||||
|
this.qos = qos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReconnect() {
|
||||||
|
return reconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReconnect(boolean reconnect) {
|
||||||
|
this.reconnect = reconnect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@ConfigurationProperties(prefix = "mqtt")
|
||||||
|
public class MqttProperties {
|
||||||
|
|
||||||
|
private String broker;
|
||||||
|
private String clientId;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private boolean cleanSession = true;
|
||||||
|
private int keepAlive = 30;
|
||||||
|
private int qos = 1;
|
||||||
|
private boolean reconnect = true;
|
||||||
|
|
||||||
|
private java.util.List<MqttConnectionProperties> connections;
|
||||||
|
|
||||||
|
public String getBroker() {
|
||||||
|
return broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBroker(String broker) {
|
||||||
|
this.broker = broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCleanSession() {
|
||||||
|
return cleanSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCleanSession(boolean cleanSession) {
|
||||||
|
this.cleanSession = cleanSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeepAlive() {
|
||||||
|
return keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeepAlive(int keepAlive) {
|
||||||
|
this.keepAlive = keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getQos() {
|
||||||
|
return qos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQos(int qos) {
|
||||||
|
this.qos = qos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReconnect() {
|
||||||
|
return reconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReconnect(boolean reconnect) {
|
||||||
|
this.reconnect = reconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.util.List<MqttConnectionProperties> getConnections() {
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnections(java.util.List<MqttConnectionProperties> connections) {
|
||||||
|
this.connections = connections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -307,12 +307,9 @@ public class DictController {
|
|||||||
|
|
||||||
@Operation(summary = "字典数据维护-下拉框列表-二级物种类别")
|
@Operation(summary = "字典数据维护-下拉框列表-二级物种类别")
|
||||||
@GetMapping("/list/two-library")
|
@GetMapping("/list/two-library")
|
||||||
public CommonResult<List<SpeciesClassifyLibraryRespVO>> getTwoLibraryList() {
|
public CommonResult<List<SpeciesThreeLevelTreeRespVO>> getTwoLibraryList() {
|
||||||
try {
|
try {
|
||||||
// 获取物种类别字典数据
|
List<SpeciesThreeLevelTreeRespVO> twoList = speciesLibraryService.getSpeciesTwoLevelTree();
|
||||||
List<SysDictDO> dictList = sysDictService.getByTypeCode(CommonConstants.DICT_TYPE_CODE_3);
|
|
||||||
// 使用工具类构建二级树结构
|
|
||||||
List<SpeciesClassifyLibraryRespVO> twoList = TreeStructureUtil.buildTwoLevelTree(dictList);
|
|
||||||
return success(twoList);
|
return success(twoList);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取二级物种类别列表失败", e);
|
log.error("获取二级物种类别列表失败", e);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 人员管理")
|
@Tag(name = "管理后台 - 人员管理")
|
||||||
@@ -38,7 +39,12 @@ public class PersonnelManagementController {
|
|||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建人员管理")
|
@Operation(summary = "创建人员管理")
|
||||||
public CommonResult<String> createPersonnelManagement(@Valid @RequestBody PersonnelManagementSaveReqVO createReqVO) {
|
public CommonResult<String> createPersonnelManagement(@Valid @RequestBody PersonnelManagementSaveReqVO createReqVO) {
|
||||||
return success(personnelManagementService.createPersonnelManagement(createReqVO));
|
String management = personnelManagementService.createPersonnelManagement(createReqVO);
|
||||||
|
if (management.length() > 0) {
|
||||||
|
return success(management);
|
||||||
|
} else {
|
||||||
|
return error(501,"手机号重复!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/reset")
|
@PutMapping("/reset")
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import jakarta.validation.Valid;
|
|||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@@ -24,6 +26,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
@@ -44,14 +47,12 @@ public class PlotInfoController {
|
|||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建地块")
|
@Operation(summary = "创建地块")
|
||||||
|
|
||||||
public CommonResult<String> createPlotInfo(@Valid @RequestBody PlotInfoSaveReqVO createReqVO) {
|
public CommonResult<String> createPlotInfo(@Valid @RequestBody PlotInfoSaveReqVO createReqVO) {
|
||||||
return success(plotInfoService.createPlotInfo(createReqVO));
|
return success(plotInfoService.createPlotInfo(createReqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
@Operation(summary = "更新地块")
|
@Operation(summary = "更新地块")
|
||||||
|
|
||||||
public CommonResult<Boolean> updatePlotInfo(@Valid @RequestBody PlotInfoSaveReqVO updateReqVO) {
|
public CommonResult<Boolean> updatePlotInfo(@Valid @RequestBody PlotInfoSaveReqVO updateReqVO) {
|
||||||
plotInfoService.updatePlotInfo(updateReqVO);
|
plotInfoService.updatePlotInfo(updateReqVO);
|
||||||
return success(true);
|
return success(true);
|
||||||
@@ -60,7 +61,6 @@ public class PlotInfoController {
|
|||||||
@DeleteMapping("/delete")
|
@DeleteMapping("/delete")
|
||||||
@Operation(summary = "删除地块")
|
@Operation(summary = "删除地块")
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
|
||||||
public CommonResult<Boolean> deletePlotInfo(@RequestParam("id") String id) {
|
public CommonResult<Boolean> deletePlotInfo(@RequestParam("id") String id) {
|
||||||
plotInfoService.deletePlotInfo(id);
|
plotInfoService.deletePlotInfo(id);
|
||||||
return success(true);
|
return success(true);
|
||||||
@@ -69,7 +69,6 @@ public class PlotInfoController {
|
|||||||
@DeleteMapping("/delete-list")
|
@DeleteMapping("/delete-list")
|
||||||
@Parameter(name = "ids", description = "编号", required = true)
|
@Parameter(name = "ids", description = "编号", required = true)
|
||||||
@Operation(summary = "批量删除地块")
|
@Operation(summary = "批量删除地块")
|
||||||
|
|
||||||
public CommonResult<Boolean> deletePlotInfoList(@RequestParam("ids") List<String> ids) {
|
public CommonResult<Boolean> deletePlotInfoList(@RequestParam("ids") List<String> ids) {
|
||||||
plotInfoService.deletePlotInfoListByIds(ids);
|
plotInfoService.deletePlotInfoListByIds(ids);
|
||||||
return success(true);
|
return success(true);
|
||||||
@@ -78,7 +77,6 @@ public class PlotInfoController {
|
|||||||
@GetMapping("/get")
|
@GetMapping("/get")
|
||||||
@Operation(summary = "获得地块")
|
@Operation(summary = "获得地块")
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
|
||||||
public CommonResult<PlotInfoRespVO> getPlotInfo(@RequestParam("id") String id) {
|
public CommonResult<PlotInfoRespVO> getPlotInfo(@RequestParam("id") String id) {
|
||||||
PlotInfoDO plotInfo = plotInfoService.getPlotInfo(id);
|
PlotInfoDO plotInfo = plotInfoService.getPlotInfo(id);
|
||||||
return success(BeanUtils.toBean(plotInfo, PlotInfoRespVO.class));
|
return success(BeanUtils.toBean(plotInfo, PlotInfoRespVO.class));
|
||||||
@@ -86,7 +84,6 @@ public class PlotInfoController {
|
|||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@Operation(summary = "获得地块分页")
|
@Operation(summary = "获得地块分页")
|
||||||
|
|
||||||
public CommonResult<PageResult<PlotInfoRespVO>> getPlotInfoPage(@Valid PlotInfoPageReqVO pageReqVO) {
|
public CommonResult<PageResult<PlotInfoRespVO>> getPlotInfoPage(@Valid PlotInfoPageReqVO pageReqVO) {
|
||||||
PageResult<PlotInfoDO> pageResult = plotInfoService.getPlotInfoPage(pageReqVO);
|
PageResult<PlotInfoDO> pageResult = plotInfoService.getPlotInfoPage(pageReqVO);
|
||||||
return success(BeanUtils.toBean(pageResult, PlotInfoRespVO.class));
|
return success(BeanUtils.toBean(pageResult, PlotInfoRespVO.class));
|
||||||
@@ -94,15 +91,14 @@ public class PlotInfoController {
|
|||||||
|
|
||||||
@GetMapping("/export-excel")
|
@GetMapping("/export-excel")
|
||||||
@Operation(summary = "导出地块 Excel")
|
@Operation(summary = "导出地块 Excel")
|
||||||
|
|
||||||
@ApiAccessLog(operateType = EXPORT)
|
@ApiAccessLog(operateType = EXPORT)
|
||||||
public void exportPlotInfoExcel(@Valid PlotInfoPageReqVO pageReqVO,
|
public void exportPlotInfoExcel(@Valid PlotInfoPageReqVO pageReqVO,
|
||||||
HttpServletResponse response) throws IOException {
|
HttpServletResponse response) throws IOException {
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||||
List<PlotInfoDO> list = plotInfoService.getPlotInfoPage(pageReqVO).getList();
|
List<PlotInfoDO> list = plotInfoService.getPlotInfoPage(pageReqVO).getList();
|
||||||
// 导出 Excel
|
// 导出 Excel
|
||||||
ExcelUtils.write(response, "地块.xls", "数据", PlotInfoRespVO.class,
|
ExcelUtils.write(response, "地块.xls", "数据", PlotInfoRespVO.class,
|
||||||
BeanUtils.toBean(list, PlotInfoRespVO.class));
|
BeanUtils.toBean(list, PlotInfoRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.dal.dataobject.mqtt;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@TableName("farm_mqtt_connection")
|
||||||
|
@KeySequence("farm_mqtt_connection_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MqttConnectionDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String tenantId;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
private String broker;
|
||||||
|
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private Boolean cleanSession;
|
||||||
|
|
||||||
|
private Integer keepAlive;
|
||||||
|
|
||||||
|
private Integer qos;
|
||||||
|
|
||||||
|
private Boolean reconnect;
|
||||||
|
|
||||||
|
private Boolean status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@TableName("system_user_role")
|
||||||
|
@KeySequence("system_user_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SystemUserRoleDO extends BaseDO {
|
||||||
|
/**
|
||||||
|
* 自增主键
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 用户 ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
/**
|
||||||
|
* 角色 ID
|
||||||
|
*/
|
||||||
|
private Long roleId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.dal.mongo.telemetry;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
|
@Document(collection = "farm_device_telemetry")
|
||||||
|
public class DeviceTelemetryDoc {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private String tenantId;
|
||||||
|
private String deviceId;
|
||||||
|
private Long ts;
|
||||||
|
private String payloadJson;
|
||||||
|
|
||||||
|
public String getId() { return id; }
|
||||||
|
public void setId(String id) { this.id = id; }
|
||||||
|
public String getTenantId() { return tenantId; }
|
||||||
|
public void setTenantId(String tenantId) { this.tenantId = tenantId; }
|
||||||
|
public String getDeviceId() { return deviceId; }
|
||||||
|
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
|
||||||
|
public Long getTs() { return ts; }
|
||||||
|
public void setTs(Long ts) { this.ts = ts; }
|
||||||
|
public String getPayloadJson() { return payloadJson; }
|
||||||
|
public void setPayloadJson(String payloadJson) { this.payloadJson = payloadJson; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.dal.mongo.telemetry;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface DeviceTelemetryRepository extends MongoRepository<DeviceTelemetryDoc, String> {
|
||||||
|
List<DeviceTelemetryDoc> findTop100ByTenantIdAndDeviceIdOrderByTsDesc(String tenantId, String deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.dal.mysql.mqtt;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.dataobject.mqtt.MqttConnectionDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface MqttConnectionMapper extends BaseMapperX<MqttConnectionDO> {
|
||||||
|
|
||||||
|
default MqttConnectionDO selectByDeviceIdAndTenant(String deviceId, String tenantId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<MqttConnectionDO>()
|
||||||
|
.eqIfPresent(MqttConnectionDO::getDeviceId, deviceId)
|
||||||
|
.eqIfPresent(MqttConnectionDO::getTenantId, tenantId)
|
||||||
|
.eq(MqttConnectionDO::getStatus, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserRoleDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SystemUserRoleMapper extends BaseMapperX<SystemUserRoleDO> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.service.mqtt;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo.DeviceInfoMapper;
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import cn.iocoder.yudao.module.farm.service.telemetry.DeviceTelemetryService;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DeviceMqttService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceInfoMapper deviceInfoMapper;
|
||||||
|
@Resource
|
||||||
|
private MqttConnectionService mqttConnectionService;
|
||||||
|
@Resource
|
||||||
|
private DeviceTelemetryService deviceTelemetryService;
|
||||||
|
|
||||||
|
private final Set<String> subscribed = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
// 上报主题
|
||||||
|
private String telemetryTopic(String deviceUniqueId) {
|
||||||
|
return "farm/" + deviceUniqueId + "/telemetry";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下发指令
|
||||||
|
private String commandTopic(String deviceUniqueId) {
|
||||||
|
return "farm/" + deviceUniqueId + "/cmd";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publishTelemetry(String deviceUniqueId, String jsonPayload) throws MqttException {
|
||||||
|
MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
|
||||||
|
if (client == null) return;
|
||||||
|
client.publish(telemetryTopic(deviceUniqueId), jsonPayload.getBytes(StandardCharsets.UTF_8), 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendCommand(String deviceUniqueId, String jsonCommand) throws MqttException {
|
||||||
|
MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
|
||||||
|
if (client == null) return;
|
||||||
|
client.publish(commandTopic(deviceUniqueId), jsonCommand.getBytes(StandardCharsets.UTF_8), 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribeTelemetry(String deviceUniqueId, IMqttMessageListener listener) throws MqttException {
|
||||||
|
MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
|
||||||
|
if (client == null) return;
|
||||||
|
String topic = telemetryTopic(deviceUniqueId);
|
||||||
|
String key = client.getClientId() + "|" + topic;
|
||||||
|
if (subscribed.add(key)) {
|
||||||
|
client.subscribe(topic, 1, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribeCommands(String deviceUniqueId, IMqttMessageListener listener) throws MqttException {
|
||||||
|
MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
|
||||||
|
if (client == null) return;
|
||||||
|
String topic = commandTopic(deviceUniqueId);
|
||||||
|
String key = client.getClientId() + "|" + topic;
|
||||||
|
if (subscribed.add(key)) {
|
||||||
|
client.subscribe(topic, 1, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅并自动入库
|
||||||
|
public void subscribeTelemetryAndPersist(String deviceUniqueId) throws MqttException {
|
||||||
|
this.subscribeTelemetry(deviceUniqueId, (topic, message) -> {
|
||||||
|
String payload = new String(message.getPayload(), StandardCharsets.UTF_8);
|
||||||
|
deviceTelemetryService.saveTelemetry(deviceUniqueId, payload);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceInfoDO getDevice(String deviceUniqueId) {
|
||||||
|
return deviceInfoMapper.selectOne(DeviceInfoDO::getDeviceUniqueId, deviceUniqueId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.service.mqtt;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MqttClientManager {
|
||||||
|
|
||||||
|
private final Map<String, MqttClient> clients = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public MqttClient createAndConnect(String name,
|
||||||
|
String broker,
|
||||||
|
String clientId,
|
||||||
|
String username,
|
||||||
|
String password,
|
||||||
|
boolean cleanSession,
|
||||||
|
int keepAlive) throws MqttException {
|
||||||
|
MqttClient client = new MqttClient(broker, clientId, new MemoryPersistence());
|
||||||
|
MqttConnectOptions options = new MqttConnectOptions();
|
||||||
|
options.setCleanSession(cleanSession);
|
||||||
|
options.setKeepAliveInterval(keepAlive);
|
||||||
|
if (username != null && !username.isEmpty()) {
|
||||||
|
options.setUserName(username);
|
||||||
|
options.setPassword(password != null ? password.toCharArray() : new char[0]);
|
||||||
|
}
|
||||||
|
client.connect(options);
|
||||||
|
clients.put(name, client);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttClient get(String name) {
|
||||||
|
return clients.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnectAndRemove(String name) {
|
||||||
|
MqttClient c = clients.remove(name);
|
||||||
|
if (c != null) {
|
||||||
|
try { c.disconnect(); } catch (Exception ignored) {}
|
||||||
|
try { c.close(); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.service.mqtt;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MqttClientService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MqttConnectionService mqttConnectionService;
|
||||||
|
|
||||||
|
public void publish(String deviceId, String topic, String payload, int qos, boolean retained) throws MqttException {
|
||||||
|
MqttClient client = mqttConnectionService.getClientByDeviceId(deviceId);
|
||||||
|
if (client == null) return;
|
||||||
|
client.publish(topic, payload.getBytes(StandardCharsets.UTF_8), qos, retained);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(String deviceId, String topicFilter, int qos, IMqttMessageListener listener) throws MqttException {
|
||||||
|
MqttClient client = mqttConnectionService.getClientByDeviceId(deviceId);
|
||||||
|
if (client == null) return;
|
||||||
|
client.subscribe(topicFilter, qos, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.service.mqtt;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.dataobject.mqtt.MqttConnectionDO;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mysql.mqtt.MqttConnectionMapper;
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MqttConnectionService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MqttConnectionMapper connectionMapper;
|
||||||
|
|
||||||
|
private final Map<String, MqttClient> cache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public MqttClient getClientByDeviceId(String deviceId) throws MqttException {
|
||||||
|
String tenantId = String.valueOf(getLoginUser().getTenantId());
|
||||||
|
return this.getClientByDeviceId(deviceId, tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttClient getClientByDeviceId(String deviceId, String tenantId) throws MqttException {
|
||||||
|
String key = tenantId + ":" + deviceId;
|
||||||
|
MqttClient existing = cache.get(key);
|
||||||
|
if (existing != null) {
|
||||||
|
if (!existing.isConnected()) {
|
||||||
|
try { existing.reconnect(); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
if (existing.isConnected()) return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
MqttConnectionDO cfg = connectionMapper.selectByDeviceIdAndTenant(deviceId, tenantId);
|
||||||
|
if (cfg == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MqttClient client = new MqttClient(cfg.getBroker(), cfg.getClientId(), new MemoryPersistence());
|
||||||
|
MqttConnectOptions options = new MqttConnectOptions();
|
||||||
|
options.setCleanSession(Boolean.TRUE.equals(cfg.getCleanSession()));
|
||||||
|
options.setAutomaticReconnect(Boolean.TRUE.equals(cfg.getReconnect()));
|
||||||
|
if (cfg.getKeepAlive() != null) options.setKeepAliveInterval(cfg.getKeepAlive());
|
||||||
|
if (cfg.getUsername() != null && !cfg.getUsername().isEmpty()) {
|
||||||
|
options.setUserName(cfg.getUsername());
|
||||||
|
options.setPassword(cfg.getPassword() != null ? cfg.getPassword().toCharArray() : new char[0]);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String lwtTopic = "farm/" + deviceId + "/lwt";
|
||||||
|
MqttMessage lwt = new MqttMessage("offline".getBytes(StandardCharsets.UTF_8));
|
||||||
|
lwt.setQos(cfg.getQos() != null ? cfg.getQos() : 1);
|
||||||
|
lwt.setRetained(true);
|
||||||
|
options.setWill(lwtTopic, lwt.getPayload(), lwt.getQos(), lwt.isRetained());
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
client.connect(options);
|
||||||
|
cache.put(key, client);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publish(String deviceId, String topic, String payload, int qos, boolean retained) throws MqttException {
|
||||||
|
MqttClient c = getClientByDeviceId(deviceId);
|
||||||
|
if (c == null) return;
|
||||||
|
c.publish(topic, payload.getBytes(StandardCharsets.UTF_8), qos, retained);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(String deviceId, String topicFilter, int qos, IMqttMessageListener listener) throws MqttException {
|
||||||
|
MqttClient c = getClientByDeviceId(deviceId);
|
||||||
|
if (c == null) return;
|
||||||
|
c.subscribe(topicFilter, qos, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload(String deviceId) {
|
||||||
|
String tenantId = String.valueOf(getLoginUser().getTenantId());
|
||||||
|
String key = tenantId + ":" + deviceId;
|
||||||
|
MqttClient old = cache.remove(key);
|
||||||
|
if (old != null) {
|
||||||
|
try { old.disconnect(); } catch (Exception ignored) {}
|
||||||
|
try { old.close(); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void shutdown() {
|
||||||
|
for (Map.Entry<String, MqttClient> e : cache.entrySet()) {
|
||||||
|
try { e.getValue().disconnect(); } catch (Exception ignored) {}
|
||||||
|
try { e.getValue().close(); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -9,8 +9,10 @@ import cn.iocoder.yudao.module.farm.controller.admin.personnelmanagement.vo.Pers
|
|||||||
import cn.iocoder.yudao.module.farm.controller.admin.personnelmanagement.vo.PersonnelManagementSaveReqVO;
|
import cn.iocoder.yudao.module.farm.controller.admin.personnelmanagement.vo.PersonnelManagementSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.PersonnelManagementDO;
|
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.PersonnelManagementDO;
|
||||||
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserDO;
|
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserDO;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserRoleDO;
|
||||||
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.PersonnelManagementMapper;
|
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.PersonnelManagementMapper;
|
||||||
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.SystemUserMapper;
|
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.SystemUserMapper;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.SystemUserRoleMapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
@@ -38,15 +40,21 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
|
|||||||
private SystemUserMapper userMapper;
|
private SystemUserMapper userMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private PasswordEncoder passwordEncoder;
|
private PasswordEncoder passwordEncoder;
|
||||||
|
@Resource
|
||||||
|
private SystemUserRoleMapper systemUserRoleMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createPersonnelManagement(PersonnelManagementSaveReqVO createReqVO) {
|
public String createPersonnelManagement(PersonnelManagementSaveReqVO createReqVO) {
|
||||||
LoginUser user = getLoginUser();
|
LoginUser user = getLoginUser();
|
||||||
|
|
||||||
// 插入
|
// 插入
|
||||||
PersonnelManagementDO personnelManagement = BeanUtils.toBean(createReqVO, PersonnelManagementDO.class);
|
PersonnelManagementDO personnelManagement = BeanUtils.toBean(createReqVO, PersonnelManagementDO.class);
|
||||||
personnelManagement.setId(IdUtil.fastUUID());
|
personnelManagement.setId(IdUtil.fastUUID());
|
||||||
personnelManagement.setTenantId(String.valueOf(user.getTenantId()));
|
personnelManagement.setTenantId(String.valueOf(user.getTenantId()));
|
||||||
|
SystemUserDO userDO = userMapper.selectByPhone(personnelManagement.getPhone());
|
||||||
|
if (userDO != null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
// 处理图片集合转换
|
// 处理图片集合转换
|
||||||
handleImageConversion(personnelManagement, createReqVO);
|
handleImageConversion(personnelManagement, createReqVO);
|
||||||
|
|
||||||
@@ -59,7 +67,14 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
|
|||||||
adminUserDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
|
adminUserDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
|
||||||
String substring = personnelManagement.getPhone().substring(personnelManagement.getPhone().length() - 6);
|
String substring = personnelManagement.getPhone().substring(personnelManagement.getPhone().length() - 6);
|
||||||
adminUserDO.setPassword(encodePassword(substring)); // 加密密码
|
adminUserDO.setPassword(encodePassword(substring)); // 加密密码
|
||||||
userMapper.insert(adminUserDO);
|
userMapper.insert(adminUserDO);// 系统用户同步新增
|
||||||
|
// 用户角色关联
|
||||||
|
for (String s : personnelManagement.getRole().split(",")) {
|
||||||
|
SystemUserRoleDO userRoleDO = new SystemUserRoleDO();
|
||||||
|
userRoleDO.setUserId(adminUserDO.getId());
|
||||||
|
userRoleDO.setRoleId(Long.valueOf(s));
|
||||||
|
systemUserRoleMapper.insert(userRoleDO);
|
||||||
|
}
|
||||||
personnelManagementMapper.insert(personnelManagement);
|
personnelManagementMapper.insert(personnelManagement);
|
||||||
// 返回
|
// 返回
|
||||||
return personnelManagement.getId();
|
return personnelManagement.getId();
|
||||||
@@ -69,12 +84,25 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
|
|||||||
public void updatePersonnelManagement(PersonnelManagementSaveReqVO updateReqVO) {
|
public void updatePersonnelManagement(PersonnelManagementSaveReqVO updateReqVO) {
|
||||||
// 校验存在
|
// 校验存在
|
||||||
validatePersonnelManagementExists(updateReqVO.getId());
|
validatePersonnelManagementExists(updateReqVO.getId());
|
||||||
|
PersonnelManagementDO managementDO = personnelManagementMapper.selectById(updateReqVO.getId());
|
||||||
|
|
||||||
|
|
||||||
// 更新
|
// 更新
|
||||||
PersonnelManagementDO updateObj = BeanUtils.toBean(updateReqVO, PersonnelManagementDO.class);
|
PersonnelManagementDO updateObj = BeanUtils.toBean(updateReqVO, PersonnelManagementDO.class);
|
||||||
|
SystemUserDO userDO = userMapper.selectByPhone(managementDO.getPhone());
|
||||||
|
if (updateReqVO.getPhone() != null) userDO.setUsername(updateReqVO.getPhone());
|
||||||
|
if (updateReqVO.getName() != null) userDO.setNickname(updateReqVO.getName());
|
||||||
|
if (updateReqVO.getPhone() != null) userDO.setMobile(updateReqVO.getPhone());
|
||||||
|
if (updateReqVO.getPicture() != null) userDO.setAvatar(updateReqVO.getPicture());
|
||||||
// 处理图片集合转换
|
// 处理图片集合转换
|
||||||
handleImageConversion(updateObj, updateReqVO);
|
handleImageConversion(updateObj, updateReqVO);
|
||||||
|
for (String s : managementDO.getRole().split(",")) {
|
||||||
|
SystemUserRoleDO userRoleDO = new SystemUserRoleDO();
|
||||||
|
userRoleDO.setUserId(userDO.getId());
|
||||||
|
userRoleDO.setRoleId(Long.valueOf(s));
|
||||||
|
systemUserRoleMapper.insert(userRoleDO);
|
||||||
|
}
|
||||||
|
userMapper.updateById(userDO);
|
||||||
personnelManagementMapper.updateById(updateObj);
|
personnelManagementMapper.updateById(updateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +110,10 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
|
|||||||
public void deletePersonnelManagement(String id) {
|
public void deletePersonnelManagement(String id) {
|
||||||
// 校验存在
|
// 校验存在
|
||||||
validatePersonnelManagementExists(id);
|
validatePersonnelManagementExists(id);
|
||||||
|
PersonnelManagementDO managementDO = personnelManagementMapper.selectById(id);
|
||||||
|
SystemUserDO userDO = userMapper.selectByPhone(managementDO.getPhone());
|
||||||
|
userMapper.deleteById(userDO.getId());
|
||||||
|
systemUserRoleMapper.delete(SystemUserRoleDO::getUserId, userDO.getId());
|
||||||
// 删除
|
// 删除
|
||||||
personnelManagementMapper.deleteById(id);
|
personnelManagementMapper.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ public interface SpeciesLibraryService {
|
|||||||
*/
|
*/
|
||||||
Map<String, String> getSpeciesLibraryForLifeCycMap();
|
Map<String, String> getSpeciesLibraryForLifeCycMap();
|
||||||
|
|
||||||
/**
|
|
||||||
* 基于 speciesName1 -> speciesName2 -> cultivarName 构建三级树
|
|
||||||
*/
|
|
||||||
List<SpeciesThreeLevelTreeRespVO> getSpeciesThreeLevelTree();
|
List<SpeciesThreeLevelTreeRespVO> getSpeciesThreeLevelTree();
|
||||||
|
|
||||||
|
|
||||||
|
List<SpeciesThreeLevelTreeRespVO> getSpeciesTwoLevelTree();
|
||||||
/**
|
/**
|
||||||
* 物种与模型
|
* 物种与模型
|
||||||
* @return
|
* @return
|
||||||
|
|||||||
@@ -305,6 +305,67 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SpeciesThreeLevelTreeRespVO> getSpeciesTwoLevelTree() {
|
||||||
|
List<TwoDictTreeRespVO> dictTree = twoDictService.getTwoDictTree();
|
||||||
|
if (dictTree == null || dictTree.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1级:parentId == null 的节点
|
||||||
|
List<TwoDictTreeRespVO> level1Nodes = dictTree.stream()
|
||||||
|
.filter(n -> n != null && n.getParentId() == null)
|
||||||
|
.sorted(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 收集所有二级分类ID,一次性查询物种,避免 N+1
|
||||||
|
List<Long> level2Ids = dictTree.stream()
|
||||||
|
.filter(n -> n != null && n.getParentId() != null) // 非根即二级(在当前两级分类中)
|
||||||
|
.map(TwoDictTreeRespVO::getId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 批量查询所有二级分类下的物种,避免 N+1 查询
|
||||||
|
Map<String, List<SpeciesLibraryDO>> categoryToSpeciesMap;
|
||||||
|
if (level2Ids.isEmpty()) {
|
||||||
|
categoryToSpeciesMap = java.util.Collections.emptyMap();
|
||||||
|
} else {
|
||||||
|
// 构建查询条件:查询所有二级分类下的物种
|
||||||
|
LambdaQueryWrapper<SpeciesLibraryDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.in(SpeciesLibraryDO::getCategory, level2Ids.stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
|
queryWrapper.eq(SpeciesLibraryDO::getTenantId, String.valueOf(getLoginUser().getTenantId()));
|
||||||
|
|
||||||
|
List<SpeciesLibraryDO> allSpecies = speciesLibraryMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
|
// 按分类ID分组
|
||||||
|
categoryToSpeciesMap = allSpecies.stream()
|
||||||
|
.collect(Collectors.groupingBy(SpeciesLibraryDO::getCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SpeciesThreeLevelTreeRespVO> result = new ArrayList<>();
|
||||||
|
for (TwoDictTreeRespVO lvl1 : level1Nodes) {
|
||||||
|
SpeciesThreeLevelTreeRespVO lvl1Vo = new SpeciesThreeLevelTreeRespVO();
|
||||||
|
lvl1Vo.setName(lvl1.getName());
|
||||||
|
lvl1Vo.setId(lvl1.getId().toString());
|
||||||
|
List<SpeciesThreeLevelTreeRespVO> lvl2Vos = new ArrayList<>();
|
||||||
|
|
||||||
|
if (lvl1.getChildren() != null && !lvl1.getChildren().isEmpty()) {
|
||||||
|
// 二级按名称排序
|
||||||
|
List<TwoDictTreeRespVO> lvl2Children = new ArrayList<>(lvl1.getChildren());
|
||||||
|
lvl2Children.sort(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo)));
|
||||||
|
for (TwoDictTreeRespVO lvl2 : lvl2Children) {
|
||||||
|
SpeciesThreeLevelTreeRespVO lvl2Vo = new SpeciesThreeLevelTreeRespVO();
|
||||||
|
lvl2Vo.setName(lvl2.getName());
|
||||||
|
lvl2Vo.setId(lvl2.getId().toString());
|
||||||
|
lvl2Vos.add(lvl2Vo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lvl1Vo.setChildren(lvl2Vos);
|
||||||
|
result.add(lvl1Vo);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private String splitSpeciesName(String speciesName, int index) {
|
private String splitSpeciesName(String speciesName, int index) {
|
||||||
if (speciesName == null) {
|
if (speciesName == null) {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.module.farm.service.telemetry;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mongo.telemetry.DeviceTelemetryDoc;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mongo.telemetry.DeviceTelemetryRepository;
|
||||||
|
import cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo.DeviceInfoMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DeviceTelemetryService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceTelemetryRepository telemetryRepository;
|
||||||
|
@Resource
|
||||||
|
private DeviceInfoMapper deviceInfoMapper;
|
||||||
|
|
||||||
|
public void saveTelemetry(String deviceUniqueId, String payloadJson) {
|
||||||
|
String tenantId = String.valueOf(getLoginUser().getTenantId());
|
||||||
|
|
||||||
|
DeviceTelemetryDoc doc = new DeviceTelemetryDoc();
|
||||||
|
doc.setTenantId(tenantId);
|
||||||
|
doc.setDeviceId(deviceUniqueId);
|
||||||
|
doc.setTs(System.currentTimeMillis());
|
||||||
|
doc.setPayloadJson(payloadJson);
|
||||||
|
telemetryRepository.save(doc);
|
||||||
|
|
||||||
|
DeviceInfoDO device = deviceInfoMapper.selectOne(DeviceInfoDO::getDeviceUniqueId, deviceUniqueId);
|
||||||
|
if (device != null) {
|
||||||
|
device.setDataImage(payloadJson);
|
||||||
|
deviceInfoMapper.updateById(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.SystemUserRoleMapper">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||||
|
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||||
|
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||||
|
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -7,4 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface PersonnelMapper extends BaseMapperX<PersonnelDO> {
|
public interface PersonnelMapper extends BaseMapperX<PersonnelDO> {
|
||||||
|
|
||||||
|
default PersonnelDO selectByPhone(String mobile) {
|
||||||
|
return selectOne(PersonnelDO::getPhone, mobile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,6 +176,27 @@ public class AdminUserServiceImpl implements AdminUserService {
|
|||||||
// 2.1 更新用户
|
// 2.1 更新用户
|
||||||
AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
|
AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
|
||||||
userMapper.updateById(updateObj);
|
userMapper.updateById(updateObj);
|
||||||
|
AdminUserDO adminUserDO = userMapper.selectById(updateObj.getId());
|
||||||
|
PersonnelDO userDo = personnelMapper.selectByPhone(adminUserDO.getMobile());
|
||||||
|
if (updateObj.getNickname() != null) userDo.setName(updateObj.getNickname());
|
||||||
|
if (updateObj.getMobile() != null) userDo.setPhone(updateObj.getMobile());
|
||||||
|
if (updateObj.getDeptId() != null) userDo.setDepartment(updateObj.getDeptId().toString());
|
||||||
|
if (updateObj.getTenantId() != null) userDo.setTenantId(updateObj.getTenantId().toString());
|
||||||
|
if (updateObj.getAvatar() != null) userDo.setPicture(updateObj.getAvatar());
|
||||||
|
userDo.setAccountStatus(0);
|
||||||
|
List<UserPostDO> userPostDOS = convertList(updateObj.getPostIds(),
|
||||||
|
postId -> new UserPostDO().setUserId(updateObj.getId()).setPostId(postId));
|
||||||
|
String roles = "";
|
||||||
|
for (UserPostDO up : userPostDOS) {
|
||||||
|
if (roles.length() > 0) {
|
||||||
|
roles += "," + up.getPostId();
|
||||||
|
} else {
|
||||||
|
roles = up.getPostId().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userDo.setRole(roles);
|
||||||
|
personnelMapper.updateById(userDo);
|
||||||
|
|
||||||
// 2.2 更新岗位
|
// 2.2 更新岗位
|
||||||
updateUserPost(updateReqVO, updateObj);
|
updateUserPost(updateReqVO, updateObj);
|
||||||
|
|
||||||
@@ -262,7 +283,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
|||||||
public void deleteUser(Long id) {
|
public void deleteUser(Long id) {
|
||||||
// 1. 校验用户存在
|
// 1. 校验用户存在
|
||||||
AdminUserDO user = validateUserExists(id);
|
AdminUserDO user = validateUserExists(id);
|
||||||
|
AdminUserDO adminUserDO = userMapper.selectById(id);
|
||||||
|
personnelMapper.delete(PersonnelDO::getPhone, adminUserDO.getMobile());
|
||||||
// 2.1 删除用户
|
// 2.1 删除用户
|
||||||
userMapper.deleteById(id);
|
userMapper.deleteById(id);
|
||||||
// 2.2 删除用户关联数据
|
// 2.2 删除用户关联数据
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ lock4j:
|
|||||||
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
|
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
|
||||||
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
|
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
|
||||||
|
|
||||||
|
|
||||||
--- #################### 监控相关配置 ####################
|
--- #################### 监控相关配置 ####################
|
||||||
|
|
||||||
# Actuator 监控端点的配置项
|
# Actuator 监控端点的配置项
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ aj:
|
|||||||
cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存
|
cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存
|
||||||
timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行
|
timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行
|
||||||
type: blockPuzzle # 验证码类型 default 三种都实例化。blockPuzzle 滑块拼图、clickWord 文字点选、pictureWord 文本输入
|
type: blockPuzzle # 验证码类型 default 三种都实例化。blockPuzzle 滑块拼图、clickWord 文字点选、pictureWord 文本输入
|
||||||
water-mark: 芋道源码 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
|
water-mark: 江西云戈 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
|
||||||
interference-options: 0 # 滑动干扰项(0/1/2)
|
interference-options: 0 # 滑动干扰项(0/1/2)
|
||||||
req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false
|
req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false
|
||||||
req-get-lock-limit: 5 # 验证失败 5 次,get接口锁定
|
req-get-lock-limit: 5 # 验证失败 5 次,get接口锁定
|
||||||
|
|||||||
Reference in New Issue
Block a user