add demo
This commit is contained in:
parent
5c2fcf5e34
commit
041ed5ff46
2
pom.xml
2
pom.xml
|
|
@ -11,7 +11,7 @@
|
|||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>tuoheng-airport-ddd</artifactId>
|
||||
<artifactId>tuoheng-ddd</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Tuoheng Airport DDD</name>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tuoheng.airport.device.application.converter;
|
||||
|
||||
import com.tuoheng.airport.device.application.dto.DeviceCreateRequest;
|
||||
import com.tuoheng.airport.device.application.dto.DeviceResponse;
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
|
||||
/**
|
||||
* 设备DTO转换器(Application层)
|
||||
* 负责 Application 层 DTO 和 Domain 层领域模型之间的转换
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
public class DeviceDtoConverter {
|
||||
|
||||
/**
|
||||
* 创建请求DTO转领域模型
|
||||
*
|
||||
* @param request 创建请求DTO
|
||||
* @return 领域模型
|
||||
*/
|
||||
public static Device toDomain(DeviceCreateRequest request) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DeviceType deviceType = DeviceType.fromCode(request.getDeviceType());
|
||||
|
||||
return Device.create(
|
||||
request.getDeviceCode(),
|
||||
request.getDeviceName(),
|
||||
deviceType,
|
||||
request.getManufacturer(),
|
||||
request.getAirportId()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 领域模型转响应DTO
|
||||
*
|
||||
* @param device 领域模型
|
||||
* @return 响应DTO
|
||||
*/
|
||||
public static DeviceResponse toResponse(Device device) {
|
||||
if (device == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DeviceResponse.builder()
|
||||
.id(device.getId())
|
||||
.deviceCode(device.getDeviceCode())
|
||||
.deviceName(device.getDeviceName())
|
||||
.deviceType(device.getDeviceType() != null ? device.getDeviceType().getCode() : null)
|
||||
.deviceTypeDesc(device.getDeviceType() != null ? device.getDeviceType().getDescription() : null)
|
||||
.status(device.getStatus() != null ? device.getStatus().getCode() : null)
|
||||
.statusDesc(device.getStatus() != null ? device.getStatus().getDescription() : null)
|
||||
.airportId(device.getAirportId())
|
||||
.manufacturer(device.getManufacturer())
|
||||
.firmwareVersion(device.getFirmwareVersion())
|
||||
.createTime(device.getCreateTime())
|
||||
.updateTime(device.getUpdateTime())
|
||||
.remark(device.getRemark())
|
||||
.canExecuteTask(device.canExecuteTask())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tuoheng.airport.device.application.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 设备创建请求DTO(Application层)
|
||||
* 用于接收前端创建设备的请求参数
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
public class DeviceCreateRequest {
|
||||
|
||||
/**
|
||||
* 设备编码(必填,唯一)
|
||||
*/
|
||||
@NotBlank(message = "设备编码不能为空")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称(必填)
|
||||
*/
|
||||
@NotBlank(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型(必填)
|
||||
* 1:多旋翼 2:固定翼 3:垂直起降 4:摄像头 5:喇叭 6:探照灯
|
||||
*/
|
||||
@NotNull(message = "设备类型不能为空")
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tuoheng.airport.device.application.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 设备查询请求DTO(Application层)
|
||||
* 用于接收前端查询设备的请求参数
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
public class DeviceQueryRequest {
|
||||
|
||||
/**
|
||||
* 设备编码(模糊查询)
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称(模糊查询)
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tuoheng.airport.device.application.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备响应DTO(Application层)
|
||||
* 用于返回给前端的设备信息
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeviceResponse {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型代码
|
||||
*/
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 设备类型描述
|
||||
*/
|
||||
private String deviceTypeDesc;
|
||||
|
||||
/**
|
||||
* 设备状态代码
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 设备状态描述
|
||||
*/
|
||||
private String statusDesc;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 是否可以执行任务
|
||||
*/
|
||||
private Boolean canExecuteTask;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tuoheng.airport.device.application.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 设备更新请求DTO(Application层)
|
||||
* 用于接收前端更新设备的请求参数
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
public class DeviceUpdateRequest {
|
||||
|
||||
/**
|
||||
* 设备ID(必填)
|
||||
*/
|
||||
@NotNull(message = "设备ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
package com.tuoheng.airport.device.application.service;
|
||||
|
||||
import com.tuoheng.airport.device.application.dto.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备应用服务接口(Application层)
|
||||
* 定义设备相关的用例(Use Cases)
|
||||
* 协调领域模型完成业务操作
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
public interface DeviceApplicationService {
|
||||
|
||||
/**
|
||||
* 创建设备
|
||||
*
|
||||
* @param request 创建请求
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse createDevice(DeviceCreateRequest request);
|
||||
|
||||
/**
|
||||
* 更新设备信息
|
||||
*
|
||||
* @param request 更新请求
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse updateDevice(DeviceUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 根据ID查询设备
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse getDeviceById(Long id);
|
||||
|
||||
/**
|
||||
* 根据设备编码查询设备
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse getDeviceByCode(String deviceCode);
|
||||
|
||||
/**
|
||||
* 查询所有设备
|
||||
*
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<DeviceResponse> getAllDevices();
|
||||
|
||||
/**
|
||||
* 根据条件查询设备列表
|
||||
*
|
||||
* @param request 查询请求
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<DeviceResponse> queryDevices(DeviceQueryRequest request);
|
||||
|
||||
/**
|
||||
* 根据机场ID查询设备列表
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<DeviceResponse> getDevicesByAirportId(Long airportId);
|
||||
|
||||
/**
|
||||
* 激活设备
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse activateDevice(Long id);
|
||||
|
||||
/**
|
||||
* 停用设备
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse deactivateDevice(Long id);
|
||||
|
||||
/**
|
||||
* 标记设备为故障状态
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse markDeviceAsFaulty(Long id);
|
||||
|
||||
/**
|
||||
* 更新设备固件版本
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @param newVersion 新版本号
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse updateDeviceFirmware(Long id, String newVersion);
|
||||
|
||||
/**
|
||||
* 分配设备到机场
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @param airportId 机场ID
|
||||
* @return 设备响应
|
||||
*/
|
||||
DeviceResponse assignDeviceToAirport(Long id, Long airportId);
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*
|
||||
* @param id 设备ID
|
||||
*/
|
||||
void deleteDevice(Long id);
|
||||
|
||||
/**
|
||||
* 统计机场下的设备数量
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 设备数量
|
||||
*/
|
||||
long countDevicesByAirportId(Long airportId);
|
||||
}
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
package com.tuoheng.airport.device.application.service.impl;
|
||||
|
||||
import com.tuoheng.airport.device.application.converter.DeviceDtoConverter;
|
||||
import com.tuoheng.airport.device.application.dto.*;
|
||||
import com.tuoheng.airport.device.application.service.DeviceApplicationService;
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceStatus;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
import com.tuoheng.airport.device.domain.service.DeviceDomainService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 设备应用服务实现类(Application层)
|
||||
* 实现业务用例,协调领域服务完成业务操作
|
||||
*
|
||||
* 职责:
|
||||
* 1. 接收 DTO,转换为领域模型
|
||||
* 2. 调用 Domain Service 完成业务逻辑
|
||||
* 3. 管理事务边界
|
||||
* 4. 异常处理和日志记录
|
||||
* 5. 将领域模型转换为 DTO 返回
|
||||
*
|
||||
* 注意:Application 层不直接调用 Repository,而是调用 Domain Service
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceApplicationServiceImpl implements DeviceApplicationService {
|
||||
|
||||
private final DeviceDomainService deviceDomainService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse createDevice(DeviceCreateRequest request) {
|
||||
log.info("Application: 开始创建设备,设备编码: {}", request.getDeviceCode());
|
||||
|
||||
// 1. DTO 转领域模型(使用领域模型的工厂方法创建)
|
||||
Device device = DeviceDtoConverter.toDomain(request);
|
||||
|
||||
// 2. 设置固件版本和备注
|
||||
if (request.getFirmwareVersion() != null) {
|
||||
device.setFirmwareVersion(request.getFirmwareVersion());
|
||||
}
|
||||
if (request.getRemark() != null) {
|
||||
device.setRemark(request.getRemark());
|
||||
}
|
||||
|
||||
// 3. 调用 Domain Service 注册设备(Domain Service 会处理业务规则)
|
||||
Device savedDevice = deviceDomainService.registerDevice(device);
|
||||
|
||||
log.info("Application: 设备创建成功,设备ID: {}, 设备编码: {}",
|
||||
savedDevice.getId(), savedDevice.getDeviceCode());
|
||||
|
||||
// 4. 领域模型转 DTO 返回
|
||||
return DeviceDtoConverter.toResponse(savedDevice);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse updateDevice(DeviceUpdateRequest request) {
|
||||
log.info("Application: 开始更新设备,设备ID: {}", request.getId());
|
||||
|
||||
// 1. 通过 Domain Service 查询设备
|
||||
Device device = deviceDomainService.getDeviceById(request.getId());
|
||||
|
||||
// 2. 更新设备信息
|
||||
if (request.getDeviceName() != null) {
|
||||
device.setDeviceName(request.getDeviceName());
|
||||
}
|
||||
if (request.getManufacturer() != null) {
|
||||
device.setManufacturer(request.getManufacturer());
|
||||
}
|
||||
if (request.getFirmwareVersion() != null) {
|
||||
device.setFirmwareVersion(request.getFirmwareVersion());
|
||||
}
|
||||
if (request.getRemark() != null) {
|
||||
device.setRemark(request.getRemark());
|
||||
}
|
||||
|
||||
// 3. 如果需要分配到机场,调用 Domain Service
|
||||
if (request.getAirportId() != null && !request.getAirportId().equals(device.getAirportId())) {
|
||||
device = deviceDomainService.assignToAirport(device.getId(), request.getAirportId());
|
||||
}
|
||||
|
||||
log.info("Application: 设备更新成功,设备ID: {}", device.getId());
|
||||
|
||||
// 4. 领域模型转 DTO 返回
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceResponse getDeviceById(Long id) {
|
||||
log.info("Application: 查询设备,设备ID: {}", id);
|
||||
|
||||
// 调用 Domain Service 查询
|
||||
Device device = deviceDomainService.getDeviceById(id);
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceResponse getDeviceByCode(String deviceCode) {
|
||||
log.info("Application: 查询设备,设备编码: {}", deviceCode);
|
||||
|
||||
// 调用 Domain Service 查询
|
||||
Device device = deviceDomainService.getDeviceByCode(deviceCode);
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceResponse> getAllDevices() {
|
||||
log.info("Application: 查询所有设备");
|
||||
|
||||
// 调用 Domain Service 查询所有激活状态的设备
|
||||
List<Device> devices = deviceDomainService.getDevicesByStatus(DeviceStatus.ACTIVE);
|
||||
|
||||
return devices.stream()
|
||||
.map(DeviceDtoConverter::toResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceResponse> queryDevices(DeviceQueryRequest request) {
|
||||
log.info("Application: 根据条件查询设备列表,查询条件: {}", request);
|
||||
|
||||
List<Device> devices;
|
||||
|
||||
// 根据不同条件调用 Domain Service
|
||||
if (request.getAirportId() != null && request.getStatus() != null) {
|
||||
// 按机场ID和状态查询
|
||||
if (request.getStatus() == DeviceStatus.ACTIVE.getCode()) {
|
||||
devices = deviceDomainService.getAvailableDevicesByAirport(request.getAirportId());
|
||||
} else {
|
||||
DeviceStatus status = DeviceStatus.fromCode(request.getStatus());
|
||||
devices = deviceDomainService.getDevicesByStatus(status).stream()
|
||||
.filter(d -> d.getAirportId() != null && d.getAirportId().equals(request.getAirportId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
} else if (request.getStatus() != null) {
|
||||
// 按状态查询
|
||||
DeviceStatus status = DeviceStatus.fromCode(request.getStatus());
|
||||
devices = deviceDomainService.getDevicesByStatus(status);
|
||||
} else if (request.getDeviceType() != null) {
|
||||
// 按设备类型查询
|
||||
DeviceType deviceType = DeviceType.fromCode(request.getDeviceType());
|
||||
devices = deviceDomainService.getDevicesByType(deviceType);
|
||||
} else {
|
||||
// 查询所有激活状态的设备
|
||||
devices = deviceDomainService.getDevicesByStatus(DeviceStatus.ACTIVE);
|
||||
}
|
||||
|
||||
return devices.stream()
|
||||
.map(DeviceDtoConverter::toResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceResponse> getDevicesByAirportId(Long airportId) {
|
||||
log.info("Application: 查询机场下的设备列表,机场ID: {}", airportId);
|
||||
|
||||
// 调用 Domain Service 查询机场下的可用设备
|
||||
List<Device> devices = deviceDomainService.getAvailableDevicesByAirport(airportId);
|
||||
|
||||
return devices.stream()
|
||||
.map(DeviceDtoConverter::toResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse activateDevice(Long id) {
|
||||
log.info("Application: 激活设备,设备ID: {}", id);
|
||||
|
||||
// 调用 Domain Service 激活设备(Domain Service 会处理业务规则)
|
||||
Device device = deviceDomainService.activateDevice(id);
|
||||
|
||||
log.info("Application: 设备激活成功,设备ID: {}, 当前状态: {}",
|
||||
id, device.getStatus());
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse deactivateDevice(Long id) {
|
||||
log.info("Application: 停用设备,设备ID: {}", id);
|
||||
|
||||
// 调用 Domain Service 停用设备(Domain Service 会处理业务规则)
|
||||
Device device = deviceDomainService.deactivateDevice(id);
|
||||
|
||||
log.info("Application: 设备停用成功,设备ID: {}, 当前状态: {}",
|
||||
id, device.getStatus());
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse markDeviceAsFaulty(Long id) {
|
||||
log.info("Application: 标记设备为故障状态,设备ID: {}", id);
|
||||
|
||||
// 调用 Domain Service 标记设备故障
|
||||
Device device = deviceDomainService.markDeviceAsFaulty(id, "系统标记");
|
||||
|
||||
log.info("Application: 设备已标记为故障状态,设备ID: {}", id);
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse updateDeviceFirmware(Long id, String newVersion) {
|
||||
log.info("Application: 更新设备固件版本,设备ID: {}, 新版本: {}", id, newVersion);
|
||||
|
||||
// 调用 Domain Service 更新固件(Domain Service 会处理业务规则)
|
||||
Device device = deviceDomainService.updateFirmware(id, newVersion);
|
||||
|
||||
log.info("Application: 设备固件版本更新成功,设备ID: {}, 新版本: {}", id, newVersion);
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DeviceResponse assignDeviceToAirport(Long id, Long airportId) {
|
||||
log.info("Application: 分配设备到机场,设备ID: {}, 机场ID: {}", id, airportId);
|
||||
|
||||
// 调用 Domain Service 分配设备(Domain Service 会处理业务规则)
|
||||
Device device = deviceDomainService.assignToAirport(id, airportId);
|
||||
|
||||
log.info("Application: 设备分配成功,设备ID: {}, 机场ID: {}", id, airportId);
|
||||
|
||||
return DeviceDtoConverter.toResponse(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteDevice(Long id) {
|
||||
log.info("Application: 删除设备,设备ID: {}", id);
|
||||
|
||||
// 调用 Domain Service 删除设备(Domain Service 会处理业务规则)
|
||||
deviceDomainService.deleteDevice(id);
|
||||
|
||||
log.info("Application: 设备删除成功,设备ID: {}", id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countDevicesByAirportId(Long airportId) {
|
||||
log.info("Application: 统计机场下的设备数量,机场ID: {}", airportId);
|
||||
|
||||
// 调用 Domain Service 统计
|
||||
long count = deviceDomainService.countDevicesByAirport(airportId);
|
||||
|
||||
log.info("Application: 机场下的设备数量: {}, 机场ID: {}", count, airportId);
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
package com.tuoheng.airport.device.domain.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备领域模型(聚合根)
|
||||
* 这是 domain 层的核心实体,包含业务逻辑和业务规则
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Device {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备编码(唯一标识)
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private DeviceType deviceType;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
*/
|
||||
private DeviceStatus status;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
// ==================== 业务方法 ====================
|
||||
|
||||
/**
|
||||
* 激活设备
|
||||
* 业务规则:只有离线或故障状态的设备才能被激活
|
||||
*/
|
||||
public void activate() {
|
||||
if (this.status == DeviceStatus.ACTIVE) {
|
||||
throw new IllegalStateException("设备已经是激活状态,无需重复激活");
|
||||
}
|
||||
this.status = DeviceStatus.ACTIVE;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用设备
|
||||
* 业务规则:只有激活状态的设备才能被停用
|
||||
*/
|
||||
public void deactivate() {
|
||||
if (this.status == DeviceStatus.INACTIVE) {
|
||||
throw new IllegalStateException("设备已经是停用状态");
|
||||
}
|
||||
this.status = DeviceStatus.INACTIVE;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记设备为故障状态
|
||||
*/
|
||||
public void markAsFaulty() {
|
||||
this.status = DeviceStatus.FAULTY;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新固件版本
|
||||
*/
|
||||
public void updateFirmware(String newVersion) {
|
||||
if (newVersion == null || newVersion.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("固件版本不能为空");
|
||||
}
|
||||
this.firmwareVersion = newVersion;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配到机场
|
||||
*/
|
||||
public void assignToAirport(Long airportId) {
|
||||
if (airportId == null || airportId <= 0) {
|
||||
throw new IllegalArgumentException("机场ID无效");
|
||||
}
|
||||
this.airportId = airportId;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证设备是否可以执行任务
|
||||
*/
|
||||
public boolean canExecuteTask() {
|
||||
return this.status == DeviceStatus.ACTIVE && this.airportId != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新设备(工厂方法)
|
||||
*/
|
||||
public static Device create(String deviceCode, String deviceName, DeviceType deviceType,
|
||||
String manufacturer, Long airportId) {
|
||||
if (deviceCode == null || deviceCode.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("设备编码不能为空");
|
||||
}
|
||||
if (deviceName == null || deviceName.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("设备名称不能为空");
|
||||
}
|
||||
if (deviceType == null) {
|
||||
throw new IllegalArgumentException("设备类型不能为空");
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return Device.builder()
|
||||
.deviceCode(deviceCode)
|
||||
.deviceName(deviceName)
|
||||
.deviceType(deviceType)
|
||||
.status(DeviceStatus.INACTIVE) // 新设备默认为停用状态
|
||||
.manufacturer(manufacturer)
|
||||
.airportId(airportId)
|
||||
.createTime(now)
|
||||
.updateTime(now)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.tuoheng.airport.device.domain.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 设备状态枚举(值对象)
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DeviceStatus {
|
||||
|
||||
/**
|
||||
* 激活状态(可用)
|
||||
*/
|
||||
ACTIVE(1, "激活"),
|
||||
|
||||
/**
|
||||
* 停用状态(不可用)
|
||||
*/
|
||||
INACTIVE(0, "停用"),
|
||||
|
||||
/**
|
||||
* 故障状态
|
||||
*/
|
||||
FAULTY(2, "故障"),
|
||||
|
||||
/**
|
||||
* 维护中
|
||||
*/
|
||||
MAINTENANCE(3, "维护中");
|
||||
|
||||
private final Integer code;
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* 根据code获取枚举
|
||||
*/
|
||||
public static DeviceStatus fromCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (DeviceStatus status : DeviceStatus.values()) {
|
||||
if (status.getCode().equals(code)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("未知的设备状态: " + code);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.tuoheng.airport.device.domain.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 设备类型枚举(值对象)
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DeviceType {
|
||||
|
||||
/**
|
||||
* 多旋翼无人机
|
||||
*/
|
||||
MULTICOPTER(1, "多旋翼无人机"),
|
||||
|
||||
/**
|
||||
* 固定翼无人机
|
||||
*/
|
||||
FIXED_WING(2, "固定翼无人机"),
|
||||
|
||||
/**
|
||||
* 垂直起降无人机
|
||||
*/
|
||||
VTOL(3, "垂直起降无人机"),
|
||||
|
||||
/**
|
||||
* 摄像头
|
||||
*/
|
||||
CAMERA(4, "摄像头"),
|
||||
|
||||
/**
|
||||
* 喇叭
|
||||
*/
|
||||
MEGAPHONE(5, "喇叭"),
|
||||
|
||||
/**
|
||||
* 探照灯
|
||||
*/
|
||||
SEARCHLIGHT(6, "探照灯");
|
||||
|
||||
private final Integer code;
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* 根据code获取枚举
|
||||
*/
|
||||
public static DeviceType fromCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (DeviceType type : DeviceType.values()) {
|
||||
if (type.getCode().equals(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("未知的设备类型: " + code);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.tuoheng.airport.device.domain.repository;
|
||||
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceStatus;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 设备仓储接口(Domain层定义,Infrastructure层实现)
|
||||
* 这是领域层和基础设施层之间的契约
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
public interface DeviceRepository {
|
||||
|
||||
/**
|
||||
* 保存设备(新增或更新)
|
||||
*
|
||||
* @param device 设备领域模型
|
||||
* @return 保存后的设备
|
||||
*/
|
||||
Device save(Device device);
|
||||
|
||||
/**
|
||||
* 根据ID查询设备
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @return 设备领域模型
|
||||
*/
|
||||
Optional<Device> findById(Long id);
|
||||
|
||||
/**
|
||||
* 根据设备编码查询设备
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @return 设备领域模型
|
||||
*/
|
||||
Optional<Device> findByDeviceCode(String deviceCode);
|
||||
|
||||
/**
|
||||
* 查询所有设备
|
||||
*
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> findAll();
|
||||
|
||||
/**
|
||||
* 根据机场ID查询设备列表
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> findByAirportId(Long airportId);
|
||||
|
||||
/**
|
||||
* 根据设备状态查询设备列表
|
||||
*
|
||||
* @param status 设备状态
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> findByStatus(DeviceStatus status);
|
||||
|
||||
/**
|
||||
* 根据设备类型查询设备列表
|
||||
*
|
||||
* @param deviceType 设备类型
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> findByDeviceType(DeviceType deviceType);
|
||||
|
||||
/**
|
||||
* 根据机场ID和状态查询设备列表
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @param status 设备状态
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> findByAirportIdAndStatus(Long airportId, DeviceStatus status);
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*
|
||||
* @param id 设备ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
boolean deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 检查设备编码是否存在
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByDeviceCode(String deviceCode);
|
||||
|
||||
/**
|
||||
* 统计机场下的设备数量
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 设备数量
|
||||
*/
|
||||
long countByAirportId(Long airportId);
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
package com.tuoheng.airport.device.domain.service;
|
||||
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceStatus;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备领域服务接口(Domain层)
|
||||
* 封装设备相关的业务逻辑和业务规则
|
||||
*
|
||||
* Domain Service 的职责:
|
||||
* 1. 封装复杂的业务逻辑(跨多个聚合根的操作)
|
||||
* 2. 协调领域模型和仓储
|
||||
* 3. 保证业务规则的一致性
|
||||
* 4. 不包含事务管理(事务由 Application 层管理)
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
public interface DeviceDomainService {
|
||||
|
||||
/**
|
||||
* 注册新设备
|
||||
* 业务规则:
|
||||
* 1. 设备编码不能重复
|
||||
* 2. 新设备默认为停用状态
|
||||
* 3. 必须指定设备类型
|
||||
*
|
||||
* @param device 设备领域模型
|
||||
* @return 注册后的设备
|
||||
*/
|
||||
Device registerDevice(Device device);
|
||||
|
||||
/**
|
||||
* 激活设备
|
||||
* 业务规则:
|
||||
* 1. 只有停用或故障状态的设备才能激活
|
||||
* 2. 设备必须已分配到机场
|
||||
* 3. 设备固件版本不能为空
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 激活后的设备
|
||||
*/
|
||||
Device activateDevice(Long deviceId);
|
||||
|
||||
/**
|
||||
* 停用设备
|
||||
* 业务规则:
|
||||
* 1. 只有激活状态的设备才能停用
|
||||
* 2. 停用前需要检查设备是否正在执行任务
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 停用后的设备
|
||||
*/
|
||||
Device deactivateDevice(Long deviceId);
|
||||
|
||||
/**
|
||||
* 标记设备为故障状态
|
||||
* 业务规则:
|
||||
* 1. 任何状态的设备都可以标记为故障
|
||||
* 2. 故障设备自动停止执行任务
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param faultReason 故障原因
|
||||
* @return 标记后的设备
|
||||
*/
|
||||
Device markDeviceAsFaulty(Long deviceId, String faultReason);
|
||||
|
||||
/**
|
||||
* 更新设备固件版本
|
||||
* 业务规则:
|
||||
* 1. 只有停用状态的设备才能更新固件
|
||||
* 2. 新版本号必须大于当前版本号
|
||||
* 3. 更新固件后需要重新激活设备
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param newVersion 新固件版本
|
||||
* @return 更新后的设备
|
||||
*/
|
||||
Device updateFirmware(Long deviceId, String newVersion);
|
||||
|
||||
/**
|
||||
* 分配设备到机场
|
||||
* 业务规则:
|
||||
* 1. 设备必须是停用状态才能分配
|
||||
* 2. 机场必须存在且状态正常
|
||||
* 3. 检查机场的设备容量限制
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param airportId 机场ID
|
||||
* @return 分配后的设备
|
||||
*/
|
||||
Device assignToAirport(Long deviceId, Long airportId);
|
||||
|
||||
/**
|
||||
* 从机场移除设备
|
||||
* 业务规则:
|
||||
* 1. 设备必须是停用状态
|
||||
* 2. 设备不能有未完成的任务
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 移除后的设备
|
||||
*/
|
||||
Device removeFromAirport(Long deviceId);
|
||||
|
||||
/**
|
||||
* 查询设备详情
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 设备领域模型
|
||||
*/
|
||||
Device getDeviceById(Long deviceId);
|
||||
|
||||
/**
|
||||
* 根据设备编码查询设备
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @return 设备领域模型
|
||||
*/
|
||||
Device getDeviceByCode(String deviceCode);
|
||||
|
||||
/**
|
||||
* 查询机场下的可用设备列表
|
||||
* 业务规则:只返回激活状态的设备
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 可用设备列表
|
||||
*/
|
||||
List<Device> getAvailableDevicesByAirport(Long airportId);
|
||||
|
||||
/**
|
||||
* 查询指定类型的设备列表
|
||||
*
|
||||
* @param deviceType 设备类型
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> getDevicesByType(DeviceType deviceType);
|
||||
|
||||
/**
|
||||
* 查询指定状态的设备列表
|
||||
*
|
||||
* @param status 设备状态
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<Device> getDevicesByStatus(DeviceStatus status);
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
* 业务规则:
|
||||
* 1. 只能删除停用状态的设备
|
||||
* 2. 设备不能有历史任务记录(或者只是逻辑删除)
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
*/
|
||||
void deleteDevice(Long deviceId);
|
||||
|
||||
/**
|
||||
* 检查设备是否可以执行任务
|
||||
* 业务规则:
|
||||
* 1. 设备必须是激活状态
|
||||
* 2. 设备必须已分配到机场
|
||||
* 3. 设备固件版本必须是最新的
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 是否可以执行任务
|
||||
*/
|
||||
boolean canExecuteTask(Long deviceId);
|
||||
|
||||
/**
|
||||
* 统计机场下的设备数量
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 设备数量
|
||||
*/
|
||||
long countDevicesByAirport(Long airportId);
|
||||
}
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
package com.tuoheng.airport.device.domain.service.impl;
|
||||
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceStatus;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
import com.tuoheng.airport.device.domain.repository.DeviceRepository;
|
||||
import com.tuoheng.airport.device.domain.service.DeviceDomainService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 设备领域服务实现类(Domain层)
|
||||
* 封装设备相关的核心业务逻辑
|
||||
*
|
||||
* 职责:
|
||||
* 1. 实现业务规则和业务逻辑
|
||||
* 2. 调用 Repository 进行数据操作
|
||||
* 3. 协调领域模型完成复杂业务
|
||||
* 4. 不处理事务(事务由 Application 层管理)
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceDomainServiceImpl implements DeviceDomainService {
|
||||
|
||||
private final DeviceRepository deviceRepository;
|
||||
|
||||
@Override
|
||||
public Device registerDevice(Device device) {
|
||||
log.info("Domain: 开始注册设备,设备编码: {}", device.getDeviceCode());
|
||||
|
||||
// 业务规则1:检查设备编码是否已存在
|
||||
if (deviceRepository.existsByDeviceCode(device.getDeviceCode())) {
|
||||
throw new IllegalArgumentException("设备编码已存在: " + device.getDeviceCode());
|
||||
}
|
||||
|
||||
// 业务规则2:新设备默认为停用状态(在 Device.create() 工厂方法中已处理)
|
||||
// 业务规则3:必须指定设备类型(在 Device.create() 工厂方法中已验证)
|
||||
|
||||
// 持久化设备
|
||||
Device savedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备注册成功,设备ID: {}, 设备编码: {}",
|
||||
savedDevice.getId(), savedDevice.getDeviceCode());
|
||||
|
||||
return savedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device activateDevice(Long deviceId) {
|
||||
log.info("Domain: 开始激活设备,设备ID: {}", deviceId);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:只有停用或故障状态的设备才能激活(在 Device.activate() 中验证)
|
||||
|
||||
// 业务规则2:设备必须已分配到机场
|
||||
if (device.getAirportId() == null) {
|
||||
throw new IllegalStateException("设备未分配到机场,无法激活");
|
||||
}
|
||||
|
||||
// 业务规则3:设备固件版本不能为空
|
||||
if (device.getFirmwareVersion() == null || device.getFirmwareVersion().trim().isEmpty()) {
|
||||
throw new IllegalStateException("设备固件版本为空,无法激活");
|
||||
}
|
||||
|
||||
// 调用领域模型的业务方法
|
||||
device.activate();
|
||||
|
||||
// 持久化
|
||||
Device updatedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备激活成功,设备ID: {}, 当前状态: {}",
|
||||
deviceId, updatedDevice.getStatus());
|
||||
|
||||
return updatedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device deactivateDevice(Long deviceId) {
|
||||
log.info("Domain: 开始停用设备,设备ID: {}", deviceId);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:只有激活状态的设备才能停用(在 Device.deactivate() 中验证)
|
||||
|
||||
// 业务规则2:停用前需要检查设备是否正在执行任务
|
||||
// TODO: 这里应该调用任务领域服务检查设备是否有正在执行的任务
|
||||
// 示例:if (taskDomainService.hasRunningTask(deviceId)) { throw ... }
|
||||
|
||||
// 调用领域模型的业务方法
|
||||
device.deactivate();
|
||||
|
||||
// 持久化
|
||||
Device updatedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备停用成功,设备ID: {}, 当前状态: {}",
|
||||
deviceId, updatedDevice.getStatus());
|
||||
|
||||
return updatedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device markDeviceAsFaulty(Long deviceId, String faultReason) {
|
||||
log.info("Domain: 标记设备为故障状态,设备ID: {}, 故障原因: {}", deviceId, faultReason);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:任何状态的设备都可以标记为故障
|
||||
// 业务规则2:故障设备自动停止执行任务
|
||||
// TODO: 这里应该调用任务领域服务停止设备的所有任务
|
||||
// 示例:taskDomainService.stopAllTasksByDevice(deviceId);
|
||||
|
||||
// 调用领域模型的业务方法
|
||||
device.markAsFaulty();
|
||||
|
||||
// 记录故障原因到备注
|
||||
String remark = device.getRemark() != null ? device.getRemark() : "";
|
||||
device.setRemark(remark + " [故障原因: " + faultReason + "]");
|
||||
|
||||
// 持久化
|
||||
Device updatedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备已标记为故障状态,设备ID: {}", deviceId);
|
||||
|
||||
return updatedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device updateFirmware(Long deviceId, String newVersion) {
|
||||
log.info("Domain: 更新设备固件版本,设备ID: {}, 新版本: {}", deviceId, newVersion);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:只有停用状态的设备才能更新固件
|
||||
if (device.getStatus() != DeviceStatus.INACTIVE) {
|
||||
throw new IllegalStateException("只有停用状态的设备才能更新固件,当前状态: " + device.getStatus());
|
||||
}
|
||||
|
||||
// 业务规则2:新版本号必须大于当前版本号
|
||||
if (device.getFirmwareVersion() != null &&
|
||||
compareVersion(newVersion, device.getFirmwareVersion()) <= 0) {
|
||||
throw new IllegalArgumentException("新版本号必须大于当前版本号");
|
||||
}
|
||||
|
||||
// 调用领域模型的业务方法
|
||||
device.updateFirmware(newVersion);
|
||||
|
||||
// 持久化
|
||||
Device updatedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备固件版本更新成功,设备ID: {}, 新版本: {}", deviceId, newVersion);
|
||||
|
||||
return updatedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device assignToAirport(Long deviceId, Long airportId) {
|
||||
log.info("Domain: 分配设备到机场,设备ID: {}, 机场ID: {}", deviceId, airportId);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:设备必须是停用状态才能分配
|
||||
if (device.getStatus() != DeviceStatus.INACTIVE) {
|
||||
throw new IllegalStateException("只有停用状态的设备才能分配到机场,当前状态: " + device.getStatus());
|
||||
}
|
||||
|
||||
// 业务规则2:机场必须存在且状态正常
|
||||
// TODO: 这里应该调用机场领域服务验证机场状态
|
||||
// 示例:airportDomainService.validateAirportAvailable(airportId);
|
||||
|
||||
// 业务规则3:检查机场的设备容量限制
|
||||
long deviceCount = deviceRepository.countByAirportId(airportId);
|
||||
final int MAX_DEVICES_PER_AIRPORT = 100; // 示例:每个机场最多100台设备
|
||||
if (deviceCount >= MAX_DEVICES_PER_AIRPORT) {
|
||||
throw new IllegalStateException("机场设备数量已达上限,无法分配新设备");
|
||||
}
|
||||
|
||||
// 调用领域模型的业务方法
|
||||
device.assignToAirport(airportId);
|
||||
|
||||
// 持久化
|
||||
Device updatedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备分配成功,设备ID: {}, 机场ID: {}", deviceId, airportId);
|
||||
|
||||
return updatedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device removeFromAirport(Long deviceId) {
|
||||
log.info("Domain: 从机场移除设备,设备ID: {}", deviceId);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:设备必须是停用状态
|
||||
if (device.getStatus() != DeviceStatus.INACTIVE) {
|
||||
throw new IllegalStateException("只有停用状态的设备才能从机场移除,当前状态: " + device.getStatus());
|
||||
}
|
||||
|
||||
// 业务规则2:设备不能有未完成的任务
|
||||
// TODO: 这里应该调用任务领域服务检查
|
||||
// 示例:if (taskDomainService.hasPendingTask(deviceId)) { throw ... }
|
||||
|
||||
// 移除机场分配
|
||||
device.setAirportId(null);
|
||||
|
||||
// 持久化
|
||||
Device updatedDevice = deviceRepository.save(device);
|
||||
|
||||
log.info("Domain: 设备已从机场移除,设备ID: {}", deviceId);
|
||||
|
||||
return updatedDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDeviceById(Long deviceId) {
|
||||
log.debug("Domain: 查询设备,设备ID: {}", deviceId);
|
||||
return deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDeviceByCode(String deviceCode) {
|
||||
log.debug("Domain: 查询设备,设备编码: {}", deviceCode);
|
||||
return deviceRepository.findByDeviceCode(deviceCode)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,设备编码: " + deviceCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getAvailableDevicesByAirport(Long airportId) {
|
||||
log.debug("Domain: 查询机场下的可用设备,机场ID: {}", airportId);
|
||||
|
||||
// 业务规则:只返回激活状态的设备
|
||||
return deviceRepository.findByAirportIdAndStatus(airportId, DeviceStatus.ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getDevicesByType(DeviceType deviceType) {
|
||||
log.debug("Domain: 查询指定类型的设备,设备类型: {}", deviceType);
|
||||
return deviceRepository.findByDeviceType(deviceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getDevicesByStatus(DeviceStatus status) {
|
||||
log.debug("Domain: 查询指定状态的设备,设备状态: {}", status);
|
||||
return deviceRepository.findByStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteDevice(Long deviceId) {
|
||||
log.info("Domain: 删除设备,设备ID: {}", deviceId);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:只能删除停用状态的设备
|
||||
if (device.getStatus() != DeviceStatus.INACTIVE) {
|
||||
throw new IllegalStateException("只能删除停用状态的设备,当前状态: " + device.getStatus());
|
||||
}
|
||||
|
||||
// 业务规则2:设备不能有历史任务记录(这里使用逻辑删除,所以可以保留历史记录)
|
||||
// TODO: 如果需要物理删除,应该检查任务记录
|
||||
// 示例:if (taskDomainService.hasHistoryTask(deviceId)) { throw ... }
|
||||
|
||||
// 删除设备(逻辑删除)
|
||||
boolean deleted = deviceRepository.deleteById(deviceId);
|
||||
|
||||
if (!deleted) {
|
||||
throw new IllegalStateException("设备删除失败,ID: " + deviceId);
|
||||
}
|
||||
|
||||
log.info("Domain: 设备删除成功,设备ID: {}", deviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExecuteTask(Long deviceId) {
|
||||
log.debug("Domain: 检查设备是否可以执行任务,设备ID: {}", deviceId);
|
||||
|
||||
// 查询设备
|
||||
Device device = deviceRepository.findById(deviceId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("设备不存在,ID: " + deviceId));
|
||||
|
||||
// 业务规则1:设备必须是激活状态
|
||||
if (device.getStatus() != DeviceStatus.ACTIVE) {
|
||||
log.debug("设备状态不是激活状态: {}", device.getStatus());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 业务规则2:设备必须已分配到机场
|
||||
if (device.getAirportId() == null) {
|
||||
log.debug("设备未分配到机场");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 业务规则3:设备固件版本必须是最新的
|
||||
// TODO: 这里应该检查固件版本是否是最新的
|
||||
// 示例:String latestVersion = firmwareService.getLatestVersion(device.getDeviceType());
|
||||
// if (!device.getFirmwareVersion().equals(latestVersion)) { return false; }
|
||||
|
||||
// 调用领域模型的业务方法
|
||||
return device.canExecuteTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countDevicesByAirport(Long airportId) {
|
||||
log.debug("Domain: 统计机场下的设备数量,机场ID: {}", airportId);
|
||||
return deviceRepository.countByAirportId(airportId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较版本号
|
||||
* 返回值:1 表示 v1 > v2,0 表示 v1 = v2,-1 表示 v1 < v2
|
||||
*/
|
||||
private int compareVersion(String v1, String v2) {
|
||||
String[] parts1 = v1.split("\\.");
|
||||
String[] parts2 = v2.split("\\.");
|
||||
int maxLength = Math.max(parts1.length, parts2.length);
|
||||
|
||||
for (int i = 0; i < maxLength; i++) {
|
||||
int num1 = i < parts1.length ? Integer.parseInt(parts1[i]) : 0;
|
||||
int num2 = i < parts2.length ? Integer.parseInt(parts2[i]) : 0;
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1;
|
||||
} else if (num1 < num2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.tuoheng.airport.device.infrastructure.persistence.converter;
|
||||
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceStatus;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
import com.tuoheng.airport.device.infrastructure.persistence.entity.DeviceEntity;
|
||||
|
||||
/**
|
||||
* 设备领域模型与数据库实体转换器
|
||||
* 负责 Domain 层和 Infrastructure 层之间的对象转换
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
public class DeviceConverter {
|
||||
|
||||
/**
|
||||
* 领域模型转数据库实体
|
||||
*
|
||||
* @param device 领域模型
|
||||
* @return 数据库实体
|
||||
*/
|
||||
public static DeviceEntity toEntity(Device device) {
|
||||
if (device == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DeviceEntity.builder()
|
||||
.id(device.getId())
|
||||
.deviceCode(device.getDeviceCode())
|
||||
.deviceName(device.getDeviceName())
|
||||
.deviceType(device.getDeviceType() != null ? device.getDeviceType().getCode() : null)
|
||||
.status(device.getStatus() != null ? device.getStatus().getCode() : null)
|
||||
.airportId(device.getAirportId())
|
||||
.manufacturer(device.getManufacturer())
|
||||
.firmwareVersion(device.getFirmwareVersion())
|
||||
.createTime(device.getCreateTime())
|
||||
.updateTime(device.getUpdateTime())
|
||||
.remark(device.getRemark())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库实体转领域模型
|
||||
*
|
||||
* @param entity 数据库实体
|
||||
* @return 领域模型
|
||||
*/
|
||||
public static Device toDomain(DeviceEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Device.builder()
|
||||
.id(entity.getId())
|
||||
.deviceCode(entity.getDeviceCode())
|
||||
.deviceName(entity.getDeviceName())
|
||||
.deviceType(DeviceType.fromCode(entity.getDeviceType()))
|
||||
.status(DeviceStatus.fromCode(entity.getStatus()))
|
||||
.airportId(entity.getAirportId())
|
||||
.manufacturer(entity.getManufacturer())
|
||||
.firmwareVersion(entity.getFirmwareVersion())
|
||||
.createTime(entity.getCreateTime())
|
||||
.updateTime(entity.getUpdateTime())
|
||||
.remark(entity.getRemark())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package com.tuoheng.airport.device.infrastructure.persistence.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备数据库实体(Infrastructure层)
|
||||
* 对应数据库表 th_device
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("th_device")
|
||||
public class DeviceEntity {
|
||||
|
||||
/**
|
||||
* 主键ID(自增)
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备编码(唯一)
|
||||
*/
|
||||
@TableField("device_code")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@TableField("device_name")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型(1:多旋翼 2:固定翼 3:垂直起降 4:摄像头 5:喇叭 6:探照灯)
|
||||
*/
|
||||
@TableField("device_type")
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 设备状态(0:停用 1:激活 2:故障 3:维护中)
|
||||
*/
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
@TableField("airport_id")
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
@TableField("manufacturer")
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
@TableField("firmware_version")
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 创建时间(自动填充)
|
||||
*/
|
||||
@TableField(value = "create_time", fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间(自动填充)
|
||||
*/
|
||||
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 逻辑删除标记(0:未删除 1:已删除)
|
||||
*/
|
||||
@TableLogic
|
||||
@TableField("is_deleted")
|
||||
private Integer isDeleted;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tuoheng.airport.device.infrastructure.persistence.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tuoheng.airport.device.infrastructure.persistence.entity.DeviceEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备Mapper接口(Infrastructure层)
|
||||
* 使用 MyBatis Plus 提供基础 CRUD 能力
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Mapper
|
||||
public interface DeviceMapper extends BaseMapper<DeviceEntity> {
|
||||
|
||||
/**
|
||||
* 根据机场ID和状态查询设备列表
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @param status 设备状态
|
||||
* @return 设备实体列表
|
||||
*/
|
||||
List<DeviceEntity> selectByAirportIdAndStatus(@Param("airportId") Long airportId,
|
||||
@Param("status") Integer status);
|
||||
|
||||
/**
|
||||
* 统计机场下的设备数量
|
||||
*
|
||||
* @param airportId 机场ID
|
||||
* @return 设备数量
|
||||
*/
|
||||
Long countByAirportId(@Param("airportId") Long airportId);
|
||||
|
||||
/**
|
||||
* 批量更新设备状态
|
||||
*
|
||||
* @param deviceIds 设备ID列表
|
||||
* @param status 目标状态
|
||||
* @return 更新数量
|
||||
*/
|
||||
int batchUpdateStatus(@Param("deviceIds") List<Long> deviceIds,
|
||||
@Param("status") Integer status);
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.tuoheng.airport.device.infrastructure.persistence.repository;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.tuoheng.airport.device.domain.model.Device;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceStatus;
|
||||
import com.tuoheng.airport.device.domain.model.DeviceType;
|
||||
import com.tuoheng.airport.device.domain.repository.DeviceRepository;
|
||||
import com.tuoheng.airport.device.infrastructure.persistence.converter.DeviceConverter;
|
||||
import com.tuoheng.airport.device.infrastructure.persistence.entity.DeviceEntity;
|
||||
import com.tuoheng.airport.device.infrastructure.persistence.mapper.DeviceMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 设备仓储实现类(Infrastructure层)
|
||||
* 实现 Domain 层定义的 DeviceRepository 接口
|
||||
* 负责数据持久化和查询
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceRepositoryImpl implements DeviceRepository {
|
||||
|
||||
private final DeviceMapper deviceMapper;
|
||||
|
||||
@Override
|
||||
public Device save(Device device) {
|
||||
DeviceEntity entity = DeviceConverter.toEntity(device);
|
||||
|
||||
if (entity.getId() == null) {
|
||||
// 新增
|
||||
deviceMapper.insert(entity);
|
||||
} else {
|
||||
// 更新
|
||||
deviceMapper.updateById(entity);
|
||||
}
|
||||
|
||||
// 返回保存后的领域模型(包含生成的ID)
|
||||
device.setId(entity.getId());
|
||||
return device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Device> findById(Long id) {
|
||||
DeviceEntity entity = deviceMapper.selectById(id);
|
||||
return Optional.ofNullable(DeviceConverter.toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Device> findByDeviceCode(String deviceCode) {
|
||||
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DeviceEntity::getDeviceCode, deviceCode);
|
||||
DeviceEntity entity = deviceMapper.selectOne(wrapper);
|
||||
return Optional.ofNullable(DeviceConverter.toDomain(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> findAll() {
|
||||
List<DeviceEntity> entities = deviceMapper.selectList(null);
|
||||
return entities.stream()
|
||||
.map(DeviceConverter::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> findByAirportId(Long airportId) {
|
||||
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DeviceEntity::getAirportId, airportId)
|
||||
.orderByDesc(DeviceEntity::getCreateTime);
|
||||
List<DeviceEntity> entities = deviceMapper.selectList(wrapper);
|
||||
return entities.stream()
|
||||
.map(DeviceConverter::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> findByStatus(DeviceStatus status) {
|
||||
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DeviceEntity::getStatus, status.getCode())
|
||||
.orderByDesc(DeviceEntity::getCreateTime);
|
||||
List<DeviceEntity> entities = deviceMapper.selectList(wrapper);
|
||||
return entities.stream()
|
||||
.map(DeviceConverter::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> findByDeviceType(DeviceType deviceType) {
|
||||
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DeviceEntity::getDeviceType, deviceType.getCode())
|
||||
.orderByDesc(DeviceEntity::getCreateTime);
|
||||
List<DeviceEntity> entities = deviceMapper.selectList(wrapper);
|
||||
return entities.stream()
|
||||
.map(DeviceConverter::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> findByAirportIdAndStatus(Long airportId, DeviceStatus status) {
|
||||
List<DeviceEntity> entities = deviceMapper.selectByAirportIdAndStatus(
|
||||
airportId, status.getCode());
|
||||
return entities.stream()
|
||||
.map(DeviceConverter::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteById(Long id) {
|
||||
// 使用逻辑删除
|
||||
return deviceMapper.deleteById(id) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsByDeviceCode(String deviceCode) {
|
||||
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DeviceEntity::getDeviceCode, deviceCode);
|
||||
return deviceMapper.selectCount(wrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAirportId(Long airportId) {
|
||||
return deviceMapper.countByAirportId(airportId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
package com.tuoheng.airport.device.presentation.controller;
|
||||
|
||||
import com.tuoheng.airport.device.application.dto.*;
|
||||
import com.tuoheng.airport.device.application.service.DeviceApplicationService;
|
||||
import com.tuoheng.airport.device.presentation.converter.DeviceVoConverter;
|
||||
import com.tuoheng.airport.device.presentation.vo.*;
|
||||
import com.tuoheng.common.response.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 设备控制器(Presentation层)
|
||||
* 提供设备管理的 REST API 接口
|
||||
* 负责接收 HTTP 请求,调用 Application 层服务,返回统一响应格式
|
||||
*
|
||||
* 职责:
|
||||
* 1. 接收前端的 VO 对象
|
||||
* 2. 将 VO 转换为 DTO 传递给 Application 层
|
||||
* 3. 将 Application 层返回的 DTO 转换为 VO 返回给前端
|
||||
* 4. 不包含任何业务逻辑
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/devices")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
@Tag(name = "设备管理", description = "设备管理相关接口")
|
||||
public class DeviceController {
|
||||
|
||||
private final DeviceApplicationService deviceApplicationService;
|
||||
|
||||
/**
|
||||
* 创建设备
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建设备", description = "创建新的设备记录")
|
||||
public Result<DeviceVO> createDevice(@Valid @RequestBody DeviceCreateVO vo) {
|
||||
log.info("接收到创建设备请求: {}", vo);
|
||||
// VO 转 DTO
|
||||
DeviceCreateRequest request = DeviceVoConverter.toCreateRequest(vo);
|
||||
// 调用 Application 层
|
||||
DeviceResponse response = deviceApplicationService.createDevice(request);
|
||||
// DTO 转 VO
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备信息
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新设备信息", description = "更新指定设备的基本信息")
|
||||
public Result<DeviceVO> updateDevice(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id,
|
||||
@Valid @RequestBody DeviceUpdateVO vo) {
|
||||
log.info("接收到更新设备请求,设备ID: {}, 请求参数: {}", id, vo);
|
||||
vo.setId(id);
|
||||
// VO 转 DTO
|
||||
DeviceUpdateRequest request = DeviceVoConverter.toUpdateRequest(vo);
|
||||
// 调用 Application 层
|
||||
DeviceResponse response = deviceApplicationService.updateDevice(request);
|
||||
// DTO 转 VO
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询设备
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "查询设备详情", description = "根据设备ID查询设备详细信息")
|
||||
public Result<DeviceVO> getDeviceById(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id) {
|
||||
log.info("接收到查询设备请求,设备ID: {}", id);
|
||||
DeviceResponse response = deviceApplicationService.getDeviceById(id);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备编码查询设备
|
||||
*/
|
||||
@GetMapping("/code/{deviceCode}")
|
||||
@Operation(summary = "根据编码查询设备", description = "根据设备编码查询设备详细信息")
|
||||
public Result<DeviceVO> getDeviceByCode(
|
||||
@Parameter(description = "设备编码") @PathVariable String deviceCode) {
|
||||
log.info("接收到查询设备请求,设备编码: {}", deviceCode);
|
||||
DeviceResponse response = deviceApplicationService.getDeviceByCode(deviceCode);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有设备
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(summary = "查询设备列表", description = "查询所有设备或根据条件筛选设备")
|
||||
public Result<List<DeviceVO>> queryDevices(DeviceQueryVO vo) {
|
||||
log.info("接收到查询设备列表请求,查询条件: {}", vo);
|
||||
// VO 转 DTO
|
||||
DeviceQueryRequest request = DeviceVoConverter.toQueryRequest(vo);
|
||||
// 调用 Application 层
|
||||
List<DeviceResponse> responses = deviceApplicationService.queryDevices(request);
|
||||
// DTO 列表转 VO 列表
|
||||
List<DeviceVO> results = responses.stream()
|
||||
.map(DeviceVoConverter::toVO)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(results);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据机场ID查询设备列表
|
||||
*/
|
||||
@GetMapping("/airport/{airportId}")
|
||||
@Operation(summary = "查询机场设备", description = "查询指定机场下的所有设备")
|
||||
public Result<List<DeviceVO>> getDevicesByAirportId(
|
||||
@Parameter(description = "机场ID") @PathVariable Long airportId) {
|
||||
log.info("接收到查询机场设备列表请求,机场ID: {}", airportId);
|
||||
List<DeviceResponse> responses = deviceApplicationService.getDevicesByAirportId(airportId);
|
||||
List<DeviceVO> results = responses.stream()
|
||||
.map(DeviceVoConverter::toVO)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(results);
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活设备
|
||||
*/
|
||||
@PostMapping("/{id}/activate")
|
||||
@Operation(summary = "激活设备", description = "将设备状态设置为激活")
|
||||
public Result<DeviceVO> activateDevice(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id) {
|
||||
log.info("接收到激活设备请求,设备ID: {}", id);
|
||||
DeviceResponse response = deviceApplicationService.activateDevice(id);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用设备
|
||||
*/
|
||||
@PostMapping("/{id}/deactivate")
|
||||
@Operation(summary = "停用设备", description = "将设备状态设置为停用")
|
||||
public Result<DeviceVO> deactivateDevice(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id) {
|
||||
log.info("接收到停用设备请求,设备ID: {}", id);
|
||||
DeviceResponse response = deviceApplicationService.deactivateDevice(id);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记设备为故障状态
|
||||
*/
|
||||
@PostMapping("/{id}/faulty")
|
||||
@Operation(summary = "标记设备故障", description = "将设备状态标记为故障")
|
||||
public Result<DeviceVO> markDeviceAsFaulty(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id) {
|
||||
log.info("接收到标记设备故障请求,设备ID: {}", id);
|
||||
DeviceResponse response = deviceApplicationService.markDeviceAsFaulty(id);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备固件版本
|
||||
*/
|
||||
@PostMapping("/{id}/firmware")
|
||||
@Operation(summary = "更新固件版本", description = "更新设备的固件版本")
|
||||
public Result<DeviceVO> updateDeviceFirmware(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id,
|
||||
@Parameter(description = "新固件版本") @RequestParam @NotBlank(message = "固件版本不能为空") String version) {
|
||||
log.info("接收到更新设备固件请求,设备ID: {}, 新版本: {}", id, version);
|
||||
DeviceResponse response = deviceApplicationService.updateDeviceFirmware(id, version);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配设备到机场
|
||||
*/
|
||||
@PostMapping("/{id}/assign")
|
||||
@Operation(summary = "分配设备到机场", description = "将设备分配到指定机场")
|
||||
public Result<DeviceVO> assignDeviceToAirport(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id,
|
||||
@Parameter(description = "机场ID") @RequestParam @NotNull(message = "机场ID不能为空") Long airportId) {
|
||||
log.info("接收到分配设备到机场请求,设备ID: {}, 机场ID: {}", id, airportId);
|
||||
DeviceResponse response = deviceApplicationService.assignDeviceToAirport(id, airportId);
|
||||
DeviceVO result = DeviceVoConverter.toVO(response);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除设备", description = "删除指定的设备(逻辑删除)")
|
||||
public Result<Void> deleteDevice(
|
||||
@Parameter(description = "设备ID") @PathVariable Long id) {
|
||||
log.info("接收到删除设备请求,设备ID: {}", id);
|
||||
deviceApplicationService.deleteDevice(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计机场下的设备数量
|
||||
*/
|
||||
@GetMapping("/airport/{airportId}/count")
|
||||
@Operation(summary = "统计机场设备数量", description = "统计指定机场下的设备总数")
|
||||
public Result<Long> countDevicesByAirportId(
|
||||
@Parameter(description = "机场ID") @PathVariable Long airportId) {
|
||||
log.info("接收到统计机场设备数量请求,机场ID: {}", airportId);
|
||||
long count = deviceApplicationService.countDevicesByAirportId(airportId);
|
||||
return Result.success(count);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tuoheng.airport.device.presentation.converter;
|
||||
|
||||
import com.tuoheng.airport.device.application.dto.*;
|
||||
import com.tuoheng.airport.device.presentation.vo.*;
|
||||
|
||||
/**
|
||||
* VO 和 DTO 转换器(Presentation层)
|
||||
* 负责 Presentation 层的 VO 和 Application 层的 DTO 之间的转换
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
public class DeviceVoConverter {
|
||||
|
||||
/**
|
||||
* 创建请求VO转DTO
|
||||
*/
|
||||
public static DeviceCreateRequest toCreateRequest(DeviceCreateVO vo) {
|
||||
if (vo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DeviceCreateRequest dto = new DeviceCreateRequest();
|
||||
dto.setDeviceCode(vo.getDeviceCode());
|
||||
dto.setDeviceName(vo.getDeviceName());
|
||||
dto.setDeviceType(vo.getDeviceType());
|
||||
dto.setManufacturer(vo.getManufacturer());
|
||||
dto.setAirportId(vo.getAirportId());
|
||||
dto.setFirmwareVersion(vo.getFirmwareVersion());
|
||||
dto.setRemark(vo.getRemark());
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新请求VO转DTO
|
||||
*/
|
||||
public static DeviceUpdateRequest toUpdateRequest(DeviceUpdateVO vo) {
|
||||
if (vo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DeviceUpdateRequest dto = new DeviceUpdateRequest();
|
||||
dto.setId(vo.getId());
|
||||
dto.setDeviceName(vo.getDeviceName());
|
||||
dto.setManufacturer(vo.getManufacturer());
|
||||
dto.setAirportId(vo.getAirportId());
|
||||
dto.setFirmwareVersion(vo.getFirmwareVersion());
|
||||
dto.setRemark(vo.getRemark());
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询请求VO转DTO
|
||||
*/
|
||||
public static DeviceQueryRequest toQueryRequest(DeviceQueryVO vo) {
|
||||
if (vo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DeviceQueryRequest dto = new DeviceQueryRequest();
|
||||
dto.setDeviceCode(vo.getDeviceCode());
|
||||
dto.setDeviceName(vo.getDeviceName());
|
||||
dto.setDeviceType(vo.getDeviceType());
|
||||
dto.setStatus(vo.getStatus());
|
||||
dto.setAirportId(vo.getAirportId());
|
||||
dto.setManufacturer(vo.getManufacturer());
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应DTO转VO
|
||||
*/
|
||||
public static DeviceVO toVO(DeviceResponse dto) {
|
||||
if (dto == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DeviceVO.builder()
|
||||
.id(dto.getId())
|
||||
.deviceCode(dto.getDeviceCode())
|
||||
.deviceName(dto.getDeviceName())
|
||||
.deviceType(dto.getDeviceType())
|
||||
.deviceTypeDesc(dto.getDeviceTypeDesc())
|
||||
.status(dto.getStatus())
|
||||
.statusDesc(dto.getStatusDesc())
|
||||
.airportId(dto.getAirportId())
|
||||
.manufacturer(dto.getManufacturer())
|
||||
.firmwareVersion(dto.getFirmwareVersion())
|
||||
.createTime(dto.getCreateTime())
|
||||
.updateTime(dto.getUpdateTime())
|
||||
.remark(dto.getRemark())
|
||||
.canExecuteTask(dto.getCanExecuteTask())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tuoheng.airport.device.presentation.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 设备创建请求VO(Presentation层)
|
||||
* 用于接收前端创建设备的请求参数
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
public class DeviceCreateVO {
|
||||
|
||||
/**
|
||||
* 设备编码(必填,唯一)
|
||||
*/
|
||||
@NotBlank(message = "设备编码不能为空")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称(必填)
|
||||
*/
|
||||
@NotBlank(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型(必填)
|
||||
* 1:多旋翼 2:固定翼 3:垂直起降 4:摄像头 5:喇叭 6:探照灯
|
||||
*/
|
||||
@NotNull(message = "设备类型不能为空")
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tuoheng.airport.device.presentation.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 设备查询请求VO(Presentation层)
|
||||
* 用于接收前端查询设备的请求参数
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
public class DeviceQueryVO {
|
||||
|
||||
/**
|
||||
* 设备编码(模糊查询)
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称(模糊查询)
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tuoheng.airport.device.presentation.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 设备更新请求VO(Presentation层)
|
||||
* 用于接收前端更新设备的请求参数
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
public class DeviceUpdateVO {
|
||||
|
||||
/**
|
||||
* 设备ID(必填)
|
||||
*/
|
||||
@NotNull(message = "设备ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tuoheng.airport.device.presentation.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备响应VO(Presentation层)
|
||||
* 用于返回给前端的设备信息
|
||||
*
|
||||
* @author tuoheng
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeviceVO {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型代码
|
||||
*/
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 设备类型描述
|
||||
*/
|
||||
private String deviceTypeDesc;
|
||||
|
||||
/**
|
||||
* 设备状态代码
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 设备状态描述
|
||||
*/
|
||||
private String statusDesc;
|
||||
|
||||
/**
|
||||
* 所属机场ID
|
||||
*/
|
||||
private Long airportId;
|
||||
|
||||
/**
|
||||
* 制造商
|
||||
*/
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String firmwareVersion;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 是否可以执行任务
|
||||
*/
|
||||
private Boolean canExecuteTask;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?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="com.tuoheng.airport.device.infrastructure.persistence.mapper.DeviceMapper">
|
||||
|
||||
<!-- 结果映射 -->
|
||||
<resultMap id="BaseResultMap" type="com.tuoheng.airport.device.infrastructure.persistence.entity.DeviceEntity">
|
||||
<id column="id" property="id"/>
|
||||
<result column="device_code" property="deviceCode"/>
|
||||
<result column="device_name" property="deviceName"/>
|
||||
<result column="device_type" property="deviceType"/>
|
||||
<result column="status" property="status"/>
|
||||
<result column="airport_id" property="airportId"/>
|
||||
<result column="manufacturer" property="manufacturer"/>
|
||||
<result column="firmware_version" property="firmwareVersion"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="remark" property="remark"/>
|
||||
<result column="is_deleted" property="isDeleted"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 根据机场ID和状态查询设备列表 -->
|
||||
<select id="selectByAirportIdAndStatus" resultMap="BaseResultMap">
|
||||
SELECT *
|
||||
FROM th_device
|
||||
WHERE is_deleted = 0
|
||||
AND airport_id = #{airportId}
|
||||
AND status = #{status}
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 统计机场下的设备数量 -->
|
||||
<select id="countByAirportId" resultType="java.lang.Long">
|
||||
SELECT COUNT(*)
|
||||
FROM th_device
|
||||
WHERE is_deleted = 0
|
||||
AND airport_id = #{airportId}
|
||||
</select>
|
||||
|
||||
<!-- 批量更新设备状态 -->
|
||||
<update id="batchUpdateStatus">
|
||||
UPDATE th_device
|
||||
SET status = #{status},
|
||||
update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="deviceIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND is_deleted = 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
-- =============================================
|
||||
-- 设备管理表结构
|
||||
-- 用于 tuoheng-ddd 项目的 device 子域
|
||||
-- =============================================
|
||||
|
||||
-- 创建设备表
|
||||
DROP TABLE IF EXISTS `th_device`;
|
||||
CREATE TABLE `th_device` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`device_code` VARCHAR(64) NOT NULL COMMENT '设备编码(唯一标识)',
|
||||
`device_name` VARCHAR(128) NOT NULL COMMENT '设备名称',
|
||||
`device_type` TINYINT(2) NOT NULL COMMENT '设备类型(1:多旋翼 2:固定翼 3:垂直起降 4:摄像头 5:喇叭 6:探照灯)',
|
||||
`status` TINYINT(2) NOT NULL DEFAULT 0 COMMENT '设备状态(0:停用 1:激活 2:故障 3:维护中)',
|
||||
`airport_id` BIGINT(20) DEFAULT NULL COMMENT '所属机场ID',
|
||||
`manufacturer` VARCHAR(128) DEFAULT NULL COMMENT '制造商',
|
||||
`firmware_version` VARCHAR(64) DEFAULT NULL COMMENT '固件版本',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`remark` VARCHAR(512) DEFAULT NULL COMMENT '备注',
|
||||
`is_deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记(0:未删除 1:已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_device_code` (`device_code`),
|
||||
KEY `idx_airport_id` (`airport_id`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_device_type` (`device_type`),
|
||||
KEY `idx_create_time` (`create_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备表';
|
||||
|
||||
-- 插入测试数据
|
||||
INSERT INTO `th_device` (`device_code`, `device_name`, `device_type`, `status`, `airport_id`, `manufacturer`, `firmware_version`, `remark`) VALUES
|
||||
('DRONE-001', '多旋翼无人机-01', 1, 1, 1, 'DJI', 'v1.2.3', '测试设备1'),
|
||||
('DRONE-002', '固定翼无人机-01', 2, 0, 1, 'DJI', 'v1.0.0', '测试设备2'),
|
||||
('DRONE-003', '垂直起降无人机-01', 3, 1, 2, 'DJI', 'v2.0.1', '测试设备3'),
|
||||
('CAMERA-001', '可见光摄像头-01', 4, 1, 1, 'Sony', 'v1.5.0', '测试摄像头1'),
|
||||
('MEGAPHONE-001', '喇叭设备-01', 5, 1, 2, 'Generic', 'v1.0.0', '测试喇叭1'),
|
||||
('SEARCHLIGHT-001', '探照灯设备-01', 6, 0, 1, 'Generic', 'v1.0.0', '测试探照灯1');
|
||||
Loading…
Reference in New Issue