提交航线管理逻辑和接口

This commit is contained in:
高大 2026-01-23 18:42:11 +08:00
parent a11dd15ce8
commit afdc3056ec
88 changed files with 5661 additions and 60 deletions

24
pom.xml
View File

@ -70,13 +70,35 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-log</artifactId> <artifactId>ruoyi-common-log</artifactId>
</dependency> </dependency>
<!-- xml文件转化 -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.20</version>
</dependency>
<!-- RuoYi Common Swagger --> <!-- RuoYi Common Swagger -->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-swagger</artifactId> <artifactId>ruoyi-common-swagger</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules-file</artifactId>
<version>3.6.7</version>
</dependency>
<!-- Flyway Database Migration --> <!-- Flyway Database Migration -->
<dependency> <dependency>
<groupId>org.flywaydb</groupId> <groupId>org.flywaydb</groupId>

View File

@ -1,32 +0,0 @@
package com.ruoyi.airline;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.ruoyi.common.security.annotation.EnableCustomConfig;
import com.ruoyi.common.security.annotation.EnableRyFeignClients;
/**
* 系统模块
*
* @author ruoyi
*/
@EnableCustomConfig
@EnableRyFeignClients
@SpringBootApplication
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
System.out.println("(♥◠‿◠)ノ゙ 系统模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.airline;
import com.ruoyi.common.security.annotation.EnableCustomConfig;
import com.ruoyi.common.security.annotation.EnableRyFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 航线模块应用启动类
*
* @author ruoyi
* @date 2026-01-17
*/
@SpringBootApplication
@EnableCustomConfig
@EnableRyFeignClients
public class TuohengAirlineApplication {
public static void main(String[] args) {
SpringApplication.run(TuohengAirlineApplication.class, args);
}
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.airline.controller;
import com.ruoyi.airline.api.domain.AirlineDataVO;
import com.ruoyi.airline.service.api.IAirlineDataService;
import com.ruoyi.airline.service.dto.AirlineDataDTO;
import com.ruoyi.airline.controller.convert.AirlineDataControllerConvert;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 航线数据Controller
*
* @author ruoyi
* @date 2026-01-17
*/
@RestController
@RequestMapping("/airline/data")
public class AirlineDataController extends BaseController
{
@Autowired
private IAirlineDataService airlineDataService;
/**
* 查询航线数据列表
*/
@RequiresPermissions("system:dept:query")
@GetMapping()
public TableDataInfo list(AirlineDataVO airlineDataVO)
{
AirlineDataDTO dto = AirlineDataControllerConvert.toDTO(airlineDataVO);
startPage();
List<AirlineDataDTO> list = airlineDataService.selectAirlineDataList(dto);
return getDataTable(AirlineDataControllerConvert.toVOList(list));
}
}

View File

@ -0,0 +1,68 @@
package com.ruoyi.airline.controller;
import com.ruoyi.airline.api.domain.AirlineFileVO;
import com.ruoyi.airline.controller.convert.AirlineFileControllerConvert;
import com.ruoyi.airline.service.api.IAirlineFileService;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.common.core.exception.base.BaseException;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 航线文件Controller
*
* @author ruoyi
* @date 2026-01-17
*/
@RestController
@RequestMapping("/airline/file")
public class AirlineFileController extends BaseController {
private static final Logger log = LoggerFactory.getLogger(AirlineFileController.class);
@Autowired
private IAirlineFileService airlineFileService;
/**
* 编辑航线文件信息
*
* @param entity 实体对象
* @return
*/
@PutMapping("/edit")
public AjaxResult edit(@RequestBody AirlineFileVO entity) {
AirlineFileDTO dto = AirlineFileControllerConvert.toDTO(entity);
return success(airlineFileService.save(dto));
}
/**
* 长江口
* <p>
* kmz类似zip一般情况下内部包含kml和wpml两个文件
*
* @param vo
*/
@PostMapping("/parseAndUpload")
public AjaxResult createOrupdate(@RequestBody AirlineFileVO vo) {
AirlineFileDTO airlineFile = AirlineFileControllerConvert.toDTO(vo);
try {
return success(airlineFileService.createOrupdate(airlineFile));
} catch (IOException e) {
throw new BaseException("更新航线失败", e.getMessage());
}
}
}

View File

@ -0,0 +1,108 @@
package com.ruoyi.airline.controller;
import com.ruoyi.airline.api.domain.AirlineFileGroupVO;
import com.ruoyi.airline.controller.convert.AirlineFileGroupControllerConvert;
import com.ruoyi.airline.service.api.IAirlineFileGroupService;
import com.ruoyi.airline.service.dto.AirlineFileGroupDTO;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.utils.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 航线分组
*
* @author 拓恒
*/
@RestController
@RequestMapping("/airline/fileGroup")
@Tag(name = "航线分组管理")
public class AirlineFileGroupController extends BaseController {
@Autowired
private IAirlineFileGroupService iAirlineFileGroupService;
/**
* 获取航线文件分组列表,根据用户Id查询分组
*
* @param airlineFileVO 查询条件
* @return
*/
@RequiresPermissions("airline:group:list")
@GetMapping()
@Operation(summary = "获取所有的航线分组")
public TableDataInfo index(AirlineFileGroupVO airlineFileVO) {
startPage();
airlineFileVO.setUserId(SecurityUtils.getUserId());
AirlineFileGroupDTO dto = AirlineFileGroupControllerConvert.toDTO(airlineFileVO);
List<AirlineFileGroupDTO> list = iAirlineFileGroupService.selectGroupList(dto);
List<AirlineFileGroupVO> result = AirlineFileGroupControllerConvert.toApiDomainList(list);
return getDataTable(result);
}
/**
* 根据分组编号获取详细信息
*/
@RequiresPermissions("airline:group:query")
@GetMapping(value = "/{groupId}")
@Operation(summary = "根据分组ID 获取分组详情信息")
public AjaxResult getInfo(@PathVariable Long groupId) {
return success(iAirlineFileGroupService.selectAirLineListsByGroupId(SecurityUtils.getUserId(), groupId));
}
/**
* 新增分组
*/
@RequiresPermissions("airline:group:add")
@Log(title = "新增分组", businessType = BusinessType.INSERT)
@PostMapping
@Operation(summary = "新增分组")
public AjaxResult add(@Validated @RequestBody AirlineFileGroupVO group) {
group.setUserId(SecurityUtils.getUserId());
AirlineFileGroupDTO dto = AirlineFileGroupControllerConvert.toDTO(group);
if (!iAirlineFileGroupService.checkGroupNameUnique(dto)) {
return error("新增分组'" + group.getGroupName() + "'失败,分组名称已存在");
}
return toAjax(iAirlineFileGroupService.insertGroup(dto));
}
/**
* 修改分组
*/
@RequiresPermissions("airline:group:edit")
@Log(title = "修改分组", businessType = BusinessType.UPDATE)
@PutMapping
@Operation(summary = "修改分组")
public AjaxResult edit(@Validated @RequestBody AirlineFileGroupVO group) {
group.setUserId(SecurityUtils.getUserId());
AirlineFileGroupDTO dto = AirlineFileGroupControllerConvert.toDTO(group);
if (!iAirlineFileGroupService.checkGroupNameUnique(dto)) {
return error("修改分组'" + group.getGroupName() + "'失败,分组名称已存在");
}
return toAjax(iAirlineFileGroupService.updateGroup(dto));
}
/**
* 删除分组前端校验分组下是否有航线弹出确认删除提示如果确认会将分组及航线一起删除
*/
@RequiresPermissions("airline:group:remove")
@Log(title = "删除分组", businessType = BusinessType.DELETE)
@DeleteMapping("/{groupId}")
@Operation(summary = "删除分组")
public AjaxResult remove(@PathVariable Long groupId) {
return toAjax(iAirlineFileGroupService.deletegroupById(SecurityUtils.getUserId(), groupId));
}
}

View File

@ -0,0 +1,88 @@
package com.ruoyi.airline.controller;
import com.ruoyi.airline.api.domain.AirlineFileGroupInfoVO;
import com.ruoyi.airline.controller.convert.AirlineFileGroupInfoControllerConvert;
import com.ruoyi.airline.service.api.IAirlineFileGroupInfoService;
import com.ruoyi.airline.service.api.IAirlineFileService;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import com.ruoyi.common.core.exception.base.BaseException;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 航线分组
*
* @author 拓恒
*/
@RestController
@RequestMapping("/airline/fileGroupInfo")
public class AirlineFileGroupInfoController extends BaseController {
@Autowired
private IAirlineFileGroupInfoService iAirlineFileGroupInfoService;
@Autowired
private IAirlineFileService iAirlineFileService;
/**
* 获取航线文件分组列表,根据用户Id查询分组
*
* @param groupId 分组ID
* @return
*/
@RequiresPermissions("airline:groupInfo:list")
@GetMapping()
public TableDataInfo selectGroupInfoListById(Long groupId) {
startPage();
List<AirlineFileGroupInfoDTO> list = iAirlineFileGroupInfoService.selectGroupInfoListById(groupId);
List<AirlineFileGroupInfoVO> result = AirlineFileGroupInfoControllerConvert.toApiDomainList(list);
return getDataTable(result);
}
/**
* kmz航线文件并转换成waypoint上传 ,仅仅返航URL
* <p>
* kmz类似zip一般情况下内部包含kml和wpml两个文件
*
* @param file
*/
@PostMapping("/parseAndUpload")
public AjaxResult parseAndUpload(@RequestParam("file") MultipartFile file, Long groupId) throws IOException {
AirlineFileDTO dto = iAirlineFileService.parseAndUplload(file);
AirlineFileDTO result = iAirlineFileService.save(dto);
AirlineFileGroupInfoDTO infoDTO = new AirlineFileGroupInfoDTO();
infoDTO.setGroupId(groupId);
infoDTO.setAirlineId(result.getId());
return success(iAirlineFileGroupInfoService.save(infoDTO));
}
/**
* 在当前分组下添加初始航线空的航线
*
* @param vo 实体对象
* @return
*/
@PostMapping("/add")
public AjaxResult add(@RequestBody AirlineFileGroupInfoVO vo) throws IOException {
if (vo.getGroupId() == null) {
throw new BaseException("分组ID不能为空");
}
AirlineFileGroupInfoDTO dto = AirlineFileGroupInfoControllerConvert.toDTO(vo);
AirlineFileGroupInfoDTO result = iAirlineFileGroupInfoService.save(dto);
return success(AirlineFileGroupInfoControllerConvert.toVO(result));
}
}

View File

@ -0,0 +1,95 @@
package com.ruoyi.airline.controller.convert;
import com.ruoyi.airline.api.domain.AirlineDataVO;
import com.ruoyi.airline.service.dto.AirlineDataDTO;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线数据Controller转换类
* 用于Controller VO和Service DTO之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineDataControllerConvert
{
/**
* 将Service DTO转换为Controller VO
*
* @param dto Service DTO
* @return Controller VO
*/
public static AirlineDataVO toVO(AirlineDataDTO dto)
{
if (dto == null) {
return null;
}
AirlineDataVO vo = new AirlineDataVO();
vo.setId(dto.getId());
vo.setFlightNumber(dto.getFlightNumber());
vo.setDepartureCity(dto.getDepartureCity());
vo.setArrivalCity(dto.getArrivalCity());
vo.setAirspeed(dto.getAirspeed());
vo.setVelocity(dto.getVelocity());
vo.setVspeed(dto.getVspeed());
vo.setHspeed(dto.getHspeed());
return vo;
}
/**
* 将Controller VO转换为Service DTO
*
* @param vo Controller VO
* @return Service DTO
*/
public static AirlineDataDTO toDTO(AirlineDataVO vo)
{
if (vo == null) {
return null;
}
AirlineDataDTO dto = new AirlineDataDTO();
dto.setId(vo.getId());
dto.setFlightNumber(vo.getFlightNumber());
dto.setDepartureCity(vo.getDepartureCity());
dto.setArrivalCity(vo.getArrivalCity());
dto.setAirspeed(vo.getAirspeed());
dto.setVelocity(vo.getVelocity());
dto.setVspeed(vo.getVspeed());
dto.setHspeed(vo.getHspeed());
return dto;
}
/**
* 将Service DTO列表转换为Controller VO列表
*
* @param dtoList Service DTO列表
* @return Controller VO列表
*/
public static List<AirlineDataVO> toVOList(List<AirlineDataDTO> dtoList)
{
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineDataControllerConvert::toVO)
.collect(Collectors.toList());
}
/**
* 将Controller VO列表转换为Service DTO列表
*
* @param voList Controller VO列表
* @return Service DTO列表
*/
public static List<AirlineDataDTO> toDTOList(List<AirlineDataVO> voList)
{
if (voList == null || voList.isEmpty()) {
return null;
}
return voList.stream()
.map(AirlineDataControllerConvert::toDTO)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,97 @@
package com.ruoyi.airline.controller.convert;
import com.ruoyi.airline.api.domain.AirlineFileVO;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件Controller转换类
* 用于Controller VO和Service DTO之间的转换
*
* @author 拓恒
* @date 2026-01-17
*/
public class AirlineFileControllerConvert {
/**
* 将Service DTO转换为Controller VO
*
* @param dto Service DTO
* @return Controller VO
*/
public static AirlineFileVO toVO(AirlineFileDTO dto) {
if (dto == null) {
return null;
}
AirlineFileVO vo = new AirlineFileVO();
vo.setId(dto.getId());
vo.setFileName(dto.getFileName());
vo.setFileUrl(dto.getFileUrl());
vo.setType(dto.getType());
vo.setLinePointDtoList(dto.getLinePointDtoList());
vo.setStatus(dto.getStatus());
vo.setDjiRthAltitude(dto.getDjiRthAltitude());
return vo;
}
/**
* 将Controller VO转换为Service DTO
*
* @param vo Controller VO
* @return Service DTO
*/
public static AirlineFileDTO toDTO(AirlineFileVO vo) {
if (vo == null) {
return null;
}
AirlineFileDTO dto = new AirlineFileDTO();
dto.setId(vo.getId());
dto.setFileName(vo.getFileName());
dto.setFileUrl(vo.getFileUrl());
dto.setType(vo.getType());
dto.setLinePointDtoList(vo.getLinePointDtoList());
dto.setStatus(vo.getStatus());
dto.setDjiRthAltitude(vo.getDjiRthAltitude());
return dto;
}
/**
* 将Service DTO列表转换为Controller VO列表
*
* @param dtoList Service DTO列表
* @return Controller VO列表
*/
public static List<AirlineFileVO> toVOList(List<AirlineFileDTO> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineFileControllerConvert::toVO)
.collect(Collectors.toList());
}
/**
* 将Controller VO列表转换为Service DTO列表
*
* @param voList Controller VO列表
* @return Service DTO列表
*/
public static List<AirlineFileDTO> toDTOList(List<AirlineFileVO> voList) {
if (voList == null || voList.isEmpty()) {
return null;
}
return voList.stream()
.map(AirlineFileControllerConvert::toDTO)
.collect(Collectors.toList());
}
public static List<AirlineFileVO> toApiDomainList(List<AirlineFileDTO> dtoList) {
if (dtoList == null)
{
return null;
}
return dtoList.stream().map(AirlineFileControllerConvert::toVO).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,103 @@
package com.ruoyi.airline.controller.convert;
import com.ruoyi.airline.api.domain.AirlineFileGroupVO;
import com.ruoyi.airline.api.domain.AirlineFileVO;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupDTO;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件分组Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileGroupControllerConvert {
/**
* 将Service DTO转换为Controller VO
*
* @param dto Service DTO
* @return Controller VO
*/
public static AirlineFileGroupVO toVO(AirlineFileGroupDTO dto) {
if (dto == null) {
return null;
}
AirlineFileGroupVO vo = new AirlineFileGroupVO();
vo.setGroupId(dto.getGroupId());
vo.setGroupName(dto.getGroupName());
vo.setUserId(dto.getUserId());
vo.setCreateBy(dto.getCreateBy());
vo.setCreateTime(dto.getCreateTime());
vo.setUpdateBy(dto.getUpdateBy());
vo.setUpdateTime(dto.getUpdateTime());
vo.setRemark(dto.getRemark());
return vo;
}
/**
* 将Controller VO转换为Service DTO
*
* @param vo Controller VO
* @return Service DTO
*/
public static AirlineFileGroupDTO toDTO(AirlineFileGroupVO vo) {
if (vo == null) {
return null;
}
AirlineFileGroupDTO dto = new AirlineFileGroupDTO();
dto.setGroupId(vo.getGroupId());
dto.setGroupName(vo.getGroupName());
dto.setUserId(vo.getUserId());
dto.setCreateBy(vo.getCreateBy());
dto.setCreateTime(vo.getCreateTime());
dto.setUpdateBy(vo.getUpdateBy());
dto.setUpdateTime(vo.getUpdateTime());
dto.setRemark(vo.getRemark());
return dto;
}
/**
* 将Service DTO列表转换为Controller VO列表
*
* @param dtoList Service DTO列表
* @return Controller VO列表
*/
public static List<AirlineFileGroupVO> toVOList(List<AirlineFileGroupDTO> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineFileGroupControllerConvert::toVO)
.collect(Collectors.toList());
}
/**
* 将Controller VO列表转换为Service DTO列表
*
* @param voList Controller VO列表
* @return Service DTO列表
*/
public static List<AirlineFileGroupDTO> toDTOList(List<AirlineFileGroupVO> voList) {
if (voList == null || voList.isEmpty()) {
return null;
}
return voList.stream()
.map(AirlineFileGroupControllerConvert::toDTO)
.collect(Collectors.toList());
}
public static List<AirlineFileGroupVO> toApiDomainList(List<AirlineFileGroupDTO> dtoList) {
if (dtoList == null)
{
return null;
}
return dtoList.stream().map(AirlineFileGroupControllerConvert::toVO).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,101 @@
package com.ruoyi.airline.controller.convert;
import com.ruoyi.airline.api.domain.AirlineFileGroupInfoVO;
import com.ruoyi.airline.api.domain.AirlineFileGroupVO;
import com.ruoyi.airline.service.dto.AirlineFileGroupDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileGroupInfoControllerConvert {
/**
* 将Service DTO转换为Controller VO
*
* @param dto Service DTO
* @return Controller VO
*/
public static AirlineFileGroupInfoVO toVO(AirlineFileGroupInfoDTO dto) {
if (dto == null) {
return null;
}
AirlineFileGroupInfoVO vo = new AirlineFileGroupInfoVO();
vo.setId(dto.getId());
vo.setGroupId(dto.getGroupId());
vo.setCreateBy(dto.getCreateBy());
vo.setCreateTime(dto.getCreateTime());
vo.setUpdateBy(dto.getUpdateBy());
vo.setUpdateTime(dto.getUpdateTime());
vo.setRemark(dto.getRemark());
return vo;
}
/**
* 将Controller VO转换为Service DTO
*
* @param vo Controller VO
* @return Service DTO
*/
public static AirlineFileGroupInfoDTO toDTO(AirlineFileGroupInfoVO vo) {
if (vo == null) {
return null;
}
AirlineFileGroupInfoDTO dto = new AirlineFileGroupInfoDTO();
dto.setId(vo.getId());
dto.setGroupId(vo.getGroupId());
dto.setCreateBy(vo.getCreateBy());
dto.setCreateTime(vo.getCreateTime());
dto.setUpdateBy(vo.getUpdateBy());
dto.setUpdateTime(vo.getUpdateTime());
dto.setRemark(vo.getRemark());
return dto;
}
/**
* 将Service DTO列表转换为Controller VO列表
*
* @param dtoList Service DTO列表
* @return Controller VO列表
*/
public static List<AirlineFileGroupInfoVO> toVOList(List<AirlineFileGroupInfoDTO> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineFileGroupInfoControllerConvert::toVO)
.collect(Collectors.toList());
}
/**
* 将Controller VO列表转换为Service DTO列表
*
* @param voList Controller VO列表
* @return Service DTO列表
*/
public static List<AirlineFileGroupInfoDTO> toDTOList(List<AirlineFileGroupInfoVO> voList) {
if (voList == null || voList.isEmpty()) {
return null;
}
return voList.stream()
.map(AirlineFileGroupInfoControllerConvert::toDTO)
.collect(Collectors.toList());
}
public static List<AirlineFileGroupInfoVO> toApiDomainList(List<AirlineFileGroupInfoDTO> dtoList) {
if (dtoList == null)
{
return null;
}
return dtoList.stream().map(AirlineFileGroupInfoControllerConvert::toVO).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.airline.domain.api;
import com.ruoyi.airline.domain.model.AirlineData;
import java.util.List;
/**
* 航线数据Domain接口
*
* @author ruoyi
* @date 2026-01-17
*/
public interface IAirlineDataDomain
{
/**
* 查询航线数据列表
*
* @param airlineData 航线数据
* @return 航线数据集合
*/
List<AirlineData> selectAirlineDataList(AirlineData airlineData);
/**
* 根据ID查询航线数据
*
* @param id 主键ID
* @return 航线数据
*/
AirlineData selectAirlineDataById(Long id);
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.airline.domain.api;
import com.ruoyi.airline.domain.model.AirlineFile;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import java.util.List;
/**
* 航线文件领域接口
*
* @author ruoyi
* @date 2026-01-17
*/
public interface IAirlineFileDomain {
List<AirlineFile> selectFileListByIds(List<Long> ids);
AirlineFile save(AirlineFile model);
}

View File

@ -0,0 +1,34 @@
package com.ruoyi.airline.domain.api;
import com.ruoyi.airline.domain.model.AirlineFileGroup;
import java.util.List;
/**
* 航线分组
*
* @author 拓恒
*/
public interface IAirlineFileGroupDomain {
/**
* 软删除
* @param model
* @return
*/
int deletegroup(AirlineFileGroup model);
/**
* 检查当前用户下分组名称是否唯一
* @param model
* @return
*/
boolean checkgroupNameUnique(AirlineFileGroup model);
int updateGroup(AirlineFileGroup model);
int insertGroup(AirlineFileGroup model);
List<AirlineFileGroup> selectGroupList(AirlineFileGroup model);
}

View File

@ -0,0 +1,25 @@
package com.ruoyi.airline.domain.api;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import java.util.List;
/**
* 航线分组明细
*
* @author 拓恒
*/
public interface IAirlineFileGroupInfoDomain {
List<AirlineFileGroupInfo> selectGroupInfoListById(Long groupId);
/**
* 软删除
*
* @param dto
*/
int deleteGroupInfo(AirlineFileGroupInfo dto);
AirlineFileGroupInfo save(AirlineFileGroupInfo model);
}

View File

@ -0,0 +1,28 @@
package com.ruoyi.airline.domain.constant;
public class FileTypeConstants {
/**
* kmz 文件本质上是zip文件
*/
public static final String KMZ = "zip";
/**
* kml 文件
*/
public static final String KML = "kml";
/**
* wpml 文件
*/
public static final String WPML = "wpml";
/**
* 航线导入支持的文件类型
*/
public static final String ROUTE_SUPPORT_TYPE = "kml,zip";
}

View File

@ -0,0 +1,81 @@
package com.ruoyi.airline.domain.convert;
import com.ruoyi.airline.domain.model.AirlineData;
import com.ruoyi.airline.mapper.entity.AirlineDataEntity;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线数据Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineDataDomainConvert
{
/**
* 将Domain模型转换为Mapper实体
*
* @param model Domain模型
* @return Mapper实体
*/
public static AirlineDataEntity toEntity(AirlineData model)
{
if (model == null) {
return null;
}
AirlineDataEntity entity = new AirlineDataEntity();
return entity;
}
/**
* 将Mapper实体转换为Domain模型
*
* @param entity Mapper实体
* @return Domain模型
*/
public static AirlineData toModel(AirlineDataEntity entity)
{
if (entity == null) {
return null;
}
AirlineData model = new AirlineData();
return model;
}
/**
* 将Mapper实体列表转换为Domain模型列表
*
* @param entityList Mapper实体列表
* @return Domain模型列表
*/
public static List<AirlineData> toModelList(List<AirlineDataEntity> entityList)
{
if (entityList == null || entityList.isEmpty()) {
return null;
}
return entityList.stream()
.map(AirlineDataDomainConvert::toModel)
.collect(Collectors.toList());
}
/**
* 将Domain模型列表转换为Mapper实体列表
*
* @param modelList Domain模型列表
* @return Mapper实体列表
*/
public static List<AirlineDataEntity> toEntityList(List<AirlineData> modelList)
{
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineDataDomainConvert::toEntity)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,97 @@
package com.ruoyi.airline.domain.convert;
import com.ruoyi.airline.domain.model.AirlineFile;
import com.ruoyi.airline.mapper.entity.AirlineFileEntity;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileDomainConvert {
/**
* 将Domain模型转换为Mapper实体
*
* @param model Domain模型
* @return Mapper实体
*/
public static AirlineFileEntity toEntity(AirlineFile model) {
if (model == null) {
return null;
}
AirlineFileEntity entity = new AirlineFileEntity();
entity.setId(model.getId());
entity.setFileName(model.getFileName());
entity.setFileUrl(model.getFileUrl());
entity.setType(model.getType());
entity.setSource(model.getSource());
entity.setStatus(model.getStatus());
entity.setFileMd5(model.getFileMd5());
entity.setCreateBy(model.getCreateBy());
entity.setUpdateBy(model.getUpdateBy());
entity.setRemark(model.getRemark());
return entity;
}
/**
* 将Mapper实体转换为Domain模型
*
* @param entity Mapper实体
* @return Domain模型
*/
public static AirlineFile toModel(AirlineFileEntity entity) {
if (entity == null) {
return null;
}
AirlineFile model = new AirlineFile();
model.setId(entity.getId());
model.setFileName(entity.getFileName());
model.setFileUrl(entity.getFileUrl());
model.setType(entity.getType());
model.setSource(entity.getSource());
model.setStatus(entity.getStatus());
model.setFileMd5(entity.getFileMd5());
model.setCreateBy(entity.getCreateBy());
model.setCreateTime(entity.getCreateTime() != null ? entity.getCreateTime().toString() : null);
model.setUpdateBy(entity.getUpdateBy());
model.setUpdateTime(entity.getUpdateTime() != null ? entity.getUpdateTime().toString() : null);
model.setRemark(entity.getRemark());
return model;
}
/**
* 将Mapper实体列表转换为Domain模型列表
*
* @param entityList Mapper实体列表
* @return Domain模型列表
*/
public static List<AirlineFile> toModelList(List<AirlineFileEntity> entityList) {
if (entityList == null || entityList.isEmpty()) {
return null;
}
return entityList.stream()
.map(AirlineFileDomainConvert::toModel)
.collect(Collectors.toList());
}
/**
* 将Domain模型列表转换为Mapper实体列表
*
* @param modelList Domain模型列表
* @return Mapper实体列表
*/
public static List<AirlineFileEntity> toEntityList(List<AirlineFile> modelList) {
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineFileDomainConvert::toEntity)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,90 @@
package com.ruoyi.airline.domain.convert;
import com.ruoyi.airline.domain.model.AirlineFileGroup;
import com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件分组Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileGroupDomainConvert {
/**
* 将Domain模型转换为Mapper实体
*
* @param model Domain模型
* @return Mapper实体
*/
public static AirlineFileGroupEntity toEntity(AirlineFileGroup model) {
if (model == null) {
return null;
}
AirlineFileGroupEntity entity = new AirlineFileGroupEntity();
entity.setGroupId(model.getGroupId());
entity.setGroupName(model.getGroupName());
entity.setUserId(model.getUserId());
entity.setCreateBy(model.getCreateBy());
entity.setUpdateBy(model.getUpdateBy());
entity.setRemark(model.getRemark());
return entity;
}
/**
* 将Mapper实体转换为Domain模型
*
* @param entity Mapper实体
* @return Domain模型
*/
public static AirlineFileGroup toModel(AirlineFileGroupEntity entity) {
if (entity == null) {
return null;
}
AirlineFileGroup model = new AirlineFileGroup();
model.setGroupId(entity.getGroupId());
model.setGroupName(entity.getGroupName());
model.setUserId(entity.getUserId());
model.setCreateBy(entity.getCreateBy());
model.setCreateTime(entity.getCreateTime() != null ? entity.getCreateTime(): null);
model.setUpdateBy(entity.getUpdateBy());
model.setUpdateTime(entity.getUpdateTime() != null ? entity.getUpdateTime(): null);
model.setRemark(entity.getRemark());
return model;
}
/**
* 将Mapper实体列表转换为Domain模型列表
*
* @param entityList Mapper实体列表
* @return Domain模型列表
*/
public static List<AirlineFileGroup> toModelList(List<AirlineFileGroupEntity> entityList) {
if (entityList == null || entityList.isEmpty()) {
return null;
}
return entityList.stream()
.map(AirlineFileGroupDomainConvert::toModel)
.collect(Collectors.toList());
}
/**
* 将Domain模型列表转换为Mapper实体列表
*
* @param modelList Domain模型列表
* @return Mapper实体列表
*/
public static List<AirlineFileGroupEntity> toEntityList(List<AirlineFileGroup> modelList) {
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineFileGroupDomainConvert::toEntity)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,82 @@
package com.ruoyi.airline.domain.convert;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileGroupInfoDomainConvert {
/**
* 将Domain模型转换为Mapper实体
*
* @param model Domain模型
* @return Mapper实体
*/
public static AirlineFileGroupInfoEntity toEntity(AirlineFileGroupInfo model) {
if (model == null) {
return null;
}
AirlineFileGroupInfoEntity entity = new AirlineFileGroupInfoEntity();
entity.setId(model.getId());
entity.setGroupId(model.getGroupId());
entity.setAirlineId(model.getAirlineId());
return entity;
}
/**
* 将Mapper实体转换为Domain模型
*
* @param entity Mapper实体
* @return Domain模型
*/
public static AirlineFileGroupInfo toModel(AirlineFileGroupInfoEntity entity) {
if (entity == null) {
return null;
}
AirlineFileGroupInfo model = new AirlineFileGroupInfo();
model.setId(entity.getId());
model.setGroupId(entity.getGroupId());
model.setAirlineId(entity.getAirlineId());
return model;
}
/**
* 将Mapper实体列表转换为Domain模型列表
*
* @param entityList Mapper实体列表
* @return Domain模型列表
*/
public static List<AirlineFileGroupInfo> toModelList(List<AirlineFileGroupInfoEntity> entityList) {
if (entityList == null || entityList.isEmpty()) {
return null;
}
return entityList.stream()
.map(AirlineFileGroupInfoDomainConvert::toModel)
.collect(Collectors.toList());
}
/**
* 将Domain模型列表转换为Mapper实体列表
*
* @param modelList Domain模型列表
* @return Mapper实体列表
*/
public static List<AirlineFileGroupInfoEntity> toEntityList(List<AirlineFileGroupInfo> modelList) {
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineFileGroupInfoDomainConvert::toEntity)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.airline.domain.enums;
import lombok.Getter;
/**
* @Author: 吴彬
* @CreateTime: 2023-06-29 15:24
* @Description: 航线文件类型枚举
* @Version: 1.0
*/
public enum AirlineFileTypeEnum {
NORMAL(1,"普通航线"),
POINT(2,"指点"),
PLANE(3,"指面"),
;
AirlineFileTypeEnum(int code, String description){
this.code = code;
this.description = description;
}
@Getter
private int code;
@Getter
private String description;
}

View File

@ -0,0 +1,53 @@
package com.ruoyi.airline.domain.impl;
import com.ruoyi.airline.domain.api.IAirlineDataDomain;
import com.ruoyi.airline.domain.model.AirlineData;
import com.ruoyi.airline.mapper.AirlineDataMapper;
import com.ruoyi.airline.mapper.entity.AirlineDataEntity;
import com.ruoyi.airline.domain.convert.AirlineDataDomainConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 航线数据Domain实现类
*
* @author ruoyi
* @date 2026-01-17
*/
@Component
public class AirlineDataDomainImpl implements IAirlineDataDomain
{
@Autowired
private AirlineDataMapper airlineDataMapper;
/**
* 查询航线数据列表
*
* @param airlineData 航线数据
* @return 航线数据集合
*/
@Override
public List<AirlineData> selectAirlineDataList(AirlineData airlineData)
{
AirlineDataEntity entity = AirlineDataDomainConvert.toEntity(airlineData);
List<AirlineDataEntity> entityList = airlineDataMapper.selectAirlineDataList(entity);
return AirlineDataDomainConvert.toModelList(entityList);
}
/**
* 根据ID查询航线数据
*
* @param id 主键ID
* @return 航线数据
*/
@Override
public AirlineData selectAirlineDataById(Long id)
{
AirlineDataEntity entity = airlineDataMapper.selectAirlineDataById(id);
return AirlineDataDomainConvert.toModel(entity);
}
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.airline.domain.impl;
import com.ruoyi.airline.domain.api.IAirlineFileDomain;
import com.ruoyi.airline.domain.convert.AirlineFileDomainConvert;
import com.ruoyi.airline.domain.model.AirlineFile;
import com.ruoyi.airline.mapper.AirlineFileMapper;
import com.ruoyi.airline.mapper.entity.AirlineFileEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 航线文件领域实现类
*
* @author ruoyi
* @date 2026-01-17
*/
@Component
public class AirlineFileDomainImpl implements IAirlineFileDomain {
@Autowired
private AirlineFileMapper airlineFileMapper;
@Override
public List<AirlineFile> selectFileListByIds(List<Long> ids) {
return AirlineFileDomainConvert.toModelList(airlineFileMapper.selectFileListByIds(ids));
}
@Override
public AirlineFile save(AirlineFile model) {
AirlineFileEntity entity = AirlineFileDomainConvert.toEntity(model);
return AirlineFileDomainConvert.toModel(airlineFileMapper.save(entity));
}
}

View File

@ -0,0 +1,54 @@
package com.ruoyi.airline.domain.impl;
import com.ruoyi.airline.domain.api.IAirlineFileGroupDomain;
import com.ruoyi.airline.domain.convert.AirlineFileGroupDomainConvert;
import com.ruoyi.airline.domain.model.AirlineFileGroup;
import com.ruoyi.airline.mapper.AirlineFileGroupMapper;
import com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 航线分组
*
* @author 拓恒
*/
@Component
public class AirlineFileGroupDomainImpl implements IAirlineFileGroupDomain {
@Autowired
private AirlineFileGroupMapper airlineFileGroupMapper;
@Override
public int deletegroup(AirlineFileGroup model) {
model.setDelFlag(1L);
AirlineFileGroupEntity entity = AirlineFileGroupDomainConvert.toEntity(model);
return airlineFileGroupMapper.deletegroup(entity);
}
@Override
public boolean checkgroupNameUnique(AirlineFileGroup model) {
AirlineFileGroupEntity entity = AirlineFileGroupDomainConvert.toEntity(model);
return airlineFileGroupMapper.checkgroupNameUnique(entity) > 0;
}
@Override
public int updateGroup(AirlineFileGroup model) {
AirlineFileGroupEntity entity = AirlineFileGroupDomainConvert.toEntity(model);
return airlineFileGroupMapper.updateGroup(entity);
}
@Override
public int insertGroup(AirlineFileGroup model) {
AirlineFileGroupEntity entity = AirlineFileGroupDomainConvert.toEntity(model);
return airlineFileGroupMapper.insertGroup(entity);
}
@Override
public List<AirlineFileGroup> selectGroupList(AirlineFileGroup model) {
AirlineFileGroupEntity entity = AirlineFileGroupDomainConvert.toEntity(model);
return AirlineFileGroupDomainConvert.toModelList(airlineFileGroupMapper.selectGroupList(entity));
}
}

View File

@ -0,0 +1,46 @@
package com.ruoyi.airline.domain.impl;
import com.ruoyi.airline.domain.api.IAirlineFileGroupInfoDomain;
import com.ruoyi.airline.domain.convert.AirlineFileGroupInfoDomainConvert;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.mapper.AirlineFileGroupInfoMapper;
import com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 航线分组明细
*
* @author 拓恒
*/
@Component
public class AirlineFileGroupInfoDomainImpl implements IAirlineFileGroupInfoDomain {
@Autowired
private AirlineFileGroupInfoMapper airlineFileGroupInfoMapper;
@Override
public List<AirlineFileGroupInfo> selectGroupInfoListById(Long groupId) {
AirlineFileGroupInfo dto = new AirlineFileGroupInfo();
dto.setGroupId(groupId);
AirlineFileGroupInfoEntity Entity = AirlineFileGroupInfoDomainConvert.toEntity(dto);
List<AirlineFileGroupInfoEntity> entities = airlineFileGroupInfoMapper.selectGroupList(Entity);
return AirlineFileGroupInfoDomainConvert.toModelList(entities);
}
@Override
public int deleteGroupInfo(AirlineFileGroupInfo model) {
model.setDelFlag(1L);
AirlineFileGroupInfoEntity Entity = AirlineFileGroupInfoDomainConvert.toEntity(model);
return airlineFileGroupInfoMapper.deleteGroupInfo(Entity);
}
@Override
public AirlineFileGroupInfo save(AirlineFileGroupInfo model) {
AirlineFileGroupInfoEntity Entity = AirlineFileGroupInfoDomainConvert.toEntity(model);
return airlineFileGroupInfoMapper.save(Entity);
}
}

View File

@ -0,0 +1,130 @@
package com.ruoyi.airline.domain.model;
/**
* 航线数据模型
* Domain 层模型用于业务逻辑处理
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineData
{
/** 主键ID */
private Long id;
/** 航班号 */
private String flightNumber;
/** 起飞城市 */
private String departureCity;
/** 到达城市 */
private String arrivalCity;
/** 空气速度 */
private Double airspeed;
/** 速度 */
private Double velocity;
/** 垂直速度 */
private Double vspeed;
/** 水平速度 */
private Double hspeed;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getFlightNumber()
{
return flightNumber;
}
public void setFlightNumber(String flightNumber)
{
this.flightNumber = flightNumber;
}
public String getDepartureCity()
{
return departureCity;
}
public void setDepartureCity(String departureCity)
{
this.departureCity = departureCity;
}
public String getArrivalCity()
{
return arrivalCity;
}
public void setArrivalCity(String arrivalCity)
{
this.arrivalCity = arrivalCity;
}
public Double getAirspeed()
{
return airspeed;
}
public void setAirspeed(Double airspeed)
{
this.airspeed = airspeed;
}
public Double getVelocity()
{
return velocity;
}
public void setVelocity(Double velocity)
{
this.velocity = velocity;
}
public Double getVspeed()
{
return vspeed;
}
public void setVspeed(Double vspeed)
{
this.vspeed = vspeed;
}
public Double getHspeed()
{
return hspeed;
}
public void setHspeed(Double hspeed)
{
this.hspeed = hspeed;
}
@Override
public String toString()
{
return "AirlineData{" +
"id=" + id +
", flightNumber='" + flightNumber + '\'' +
", departureCity='" + departureCity + '\'' +
", arrivalCity='" + arrivalCity + '\'' +
", airspeed=" + airspeed +
", velocity=" + velocity +
", vspeed=" + vspeed +
", hspeed=" + hspeed +
'}';
}
}

View File

@ -0,0 +1,147 @@
package com.ruoyi.airline.domain.model;
import com.ruoyi.airline.api.domain.AirLinePointVO;
import lombok.Data;
import java.util.List;
/**
* 航线文件领域模型
* Domain 层模型用于业务逻辑处理
*
* @author ruoyi
* @date 2026-01-17
*/
@Data
public class AirlineFile {
/**
* 主键ID
*/
private Long id;
/**
* 文件名称
*/
private String fileName;
/**
* 飞行器厂商
*/
private String airVendor;
/**
* 飞行器类型
*/
private String airType;
/**
* 文件地址
*/
private String fileUrl;
/**
* 航线类型1,航点航线;2,指点航线;3,指面航线
*/
private Integer type;
/**
* 文件备注
*/
private String note;
/**
* 航线距离
*/
private Double distance;
/**
* 航线点列表
*/
private List<AirLinePointVO> linePointDtoList;
/**
* 数据来源
*/
private String source;
/**
* 1 启用 0 停用
*/
private Integer status;
/**
* 航线文件对应的 MD5指纹
*/
private String fileMd5;
/**
* 大疆航线对应的oss地址可能存kmz也可能存waypoint要看fileUrl存的是啥这个字段存反的
*/
private String djiFileUrl;
/**
* kmz航线的全局高度
*/
private Integer djiRthAltitude;
/**
* 航线转弯类型 1-直线2-协调转弯
*/
private Integer turnRadius;
/**
* 是否需要自动拍照
*/
private Integer autoTakePhoto;
/**
* 自动拍照间隔时间
*/
private Integer autoTakePhotoInterval;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private String createTime;
/**
* 更新者
*/
private String updateBy;
/**
* 更新时间
*/
private String updateTime;
/**
* 备注
*/
private String remark;
@Override
public String toString() {
return "AirlineFile{" +
"id=" + id +
", fileName='" + fileName + '\'' +
", fileUrl='" + fileUrl + '\'' +
", type=" + type +
", note='" + note + '\'' +
", distance=" + distance +
", linePointDtoList=" + linePointDtoList +
", source='" + source + '\'' +
", status=" + status +
", fileMd5='" + fileMd5 + '\'' +
", djiFileUrl='" + djiFileUrl + '\'' +
", djiRthAltitude=" + djiRthAltitude +
", turnRadius=" + turnRadius +
", autoTakePhoto=" + autoTakePhoto +
", autoTakePhotoInterval=" + autoTakePhotoInterval +
'}';
}
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.airline.domain.model;
import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.web.domain.ExBaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 航线分组
*
* @author 拓恒
*/
@Data
public class AirlineFileGroup extends ExBaseEntity {
/**
* 用户ID
*/
private Long groupId;
/**
* 分组名称
*/
private String groupName;
/**
* 用户ID分组自带用户归属 后期权限都是基于用户ID进行
*/
private Long userId;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("groupId", getGroupId())
.append("groupName", getGroupName())
.append("userId", getUserId())
.toString();
}
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.airline.domain.model;
import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.web.domain.ExBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 航线分组明细
*
* @author 拓恒
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AirlineFileGroupInfo extends ExBaseEntity {
/**
* id,主键用于order by 排序
*/
private Long id;
/**
* 用户ID
*/
private Long groupId;
/**
* 航线id
*/
private Long airlineId;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("groupId", getGroupId())
.append("airlineId", getAirlineId())
.toString();
}
}

View File

@ -0,0 +1,74 @@
package com.ruoyi.airline.domain.model;
import com.ruoyi.airline.domain.model.kml.NewGeoPoint;
import lombok.Data;
import java.util.List;
/**
* 航线文件
*/
@Data
public class KmlParams {
/**
* 无人机类型 91
*/
private Integer droneType;
/**
* 无人机子类型 1
*/
private Integer subDroneType;
/**
* 相机枚举值 type 机场2为81
*/
private Integer payloadType;
/**
* 相机枚举值 subtype 机场2为0
*/
private Integer payloadSubEnumType;
/**
* 相机枚举值 gimbalindex 机场2为0
*/
private Integer payloadPosition;
/**
* 航点执行高度
*/
private Integer executeHeight;
/**
* 航点飞行速度
*/
private Integer autoFlightSpeed;
/**
* 图片存储类型
*/
private String imageFormat;
/**
* 机场经度
*/
private String airportLongitude;
/**
* 机场纬度
*/
private String airportLatitude;
/**
* 椭球高度 地表高度 可以先给默认值
*/
private String airportHeight;
/**
* 航线航点
*/
private List<NewGeoPoint> pointList;
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:action")
public class KmlAction {
@XStreamAlias("wpml:actionId")
private String actionId;
@XStreamAlias("wpml:actionActuatorFunc")
private String actionActuatorFunc;
@XStreamAlias("wpml:actionActuatorFuncParam")
private KmlActionActuatorFuncParam actionActuatorFuncParam;
}

View File

@ -0,0 +1,161 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:actionActuatorFuncParam")
public class KmlActionActuatorFuncParam {
// takePhoto & startRecord & stopRecord
@XStreamAlias("wpml:payloadPositionIndex")
private String payloadPositionIndex;
@XStreamAlias("wpml:fileSuffix")
private String fileSuffix;
@XStreamAlias("wpml:payloadLensIndex")
private String payloadLensIndex;
@XStreamAlias("wpml:useGlobalPayloadLensIndex")
private String useGlobalPayloadLensIndex;
// focus
@XStreamAlias("wpml:isPointFocus")
private String isPointFocus;
@XStreamAlias("wpml:focusX")
private String focusX;
@XStreamAlias("wpml:focusY")
private String focusY;
@XStreamAlias("wpml:focusRegionWidth")
private String focusRegionWidth;
@XStreamAlias("wpml:focusRegionHeight")
private String focusRegionHeight;
@XStreamAlias("wpml:isInfiniteFocus")
private String isInfiniteFocus;
// zoom
@XStreamAlias("wpml:focalLength")
private String focalLength;
// customDirName
@XStreamAlias("wpml:directoryName")
private String directoryName;
// gimbalRotate & gimbalEvenlyRotate
@XStreamAlias("wpml:gimbalHeadingYawBase")
private String gimbalHeadingYawBase;
@XStreamAlias("wpml:gimbalRotateMode")
private String gimbalRotateMode;
@XStreamAlias("wpml:gimbalPitchRotateEnable")
private String gimbalPitchRotateEnable;
@XStreamAlias("wpml:gimbalPitchRotateAngle")
private String gimbalPitchRotateAngle;
@XStreamAlias("wpml:gimbalRollRotateEnable")
private String gimbalRollRotateEnable;
@XStreamAlias("wpml:gimbalRollRotateAngle")
private String gimbalRollRotateAngle;
@XStreamAlias("wpml:gimbalYawRotateEnable")
private String gimbalYawRotateEnable;
@XStreamAlias("wpml:gimbalYawRotateAngle")
private String gimbalYawRotateAngle;
@XStreamAlias("wpml:gimbalRotateTimeEnable")
private String gimbalRotateTimeEnable;
@XStreamAlias("wpml:gimbalRotateTime")
private String gimbalRotateTime;
// rotateYaw
@XStreamAlias("wpml:aircraftHeading")
private String aircraftHeading;
@XStreamAlias("wpml:aircraftPathMode")
private String aircraftPathMode;
// hover
@XStreamAlias("wpml:hoverTime")
private String hoverTime;
// orientedShoot
@XStreamAlias("wpml:accurateFrameValid")
private String accurateFrameValid;
@XStreamAlias("wpml:targetAngle")
private String targetAngle;
@XStreamAlias("wpml:actionUUID")
private String actionUUID;
@XStreamAlias("wpml:imageWidth")
private String imageWidth;
@XStreamAlias("wpml:imageHeight")
private String imageHeight;
@XStreamAlias("wpml:AFPos")
private String AFPos;
@XStreamAlias("wpml:gimbalPort")
private String gimbalPort;
@XStreamAlias("wpml:orientedCameraType")
private String orientedCameraType;
@XStreamAlias("wpml:orientedFilePath")
private String orientedFilePath;
@XStreamAlias("wpml:orientedFileMD5")
private String orientedFileMD5;
@XStreamAlias("wpml:orientedFileSize")
private String orientedFileSize;
@XStreamAlias("wpml:orientedFileSuffix")
private String orientedFileSuffix;
@XStreamAlias("wpml:orientedCameraApertue")
private String orientedCameraApertue;
@XStreamAlias("wpml:orientedCameraLuminance")
private String orientedCameraLuminance;
@XStreamAlias("wpml:orientedCameraShutterTime")
private String orientedCameraShutterTime;
@XStreamAlias("wpml:orientedCameraISO")
private String orientedCameraISO;
@XStreamAlias("wpml:orientedPhotoMode")
private String orientedPhotoMode;
// panoShot
@XStreamAlias("wpml:panoShotSubMode")
private String panoShotSubMode;
// recordPointCloud
@XStreamAlias("wpml:recordPointCloudOperate")
private String recordPointCloudOperate;
}

View File

@ -0,0 +1,34 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import java.util.List;
@Data
@XStreamAlias("wpml:actionGroup")
public class KmlActionGroup {
@XStreamAlias("wpml:actionGroupId")
private String actionGroupId;
@XStreamAlias("wpml:actionGroupStartIndex")
private String actionGroupStartIndex;
@XStreamAlias("wpml:actionGroupEndIndex")
private String actionGroupEndIndex;
@XStreamAlias("wpml:actionGroupMode")
private String actionGroupMode;
@XStreamAlias("wpml:actionTrigger")
private KmlActionTrigger actionTrigger;
@XStreamAlias("wpml:action")
private List<KmlAction> action;
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:actionTrigger")
public class KmlActionTrigger {
@XStreamAlias("wpml:actionTriggerType")
private String actionTriggerType;
@XStreamAlias("wpml:actionTriggerParam")
private String actionTriggerParam;
}

View File

@ -0,0 +1,26 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("Document")
public class KmlDocument {
@XStreamAlias("wpml:author")
private String author;
@XStreamAlias("wpml:createTime")
private String createTime;
@XStreamAlias("wpml:updateTime")
private String updateTime;
@XStreamAlias("wpml:missionConfig")
private KmlMissionConfig kmlMissionConfig;
@XStreamAlias("Folder")
private KmlFolder folder;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:droneInfo")
public class KmlDroneInfo {
@XStreamAlias("wpml:droneEnumValue")
private String droneEnumValue;
@XStreamAlias("wpml:droneSubEnumValue")
private String droneSubEnumValue;
}

View File

@ -0,0 +1,140 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import lombok.Data;
import java.util.List;
/**
* 模板信息
*/
@Data
@XStreamAlias("Folder")
public class KmlFolder {
/**
* 预定义模板类型 必填
* waypoint航点飞行
* mapping2d建图航拍
* mapping3d倾斜摄影
* mappingStrip航带飞行
*/
@XStreamAlias("wpml:templateType")
private String templateType;
/**
* 模板ID 必填
* 0 0开始
*/
@XStreamAlias("wpml:templateId")
private String templateId;
// 以下为 wpml 文件使用
/**
* 执行高度模式
* WGS84椭球高模式
* relativeToStartPoint相对起飞点高度模式
* realTimeFollowSurface: 使用实时仿地模式仅支持M3E/M3T/M3M
*/
@XStreamAlias("wpml:executeHeightMode")
private String executeHeightMode;
/**
* 航线ID 0开始
*/
@XStreamAlias("wpml:waylineId")
private String waylineId;
/**
*
*/
@XStreamAlias("wpml:distance")
private String distance;
/**
*
*/
@XStreamAlias("wpml:duration")
private String duration;
@XStreamAlias("wpml:waylineCoordinateSysParam")
private KmlWayLineCoordinateSysParam waylineCoordinateSysParam;
/**
* 全局航线飞行速度 m/s 必填
*/
@XStreamAlias("wpml:autoFlightSpeed")
private String autoFlightSpeed;
/**
* 全局航线高度相对起飞点高度
*/
@XStreamAlias("wpml:globalHeight")
private String globalHeight;
/**
*
*/
@XStreamAlias("wpml:caliFlightEnable")
private String caliFlightEnable;
/**
* 云台俯仰角控制模式
* manual手动控制飞行器从一个航点飞向下一个航点的过程中支持用户手动控制云台的俯仰角度若无用户控制则保持飞离航点时的云台俯仰角度
* usePointSetting依照每个航点设置飞行器从一个航点飞向下一个航点的过程中云台俯仰角均匀过渡至下一个航点的俯仰角
*/
@XStreamAlias("wpml:gimbalPitchMode")
private String gimbalPitchMode;
//以下为航点飞行模板元素
/**
* 全局偏航角模式参数
*/
@XStreamAlias("wpml:globalWaypointHeadingParam")
private KmlGlobalWaypointHeadingParam globalWaypointHeadingParam;
/**
* 全局航点类型全局航点转弯模式
* coordinateTurn协调转弯不过点提前转弯
* toPointAndStopWithDiscontinuityCurvature直线飞行飞行器到点停
* toPointAndStopWithContinuityCurvature曲线飞行飞行器到点停
* toPointAndPassWithContinuityCurvature曲线飞行飞行器过点不停
*/
@XStreamAlias("wpml:globalWaypointTurnMode")
private String globalWaypointTurnMode;
/**
* 全局航段轨迹是否尽量贴合直线
* 0航段轨迹全程为曲线
* 1航段轨迹尽量贴合两点连线
*/
@XStreamAlias("wpml:globalUseStraightLine")
private String globalUseStraightLine;
/**
* 航点信息包括航点经纬度和高度等
*/
@XStreamImplicit(itemFieldName = "Placemark")
private List<KmlPlacemark> placemarkList;
/**
* TODO
* 航线初始动作
* *该元素用于规划一系列初始动作在航线开始前执行航线中断恢复时先执行初始动作再执行航点动作
*/
@XStreamAlias("wpml:startActionGroup")
private KmlActionGroup actionGroup;
/**
* 负载数据
*/
@XStreamAlias("wpml:payloadParam")
private KmlPayloadParam payloadParam;
}

View File

@ -0,0 +1,46 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 全局偏航角模式参数
*/
@Data
@XStreamAlias("wpml:globalWaypointHeadingParam")
public class KmlGlobalWaypointHeadingParam {
/**
* fixed:固定为用户设置的偏航角
* followWayline:偏航角跟随航线
*/
@XStreamAlias("wpml:waypointHeadingMode")
private String waypointHeadingMode;
/**
* 不知道啥 默认0
*/
@XStreamAlias("wpml:waypointHeadingAngle")
private String waypointHeadingAngle;
/**
* 不知道啥 默认0.000000,0.000000,0.000000
*/
@XStreamAlias("wpml:waypointPoiPoint")
private String waypointPoiPoint;
/**
* 不知道啥 followBadArc
*/
@XStreamAlias("wpml:waypointHeadingPathMode")
private String waypointHeadingPathMode;
/**
* 不知道啥 默认0
*/
@XStreamAlias("wpml:waypointHeadingPoiIndex")
private String waypointHeadingPoiIndex;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import lombok.Data;
@Data
@XStreamAlias("kml")
public class KmlInfo {
@XStreamAsAttribute
@XStreamAlias("xmlns")
private String xmlns = "http://www.opengis.net/kml/2.2";
@XStreamAsAttribute
@XStreamAlias("xmlns:wpml")
private String wpml = "http://www.dji.com/wpmz/1.0.4";
@XStreamAlias("Document")
private KmlDocument document;
}

View File

@ -0,0 +1,44 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:missionConfig")
public class KmlMissionConfig {
@XStreamAlias("wpml:flyToWaylineMode")
private String flyToWayLineMode;
@XStreamAlias("wpml:finishAction")
private String finishAction;
@XStreamAlias("wpml:exitOnRCLost")
private String exitOnRCLost;
@XStreamAlias("wpml:executeRCLostAction")
private String executeRCLostAction;
@XStreamAlias("wpml:takeOffSecurityHeight")
private String takeOffSecurityHeight;
@XStreamAlias("wpml:globalTransitionalSpeed")
private String globalTransitionalSpeed;
@XStreamAlias("wpml:globalRTHHeight")
private String globalRTHHeight;
@XStreamAlias("wpml:takeOffRefPoint")
private String takeOffRefPoint;
@XStreamAlias("wpml:takeOffRefPointAGLHeight")
private String takeOffRefPointAGLHeight;
@XStreamAlias("wpml:droneInfo")
private KmlDroneInfo droneInfo;
@XStreamAlias("wpml:payloadInfo")
private KmlPayloadInfo payloadInfo;
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 负载机型信息 type-subtype-gimbalindex
*/
@Data
@XStreamAlias("wpml:payloadInfo")
public class KmlPayloadInfo {
/**
* 相机枚举值 type
*/
@XStreamAlias("wpml:payloadEnumValue")
private String payloadEnumValue;
/**
* 相机枚举值 subtype
*/
@XStreamAlias("wpml:payloadSubEnumValue")
private String payloadSubEnumValue;
/**
* 相机枚举值 gimbalindex
*/
@XStreamAlias("wpml:payloadPositionIndex")
private String payloadPositionIndex;
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 负载设置
*/
@Data
@XStreamAlias("wpml:payloadParam")
public class KmlPayloadParam {
@XStreamAlias("wpml:payloadPositionIndex")
private String payloadPositionIndex;
@XStreamAlias("wpml:focusMode")
private String focusMode;
@XStreamAlias("wpml:meteringMode")
private String meteringMode;
@XStreamAlias("wpml:dewarpingEnable")
private String dewarpingEnable;
@XStreamAlias("wpml:returnMode")
private String returnMode;
@XStreamAlias("wpml:samplingRate")
private String samplingRate;
@XStreamAlias("wpml:scanningMode")
private String scanningMode;
@XStreamAlias("wpml:modelColoringEnable")
private String modelColoringEnable;
@XStreamAlias("wpml:imageFormat")
private String imageFormat;
}

View File

@ -0,0 +1,135 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("Placemark")
public class KmlPlacemark {
/**
* 航点经纬度<经度,纬度>
*/
@XStreamAlias("Point")
private KmlPoint kmlPoint;
/**
* 航点序号
* 在一条航线内该ID唯一该序号必须从0开始单调连续递增
*/
@XStreamAlias("wpml:index")
private String index;
/**
*
*/
@XStreamAlias("wpml:executeHeight")
private String executeHeight;
// 下面 wpml 文件使用
/**
* 航点高度WGS84椭球高度
*/
@XStreamAlias("wpml:ellipsoidHeight")
private String ellipsoidHeight;
/**
* 航点高度EGM96海拔高度/相对起飞点高度/AGL相对地面高度
*/
@XStreamAlias("wpml:height")
private String height;
/**
* 航点飞行速度 1,15 默认10
*/
@XStreamAlias("wpml:waypointSpeed")
private String waypointSpeed;
/**
* 偏航角模式参数
*/
@XStreamAlias("wpml:waypointHeadingParam")
private KmlWaypointHeadingParam waypointHeadingParam;
/**
* 航点类型航点转弯模式
*/
@XStreamAlias("wpml:waypointTurnParam")
private KmlWaypointTurnParam waypointTurnParam;
/**
* 是否使用全局高度 0, 1
*/
@XStreamAlias("wpml:useGlobalHeight")
private String useGlobalHeight;
/**
* 是否使用全局飞行速度 此处的全局飞行速度即wpml:autoFlightSpeed
* 0不使用全局设置
* 1使用全局设置
*/
@XStreamAlias("wpml:useGlobalSpeed")
private String useGlobalSpeed;
/**
* 是否使用全局偏航角模式参数 默认1
* 0不使用全局设置
* 1使用全局设置
*/
@XStreamAlias("wpml:useGlobalHeadingParam")
private String useGlobalHeadingParam;
/**
* 是否使用全局偏航角模式参数
* 0不使用全局设置
* 1使用全局设置
*/
@XStreamAlias("wpml:useGlobalTurnParam")
private String useGlobalTurnParam;
/**
* 该航段是否贴合直线
* 0航段轨迹全程为曲线
* 1航段轨迹尽量贴合两点连线
* 当且仅当wpml:waypointTurnParam"waypointTurnMode"被设置为toPointAndStopWithContinuityCurvaturetoPointAndPassWithContinuityCurvature时必需
* 如果此元素被设置则局部定义会覆盖全局定义
*/
@XStreamAlias("wpml:useStraightLine")
private String useStraightLine;
/**
* 航点云台俯仰角
* 对应机型云台可转动范围
*/
@XStreamAlias("wpml:gimbalPitchAngle")
private String gimbalPitchAngle;
/**
* 动作集合
*/
@XStreamAlias("wpml:actionGroup")
private KmlActionGroup actionGroup;
/**
*
*/
@XStreamAlias("wpml:waypointGimbalHeadingParam")
private KmlWaypointGimbalHeadingParam waypointGimbalHeadingParam;
/**
* 是否危险点
* 0正常点1危险点
*/
@XStreamAlias("wpml:isRisky")
private String isRisky;
/**
*
*/
@XStreamAlias("wpml:waypointWorkType")
private String waypointWorkType;
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
//@Data
@XStreamAlias("Point")
public class KmlPoint {
public String getCoordinates() {
return coordinates;
}
public void setCoordinates(String coordinates) {
String replace = coordinates.replace("\n", "");
this.coordinates = replace;
}
@XStreamAlias("coordinates")
private String coordinates;
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 坐标系参数
*/
@Data
@XStreamAlias("wpml:waylineCoordinateSysParam")
public class KmlWayLineCoordinateSysParam {
@XStreamAlias("wpml:coordinateMode")
private String coordinateMode;
@XStreamAlias("wpml:heightMode")
private String heightMode;
@XStreamAlias("wpml:positioningType")
private String positioningType;
@XStreamAlias("wpml:globalShootHeight")
private String globalShootHeight;
@XStreamAlias("wpml:surfaceFollowModeEnable")
private String surfaceFollowModeEnable;
@XStreamAlias("wpml:surfaceRelativeHeight")
private String surfaceRelativeHeight;
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:waypointGimbalHeadingParam")
public class KmlWaypointGimbalHeadingParam {
@XStreamAlias("wpml:waypointGimbalPitchAngle")
private String waypointGimbalPitchAngle;
@XStreamAlias("wpml:waypointGimbalYawAngle")
private String waypointGimbalYawAngle;
}

View File

@ -0,0 +1,48 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:waypointHeadingParam")
public class KmlWaypointHeadingParam {
/**
* 不知道是啥 默认followWayline
*/
@XStreamAlias("wpml:waypointHeadingMode")
private String waypointHeadingMode;
/**
* 不知道是啥 默认0
*/
@XStreamAlias("wpml:waypointHeadingAngle")
private String waypointHeadingAngle;
/**
* 不知道是啥 默认 0.000000,0.000000,0.000000
*/
@XStreamAlias("wpml:waypointPoiPoint")
private String waypointPoiPoint;
/**
* 不知道是啥 默认0
*/
@XStreamAlias("wpml:waypointHeadingAngleEnable")
private String waypointHeadingAngleEnable;
/**
* 不知道是啥 默认 followBadArc
*/
@XStreamAlias("wpml:waypointHeadingPathMode")
private String waypointHeadingPathMode;
/**
* 不知道是啥 默认 followBadArc 默认0
*/
@XStreamAlias("wpml:waypointHeadingPoiIndex")
private String waypointHeadingPoiIndex;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.airline.domain.model.kml;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("wpml:waypointTurnParam")
public class KmlWaypointTurnParam {
@XStreamAlias("wpml:waypointTurnMode")
private String waypointTurnMode;
@XStreamAlias("wpml:waypointTurnDampingDist")
private String waypointTurnDampingDist;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.airline.domain.model.kml;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 一个点
*/
@Data
public class NewGeoPoint implements Serializable {
/**
* 序号
*/
private int id;
/**
* 经度
*/
private double longitude;
/**
* 纬度
*/
private double latitude;
/**
* 航点动作
*/
private List<PointActionReq> actions ;
}

View File

@ -0,0 +1,49 @@
package com.ruoyi.airline.domain.model.kml;
import lombok.Data;
import java.io.Serializable;
@Data
public class PointActionReq implements Serializable {
/**
* 动作编号
*/
private Integer actionIndex;
/**
* 飞行器悬停等待时间
*/
private Integer hoverTime;
/**
* 飞行器目标偏航角
*/
private Double aircraftHeading;
/**
* 是否使用全局拍照模式 0不使用 1使用
*/
private Integer useGlobalImageFormat;
/**
* 拍照模式字典
*/
private String imageFormat;
/**
* 云台偏航角
*/
private Double gimbalYawRotateAngle;
/**
* 云台俯仰角
*/
private Double gimbalPitchRotateAngle;
/**
* 变焦焦距
*/
private Double zoom;
}

View File

@ -0,0 +1,37 @@
package com.ruoyi.airline.domain.model.kml;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class RoutePointReq implements Serializable {
/**
* 航点编号
*/
private Integer routePointIndex;
/**
* 经度
*/
private Double longitude;
/**
* 纬度
*/
private Double latitude;
/**
* 高度
*/
private Double height;
/**
* 航点动作列表
*/
private List<PointActionReq> actions;
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.airline.domain.uitl;
import com.ruoyi.airline.domain.model.kml.*;
import com.thoughtworks.xstream.XStream;
import java.io.InputStream;
/**
* 航线文件操作工具类
*/
public class KmlFileUtils {
/**
* kml文件解析
*
* @param inputStream 输入
* @return 输出
*/
public static KmlInfo parseKml(InputStream inputStream) {
XStream xStream = new XStream();
xStream.allowTypes(new Class[]{KmlInfo.class, KmlAction.class, KmlWayLineCoordinateSysParam.class, KmlPoint.class});
xStream.alias("kml", KmlInfo.class);
xStream.processAnnotations(KmlInfo.class);
xStream.autodetectAnnotations(true);
xStream.ignoreUnknownElements();
xStream.addImplicitCollection(KmlActionGroup.class, "action");
return (KmlInfo) xStream.fromXML(inputStream);
}
}

View File

@ -0,0 +1,299 @@
package com.ruoyi.airline.domain.uitl;
import com.ruoyi.airline.api.domain.AirLinePointVO;
import com.ruoyi.airline.domain.model.kml.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class WayPointUitls {
private static final Logger log = LoggerFactory.getLogger(WayPointUitls.class);
/**
* kmz转换waypoint并同时上传到OSS返回两个url
*
* @param kmlInfo
* @return
*/
public static byte[] kmz2waypoint(KmlInfo kmlInfo) {
//准备一个waypoint文件的标头文本
StringBuilder waypointBuilder = new StringBuilder("QGC WPL 110\n");
// 重置全局id计数器
//定义waypoint的航点对象集合备用
List<AirLinePointVO> linePoints = new ArrayList<>();
//m3和m4TD的机型可以从missionConfig获取部分基础数据
KmlMissionConfig missionConfig = kmlInfo.getDocument().getKmlMissionConfig();
//其他场景下都可以从missionConfig 拿航点和动作集合
List<KmlPlacemark> placeMarkList = kmlInfo.getDocument().getFolder().getPlacemarkList();
//获取kml文件中的第一个坐标
String[] takeoffCoords;
if (missionConfig.getTakeOffRefPoint() != null) {
takeoffCoords = missionConfig.getTakeOffRefPoint().split(",");
} else {
// M300/M350使用第一个航点的坐标
KmlPlacemark kmlPlacemark = placeMarkList.get(0);
String[] coords = kmlPlacemark.getKmlPoint().getCoordinates()
.replaceAll("[\\n ]", "")
.split(",");
takeoffCoords = new String[]{coords[1], coords[0]}; // 纬度, 经度
}
//1.设置waypoint文件的起飞点第一个command 16 不需要高度
linePoints.add(buildPoint(16,
takeoffCoords[0], takeoffCoords[1], 0,
null, null, null, null, 0, 0, 0
));
//2.设置waypoint文件的安全高度点command 22需要高度,使用第一个航点的高度
linePoints.add(buildPoint(22,
takeoffCoords[0], takeoffCoords[1],
Math.round(Float.parseFloat(placeMarkList.get(0).getHeight())), //高度转换成整数
null, null, null, null, 0, 0, 0
));
//3.处理普通航点和航线动作
for (KmlPlacemark placeMark : placeMarkList) {
// 航点坐标纬度+经度的排布顺序
KmlPoint point = placeMark.getKmlPoint();
String cleanCoords = point.getCoordinates().replaceAll("[\n ]", "");
String[] coords = cleanCoords.split(",");
// 基础航点安全点22和结束点20之间的其他16普通航点
AirLinePointVO waypoint = buildPoint(
16,
coords[1], coords[0],
(int) Float.parseFloat(placeMark.getHeight()),
null, null, null, null, 0, 0, 0
);
linePoints.add(waypoint);
// 解析该航点对应的附加动作如拍照悬停等
//先判断动作组有没有动作
KmlActionGroup actionGroup = placeMark.getActionGroup();
if (!ObjectUtils.isEmpty(actionGroup)) {
// 获取动作组中的动作列表
List<KmlAction> actionList = actionGroup.getAction();
//动作组没有动作也结束动作组合
if (!CollectionUtils.isEmpty(actionList)) {
// 遍历所有动作
for (KmlAction action : actionList) {
// 使用全局id累加
processActions(action, linePoints);
}
}
}
}
// 4. 返航点command 20
linePoints.add(buildPoint(20, takeoffCoords[0], takeoffCoords[1], Math.round(Float.parseFloat(placeMarkList.get(0).getHeight())), null, null, null, null, 0, 0, 0));
// 5. 生成Waypoints文件内容
for (int i = 0; i < linePoints.size(); i++) {
AirLinePointVO point = linePoints.get(i);
waypointBuilder.append(formatWaypointLine(point, i)).append("\n");
}
return waypointBuilder.toString().getBytes();
}
// 格式化航点行直接使用DTO字段
public static String formatWaypointLine(AirLinePointVO point, Integer index) {
switch (point.getCommand()) {
case 16:
if (index == 0) {
// 标准航点第一个16航点的时候字段3是0
return String.format(Locale.US,
"%d\t0\t0\t16\t0\t0\t0\t0\t%s\t%s\t%d.000000\t1",
index, point.getLat(), point.getLon(), point.getAlt());
} else {
//其他16的时候字段3是3
return String.format(Locale.US,
"%d\t0\t3\t16\t0\t0\t0\t0\t%s\t%s\t%d.000000\t1",
index, point.getLat(), point.getLon(), point.getAlt());
}
case 22: // 安全高度
return String.format(Locale.US,
"%d\t0\t3\t22\t0\t0\t0\t0\t%s\t%s\t%d.000000\t1",
index, point.getLat(), point.getLon(), point.getAlt());
case 93: // 悬停参数1=悬停时间
return String.format(Locale.US,
"%d\t0\t3\t93\t%s\t0\t0\t0\t0\t0\t0.000000\t1", index, point.getLoiterTime());
case 203: // 拍照没有参数只是个触发点
return String.format(Locale.US,
"%d\t0\t3\t203\t0\t0\t0\t0\t0\t0\t0.000000\t1", index);
case 205: // 云台角度参数1=俯仰角参数3=偏航角
return String.format(Locale.US,
"%d\t0\t3\t205\t%s\t0\t%s\t0\t0\t0\t0.000000\t1",
index, point.getCameraPitch(), point.getCameraYaw());
case 115: // 旋转无人机参数1=索引参数2=角度参数3=速度写死5参数4=方向写死1全都代表正向角度自带正负值避免负负得正参数5=1默认写死
return String.format(Locale.US,
"%d\t0\t3\t115\t%s\t5\t1\t1\t0\t0\t0.000000\t1",
index, point.getCameraYaw());
case 531: // 变焦第二个参数是变焦倍数
return String.format(Locale.US,
"%d\t0\t3\t531\t0\t%s\t0\t0\t0\t0\t0.000000\t1", index, point.getZoomAbsolute());
case 532: // 聚焦没有参数
return String.format(Locale.US,
"%d\t0\t3\t532\t0\t0\t0\t0\t0\t0\t0.000000\t1", index);
case 2500: // 视频录制无参数
return String.format("%d\t0\t3\t2500\t0\t0\t0\t0\t0\t0\t0.000000\t1", index);
case 2501: // 结束录制无参数
return String.format("%d\t0\t3\t2501\t0\t0\t0\t0\t0\t0\t0.000000\t1", index);
case 20: // 返航 使用的是第一个航点的经纬度和高度
return String.format("%d\t0\t3\t20\t0\t0\t0\t0\t%s\t%s\t%d.000000\t1", index, point.getLat(), point.getLon(), point.getAlt());
default:
throw new IllegalArgumentException("未知命令: " + point.getCommand());
}
}
// 动作解析逻辑
public static void processActions(KmlAction action, List<AirLinePointVO> linePoints) {
//kmz航线的动作code
String actionType = action.getActionActuatorFunc();
//动作参数
KmlActionActuatorFuncParam actionActuatorFuncParam = action.getActionActuatorFuncParam();
switch (actionType) {
case "hover":
// 悬停命令93
linePoints.add(buildPoint(
93,
"0", "0", 0,
actionActuatorFuncParam.getHoverTime(), // loiterTime悬停时间/s
"0",
"0",
"0",
0,
0,
0
));
break;
case "takePhoto":
// 拍照动作命令203 没啥参数
linePoints.add(buildPoint(
203,
"0", "0", 0,
"0",
"0",
"0",
"0",
0,
0,
0
));
break;
case "startRecord":
// 开始录像命令2500没啥参数
linePoints.add(buildPoint(
2500,
"0", "0", 0,
"0", "0", "0", "0",
0, 0, 0
));
break;
case "stopRecord":
// 结束录像命令2501 没啥参数
linePoints.add(buildPoint(
2501,
"0", "0", 0,
"0", "0", "0", "0",
0, 0, 0
));
break;
case "zoom":
// 变焦动作通过命令531的参数6实现
linePoints.add(buildPoint(
531,
"0", "0", 0,
"0", "0", "0", "0",
0,
Math.round(Float.parseFloat(actionActuatorFuncParam.getFocalLength()) / 24) //FocalLength=kmz的这个值的mm的焦距除24一般是最低焦距取绝对值得到变倍整数
, 0
));
break;
case "focus":
// 聚焦动作命令532 没啥参数
linePoints.add(buildPoint(
532,
"0", "0", 0,
"0", "0", "0", "0",
0, 0, 0
));
break;
case "gimbalRotate":
// 云台控制命令205
linePoints.add(buildPoint(
205,
"0", "0", 0,
"0",
String.valueOf(Math.round(Float.parseFloat(actionActuatorFuncParam.getGimbalPitchRotateAngle().toString()))), // 参数1=俯仰角 转换成整数
"0",
String.valueOf(Math.round(Float.parseFloat(actionActuatorFuncParam.getGimbalYawRotateAngle().toString()))), // 参数3=偏航角转换成整数
0, 0, 0
));
break;
case "rotateYaw":
// 无人机旋转命令115
linePoints.add(buildPoint(
115,
"0", "0", 0, "0", "0", "0",
String.valueOf(Math.round(Float.parseFloat(actionActuatorFuncParam.getAircraftHeading().toString()))), //旋转角度偏航角转换成整数
0, 0, "counterClockwise".equals(actionActuatorFuncParam.getAircraftPathMode()) ? -1 : 1 // 旋转方向逆时针/顺时针
));
break;
default:
log.error("未知动作类型: {}", actionType);
}
}
//构建waypoint航点
public static AirLinePointVO buildPoint(int command, String lat, String lon, int alt,
String loiterTime, String cameraPitch, String cameraRoll, String cameraYaw,
int sessionControl, int zoomAbsolute, int rotateDirection) {
AirLinePointVO point = new AirLinePointVO();
point.setCommand(command);
point.setLat(lat);
point.setLon(lon);
point.setAlt(alt);
point.setLoiterTime(loiterTime);
point.setCameraPitch(cameraPitch);
point.setCameraRoll(cameraRoll);
point.setCameraYaw(cameraYaw);
point.setSessionControl(sessionControl);
point.setZoomAbsolute(zoomAbsolute);
point.setRotateDirection(rotateDirection);
return point;
}
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.airline.mapper;
import com.ruoyi.airline.mapper.entity.AirlineDataEntity;
import java.util.List;
/**
* 航线数据Mapper接口
*
* @author ruoyi
* @date 2026-01-17
*/
public interface AirlineDataMapper
{
List<AirlineDataEntity> selectAirlineDataList(AirlineDataEntity entity);
AirlineDataEntity selectAirlineDataById(Long id);
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.airline.mapper;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity;
import java.util.List;
/**
* 航线分组明细表 airline_file_group
*
* @author 拓恒
*/
public interface AirlineFileGroupInfoMapper {
List<AirlineFileGroupInfoEntity> selectGroupList(AirlineFileGroupInfoEntity entity);
int deleteGroupInfo(AirlineFileGroupInfoEntity entity);
AirlineFileGroupInfo save(AirlineFileGroupInfoEntity entity);
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.airline.mapper;
import com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity;
import java.util.List;
/**
* 航线分组表 airline_group
*
* @author 拓恒
*/
public interface AirlineFileGroupMapper {
int checkgroupNameUnique(AirlineFileGroupEntity model);
int deletegroup(AirlineFileGroupEntity entity);
int updateGroup(AirlineFileGroupEntity entity);
int insertGroup(AirlineFileGroupEntity entity);
List<AirlineFileGroupEntity> selectGroupList(AirlineFileGroupEntity entity);
}

View File

@ -0,0 +1,19 @@
package com.ruoyi.airline.mapper;
import com.ruoyi.airline.mapper.entity.AirlineFileEntity;
import java.util.List;
/**
* 航线文件Mapper接口
*
* @author ruoyi
* @date 2026-01-17
*/
public interface AirlineFileMapper {
AirlineFileEntity save(AirlineFileEntity entity);
List<AirlineFileEntity> selectFileListByIds(List<Long> ids);
}

View File

@ -0,0 +1,70 @@
package com.ruoyi.airline.mapper.entity;
import com.ruoyi.common.core.web.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 航线数据表实体对象 tuoheng_airline_data
* Mapper 层实体对应数据库表
*
* @author ruoyi
* @date 2026-01-17
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AirlineDataEntity extends BaseEntity
{
private static final long serialVersionUID = 1L;
/* 主机Ip*/
private String hostIp;
/* 任务id*/
private int inspectionId;
private int recordId;
/**
* lng
*/
private String lng;
/**
* lat
*/
private String lat;
/**
* 高度
*/
private String altitude;
/**
* 实时时间
*/
private String timestamp;
private long flyTime;
private String requestId;
private String hspeed;
private String vspeed;
private String ysingal;
//地速
private String velocity;
private String airspeed;
private String dv;
private String roll;
private String yaw;
private String gps;
private String pitch;
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.airline.mapper.entity;
import com.ruoyi.common.core.web.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
* 航线文件表
* </p>
*
* @author 拓恒
* @since 2021-09-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class AirlineFileEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
private Long id;
/**
* 航线名称
*/
private String name;
/**
* 飞行器厂商
*/
private String airVendor;
/**
* 飞行器类型
*/
private String airType;
/**
* 文件名称
*/
private String fileName;
/**
* 文件地址
*/
private String fileUrl;
/**
* 航线类型1,航点航线;2,指点航线;3,指面航线
*/
private Integer type;
/**
* 数据来源
*/
private String source;
/**
* 1 启用 0 停用默认启用
*/
private Integer status;
/**
* 航线文件对应的 MD5指纹
*/
private String fileMd5;
}

View File

@ -0,0 +1,40 @@
package com.ruoyi.airline.mapper.entity;
import com.ruoyi.common.core.web.domain.ExBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 航线分组表 airline_group
*
* @author 拓恒
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AirlineFileGroupEntity extends ExBaseEntity {
/**
* 用户ID
*/
private Long groupId;
/**
* 分组名称
*/
private String groupName;
/**
* 用户ID分组自带用户归属 后期权限都是基于用户ID进行
*/
private Long userId;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("groupId", getGroupId())
.append("groupName", getGroupName())
.append("userId", getUserId())
.toString();
}
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.airline.mapper.entity;
import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.web.domain.ExBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 航线分组明细表 airline_file_group
*
* @author 拓恒
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AirlineFileGroupInfoEntity extends ExBaseEntity {
/**
* id,主键
*/
private Long id;
/**
* 用户ID
*/
private Long groupId;
/**
* 航线id
*/
private Long airlineId;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("groupId", getGroupId())
.append("airlineId", getAirlineId())
.toString();
}
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.airline.service.api;
import com.ruoyi.airline.service.dto.AirlineDataDTO;
import java.util.List;
/**
* 航线数据Service接口
*
* @author ruoyi
* @date 2026-01-17
*/
public interface IAirlineDataService
{
/**
* 查询航线数据列表
*
* @param airlineDataDTO 航线数据
* @return 航线数据集合
*/
List<AirlineDataDTO> selectAirlineDataList(AirlineDataDTO airlineDataDTO);
/**
* 根据ID查询航线数据
*
* @param id 主键ID
* @return 航线数据
*/
AirlineDataDTO selectAirlineDataById(Long id);
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.airline.service.api;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 航线分组明细
*
* @author 拓恒
*/
public interface IAirlineFileGroupInfoService {
List<AirlineFileGroupInfoDTO> selectGroupInfoListById(Long groupId);
AirlineFileGroupInfoDTO save(AirlineFileGroupInfoDTO dto) throws IOException;
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.airline.service.api;
import com.ruoyi.airline.service.dto.AirlineFileGroupDTO;
import java.util.List;
/**
* 航线分组
*
* @author 拓恒
*/
public interface IAirlineFileGroupService {
int deletegroupById(Long userId, Long groupId);
/**
* 检查名称是否已经存在
* @param group
* @return
*/
boolean checkGroupNameUnique(AirlineFileGroupDTO group);
int updateGroup(AirlineFileGroupDTO group);
int insertGroup(AirlineFileGroupDTO group);
List<AirlineFileGroupDTO> selectGroupList(AirlineFileGroupDTO dto);
AirlineFileGroupDTO selectAirLineListsByGroupId(Long userId, Long groupId);
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.airline.service.api;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* 航线文件Service接口
*
* @author ruoyi
* @date 2026-01-17
*/
public interface IAirlineFileService {
AirlineFileDTO save(AirlineFileDTO dto);
AirlineFileDTO parseAndUplload(MultipartFile file);
AirlineFileDTO createOrupdate(AirlineFileDTO airlineFile) throws IOException;
}

View File

@ -0,0 +1,95 @@
package com.ruoyi.airline.service.convert;
import com.ruoyi.airline.service.dto.AirlineDataDTO;
import com.ruoyi.airline.domain.model.AirlineData;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线数据Service转换类
* 用于Service DTO和Domain模型之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineDataServiceConvert
{
/**
* 将Service DTO转换为Domain模型
*
* @param dto Service DTO
* @return Domain模型
*/
public static AirlineData toModel(AirlineDataDTO dto)
{
if (dto == null) {
return null;
}
AirlineData model = new AirlineData();
model.setId(dto.getId());
model.setFlightNumber(dto.getFlightNumber());
model.setDepartureCity(dto.getDepartureCity());
model.setArrivalCity(dto.getArrivalCity());
model.setAirspeed(dto.getAirspeed());
model.setVelocity(dto.getVelocity());
model.setVspeed(dto.getVspeed());
model.setHspeed(dto.getHspeed());
return model;
}
/**
* 将Domain模型转换为Service DTO
*
* @param model Domain模型
* @return Service DTO
*/
public static AirlineDataDTO toDTO(AirlineData model)
{
if (model == null) {
return null;
}
AirlineDataDTO dto = new AirlineDataDTO();
dto.setId(model.getId());
dto.setFlightNumber(model.getFlightNumber());
dto.setDepartureCity(model.getDepartureCity());
dto.setArrivalCity(model.getArrivalCity());
dto.setAirspeed(model.getAirspeed());
dto.setVelocity(model.getVelocity());
dto.setVspeed(model.getVspeed());
dto.setHspeed(model.getHspeed());
return dto;
}
/**
* 将Domain模型列表转换为Service DTO列表
*
* @param modelList Domain模型列表
* @return Service DTO列表
*/
public static List<AirlineDataDTO> toDTOList(List<AirlineData> modelList)
{
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineDataServiceConvert::toDTO)
.collect(Collectors.toList());
}
/**
* 将Service DTO列表转换为Domain模型列表
*
* @param dtoList Service DTO列表
* @return Domain模型列表
*/
public static List<AirlineData> toModelList(List<AirlineDataDTO> dtoList)
{
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineDataServiceConvert::toModel)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,82 @@
package com.ruoyi.airline.service.convert;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileGroupInfoServiceConvert {
/**
* 将Domain模型转换为Mapper实体
*
* @param model Domain模型
* @return Mapper实体
*/
public static AirlineFileGroupInfoDTO toDTO(AirlineFileGroupInfo model) {
if (model == null) {
return null;
}
AirlineFileGroupInfoDTO dto = new AirlineFileGroupInfoDTO();
dto.setId(model.getId());
dto.setGroupId(model.getGroupId());
dto.setAirlineId(model.getAirlineId());
return dto;
}
/**
* 将Mapper实体转换为Domain模型
*
* @param dto Mapper实体
* @return Domain模型
*/
public static AirlineFileGroupInfo toModel(AirlineFileGroupInfoDTO dto) {
if (dto == null) {
return null;
}
AirlineFileGroupInfo model = new AirlineFileGroupInfo();
model.setId(dto.getId());
model.setGroupId(dto.getGroupId());
model.setAirlineId(dto.getAirlineId());
return model;
}
/**
* 将Mapper实体列表转换为Domain模型列表
*
* @param entityList Mapper实体列表
* @return Domain模型列表
*/
public static List<AirlineFileGroupInfo> toModelList(List<AirlineFileGroupInfoDTO> entityList) {
if (entityList == null || entityList.isEmpty()) {
return null;
}
return entityList.stream()
.map(AirlineFileGroupInfoServiceConvert::toModel)
.collect(Collectors.toList());
}
/**
* 将Domain模型列表转换为Mapper实体列表
*
* @param modelList Domain模型列表
* @return Mapper实体列表
*/
public static List<AirlineFileGroupInfoDTO> toDtoList(List<AirlineFileGroupInfo> modelList) {
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineFileGroupInfoServiceConvert::toDTO)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,92 @@
package com.ruoyi.airline.service.convert;
import com.ruoyi.airline.domain.model.AirlineFile;
import com.ruoyi.airline.domain.model.AirlineFileGroup;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupDTO;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件分组Domain转换类
* 用于Domain模型和Mapper实体之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileGroupServiceConvert {
/**
* 将Domain模型转换为Mapper实体
*
* @param model Domain模型
* @return Mapper实体
*/
public static AirlineFileGroupDTO toDTO(AirlineFileGroup model) {
if (model == null) {
return null;
}
AirlineFileGroupDTO dto = new AirlineFileGroupDTO();
dto.setGroupId(model.getGroupId());
dto.setGroupName(model.getGroupName());
dto.setUserId(model.getUserId());
dto.setCreateBy(model.getCreateBy());
dto.setUpdateBy(model.getUpdateBy());
dto.setRemark(model.getRemark());
return dto;
}
/**
* 将Mapper实体转换为Domain模型
*
* @param dto Mapper实体
* @return Domain模型
*/
public static AirlineFileGroup toModel(AirlineFileGroupDTO dto) {
if (dto == null) {
return null;
}
AirlineFileGroup model = new AirlineFileGroup();
model.setGroupId(dto.getGroupId());
model.setGroupName(dto.getGroupName());
model.setUserId(dto.getUserId());
model.setCreateBy(dto.getCreateBy());
model.setCreateTime(dto.getCreateTime() != null ? dto.getCreateTime(): null);
model.setUpdateBy(dto.getUpdateBy());
model.setUpdateTime(dto.getUpdateTime() != null ? dto.getUpdateTime(): null);
model.setRemark(dto.getRemark());
return model;
}
/**
* 将Domain模型列表转换为Service DTO列表
*
* @param modelList Domain模型列表
* @return Service DTO列表
*/
public static List<AirlineFileGroupDTO> toDTOList(List<AirlineFileGroup> modelList) {
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineFileGroupServiceConvert::toDTO)
.collect(Collectors.toList());
}
/**
* 将Service DTO列表转换为Domain模型列表
*
* @param dtoList Service DTO列表
* @return Domain模型列表
*/
public static List<AirlineFileGroup> toModelList(List<AirlineFileGroupDTO> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineFileGroupServiceConvert::toModel)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,115 @@
package com.ruoyi.airline.service.convert;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.airline.domain.model.AirlineFile;
import java.util.List;
import java.util.stream.Collectors;
/**
* 航线文件Service转换类
* 用于Service DTO和Domain模型之间的转换
*
* @author ruoyi
* @date 2026-01-17
*/
public class AirlineFileServiceConvert {
/**
* 将Service DTO转换为Domain模型
*
* @param dto Service DTO
* @return Domain模型
*/
public static AirlineFile toModel(AirlineFileDTO dto) {
if (dto == null) {
return null;
}
AirlineFile model = new AirlineFile();
model.setId(dto.getId());
model.setFileName(dto.getFileName());
model.setFileUrl(dto.getFileUrl());
model.setType(dto.getType());
model.setNote(dto.getNote());
model.setDistance(dto.getDistance());
model.setLinePointDtoList(dto.getLinePointDtoList());
model.setSource(dto.getSource());
model.setStatus(dto.getStatus());
model.setFileMd5(dto.getFileMd5());
model.setDjiFileUrl(dto.getDjiFileUrl());
model.setDjiRthAltitude(dto.getDjiRthAltitude());
model.setTurnRadius(dto.getTurnRadius());
model.setAutoTakePhoto(dto.getAutoTakePhoto());
model.setAutoTakePhotoInterval(dto.getAutoTakePhotoInterval());
model.setCreateBy(dto.getCreateBy());
model.setCreateTime(dto.getCreateTime());
model.setUpdateBy(dto.getUpdateBy());
model.setUpdateTime(dto.getUpdateTime());
model.setRemark(dto.getRemark());
return model;
}
/**
* 将Domain模型转换为Service DTO
*
* @param model Domain模型
* @return Service DTO
*/
public static AirlineFileDTO toDTO(AirlineFile model) {
if (model == null) {
return null;
}
AirlineFileDTO dto = new AirlineFileDTO();
dto.setId(model.getId());
dto.setFileName(model.getFileName());
dto.setFileUrl(model.getFileUrl());
dto.setType(model.getType());
dto.setNote(model.getNote());
dto.setDistance(model.getDistance());
dto.setLinePointDtoList(model.getLinePointDtoList());
dto.setSource(model.getSource());
dto.setStatus(model.getStatus());
dto.setFileMd5(model.getFileMd5());
dto.setDjiFileUrl(model.getDjiFileUrl());
dto.setDjiRthAltitude(model.getDjiRthAltitude());
dto.setTurnRadius(model.getTurnRadius());
dto.setAutoTakePhoto(model.getAutoTakePhoto());
dto.setAutoTakePhotoInterval(model.getAutoTakePhotoInterval());
dto.setCreateBy(model.getCreateBy());
dto.setCreateTime(model.getCreateTime());
dto.setUpdateBy(model.getUpdateBy());
dto.setUpdateTime(model.getUpdateTime());
dto.setRemark(model.getRemark());
return dto;
}
/**
* 将Domain模型列表转换为Service DTO列表
*
* @param modelList Domain模型列表
* @return Service DTO列表
*/
public static List<AirlineFileDTO> toDTOList(List<AirlineFile> modelList) {
if (modelList == null || modelList.isEmpty()) {
return null;
}
return modelList.stream()
.map(AirlineFileServiceConvert::toDTO)
.collect(Collectors.toList());
}
/**
* 将Service DTO列表转换为Domain模型列表
*
* @param dtoList Service DTO列表
* @return Domain模型列表
*/
public static List<AirlineFile> toModelList(List<AirlineFileDTO> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return null;
}
return dtoList.stream()
.map(AirlineFileServiceConvert::toModel)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,54 @@
package com.ruoyi.airline.service.dto;
import lombok.Data;
/**
* 航线数据DTO
* Service 层数据传输对象用于Controller和Service之间的数据传递
*
* @author ruoyi
* @date 2026-01-17
*/
@Data
public class AirlineDataDTO
{
/** 主键ID */
private Long id;
/** 航班号 */
private String flightNumber;
/** 起飞城市 */
private String departureCity;
/** 到达城市 */
private String arrivalCity;
/** 空气速度 */
private Double airspeed;
/** 速度 */
private Double velocity;
/** 垂直速度 */
private Double vspeed;
/** 水平速度 */
private Double hspeed;
@Override
public String toString()
{
return "AirlineDataDTO{" +
"id=" + id +
", flightNumber='" + flightNumber + '\'' +
", departureCity='" + departureCity + '\'' +
", arrivalCity='" + arrivalCity + '\'' +
", airspeed=" + airspeed +
", velocity=" + velocity +
", vspeed=" + vspeed +
", hspeed=" + hspeed +
'}';
}
}

View File

@ -0,0 +1,154 @@
package com.ruoyi.airline.service.dto;
import com.ruoyi.airline.api.domain.AirLinePointVO;
import lombok.Data;
import java.util.List;
/**
* 航线文件DTO
* Service 层数据传输对象用于Controller和Service之间的数据传递
*
* @author ruoyi
* @date 2026-01-17
*/
@Data
public class AirlineFileDTO {
/**
* 主键ID
*/
private Long id;
/**
* 文件名称
*/
private String fileName;
/**
* 飞行器厂商
*/
private String airVendor;
/**
* 飞行器类型
*/
private String airType;
/**
* 文件地址
*/
private String fileUrl;
/**
* 航线类型1,航点航线;2,指点航线;3,指面航线
*/
private Integer type;
/**
* 文件备注
*/
private String note;
/**
* 航线距离
*/
private Double distance;
/**
* 航线点列表
*/
private List<AirLinePointVO> linePointDtoList;
/**
* 关联机场id
*/
private Integer airportId;
/**
* 数据来源
*/
private String source;
/**
* 1 启用 0 停用
*/
private Integer status;
/**
* 航线文件对应的 MD5指纹
*/
private String fileMd5;
/**
* 大疆航线对应的oss地址可能存kmz也可能存waypoint要看fileUrl存的是啥这个字段存反的
*/
private String djiFileUrl;
/**
* kmz航线的全局高度
*/
private Integer djiRthAltitude;
/**
* 航线转弯类型 1-直线2-协调转弯
*/
private Integer turnRadius;
/**
* 是否需要自动拍照
*/
private Integer autoTakePhoto;
/**
* 自动拍照间隔时间
*/
private Integer autoTakePhotoInterval;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private String createTime;
/**
* 更新者
*/
private String updateBy;
/**
* 更新时间
*/
private String updateTime;
/**
* 备注
*/
private String remark;
@Override
public String toString() {
return "AirlineFileDTO{" +
"id=" + id +
", fileName='" + fileName + '\'' +
", fileUrl='" + fileUrl + '\'' +
", type=" + type +
", note='" + note + '\'' +
", distance=" + distance +
", linePointDtoList=" + linePointDtoList +
", airportId=" + airportId +
", source='" + source + '\'' +
", status=" + status +
", fileMd5='" + fileMd5 + '\'' +
", djiFileUrl='" + djiFileUrl + '\'' +
", djiRthAltitude=" + djiRthAltitude +
", turnRadius=" + turnRadius +
", autoTakePhoto=" + autoTakePhoto +
", autoTakePhotoInterval=" + autoTakePhotoInterval +
'}';
}
}

View File

@ -0,0 +1,45 @@
package com.ruoyi.airline.service.dto;
import com.ruoyi.common.core.web.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.List;
/**
* 航线分组表 airline_group
*
* @author 拓恒
*/
@Data
public class AirlineFileGroupDTO extends BaseEntity {
/**
* 用户ID
*/
private Long groupId;
/**
* 分组名称
*/
private String groupName;
/**
* 用户ID分组自带用户归属 后期权限都是基于用户ID进行
*/
private Long userId;
/**
* 组关联的航线
*/
private List<AirlineFileDTO> groupInfos;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("groupId", getGroupId())
.append("groupName", getGroupName())
.append("userId", getUserId())
.toString();
}
}

View File

@ -0,0 +1,40 @@
package com.ruoyi.airline.service.dto;
import com.ruoyi.common.core.web.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 航线分组明细表 airline_file_group
*
* @author 拓恒
*/
@Data
public class AirlineFileGroupInfoDTO extends BaseEntity {
/**
* id,主键
*/
private Long id;
/**
* 用户ID
*/
private Long groupId;
/**
* 航线id
*/
private Long airlineId;
private AirlineFileDTO airlineFileDTO;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("groupId", getGroupId())
.append("airlineId", getAirlineId())
.toString();
}
}

View File

@ -0,0 +1,52 @@
package com.ruoyi.airline.service.impl;
import com.ruoyi.airline.service.api.IAirlineDataService;
import com.ruoyi.airline.service.dto.AirlineDataDTO;
import com.ruoyi.airline.service.convert.AirlineDataServiceConvert;
import com.ruoyi.airline.domain.api.IAirlineDataDomain;
import com.ruoyi.airline.domain.model.AirlineData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 航线数据Service实现类
*
* @author ruoyi
* @date 2026-01-17
*/
@Service
public class AirlineDataServiceImpl implements IAirlineDataService
{
@Autowired
private IAirlineDataDomain airlineDataDomain;
/**
* 查询航线数据列表
*
* @param airlineDataDTO 航线数据
* @return 航线数据集合
*/
@Override
public List<AirlineDataDTO> selectAirlineDataList(AirlineDataDTO airlineDataDTO)
{
AirlineData model = AirlineDataServiceConvert.toModel(airlineDataDTO);
List<AirlineData> modelList = airlineDataDomain.selectAirlineDataList(model);
return AirlineDataServiceConvert.toDTOList(modelList);
}
/**
* 根据ID查询航线数据
*
* @param id 主键ID
* @return 航线数据
*/
@Override
public AirlineDataDTO selectAirlineDataById(Long id)
{
AirlineData model = airlineDataDomain.selectAirlineDataById(id);
return AirlineDataServiceConvert.toDTO(model);
}
}

View File

@ -0,0 +1,120 @@
package com.ruoyi.airline.service.impl;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.ruoyi.airline.domain.api.IAirlineFileDomain;
import com.ruoyi.airline.domain.api.IAirlineFileGroupDomain;
import com.ruoyi.airline.domain.api.IAirlineFileGroupInfoDomain;
import com.ruoyi.airline.domain.model.AirlineFileGroup;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.service.api.IAirlineFileGroupInfoService;
import com.ruoyi.airline.service.api.IAirlineFileGroupService;
import com.ruoyi.airline.service.convert.AirlineFileGroupInfoServiceConvert;
import com.ruoyi.airline.service.convert.AirlineFileGroupServiceConvert;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import com.ruoyi.common.core.exception.base.BaseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 航线文件Service实现类
*
* @author ruoyi
* @date 2026-01-17
*/
@Service
public class AirlineFileServiceGroupImpl implements IAirlineFileGroupService {
private static final Logger log = LoggerFactory.getLogger(AirlineFileServiceGroupImpl.class);
@Autowired
private IAirlineFileGroupDomain iAirlineFileGroupDomain;
@Autowired
private IAirlineFileGroupInfoDomain iAirlineFileGroupInfoDomain;
@Autowired
private IAirlineFileGroupInfoService iAirlineFileGroupInfoService;
@Autowired
private IAirlineFileDomain iAirlineFileDomain;
@Override
public int deletegroupById(Long userId, Long groupId) {
// 1删除航线信息
AirlineFileGroupInfoDTO dto = new AirlineFileGroupInfoDTO();
dto.setGroupId(groupId);
AirlineFileGroupInfo model = AirlineFileGroupInfoServiceConvert.toModel(dto);
int result = iAirlineFileGroupInfoDomain.deleteGroupInfo(model);
if (result > 0) {
// 2删除分组
AirlineFileGroup model2 = new AirlineFileGroup();
model2.setGroupId(groupId);
model2.setUserId(userId);
return iAirlineFileGroupDomain.deletegroup(model2);
}
// TODO 增加事务机制
throw new BaseException("删除航线失败");
}
@Override
public boolean checkGroupNameUnique(AirlineFileGroupDTO group) {
AirlineFileGroup model = AirlineFileGroupServiceConvert.toModel(group);
return iAirlineFileGroupDomain.checkgroupNameUnique(model);
}
@Override
public int updateGroup(AirlineFileGroupDTO group) {
AirlineFileGroup model = AirlineFileGroupServiceConvert.toModel(group);
return iAirlineFileGroupDomain.updateGroup(model);
}
@Override
public int insertGroup(AirlineFileGroupDTO group) {
AirlineFileGroup model = AirlineFileGroupServiceConvert.toModel(group);
return iAirlineFileGroupDomain.insertGroup(model);
}
/**
* 查询分组列表
*
* @param group
* @return
*/
@Override
public List<AirlineFileGroupDTO> selectGroupList(AirlineFileGroupDTO group) {
AirlineFileGroup model = AirlineFileGroupServiceConvert.toModel(group);
return AirlineFileGroupServiceConvert.toDTOList(iAirlineFileGroupDomain.selectGroupList(model));
}
/**
* 根据分组ID 查询 分组下所有的 航线文件
*
* @param groupId 分组id
* @return
*/
@Override
public AirlineFileGroupDTO selectAirLineListsByGroupId(Long userId, Long groupId) {
AirlineFileGroupDTO dto = new AirlineFileGroupDTO();
dto.setUserId(userId);
dto.setGroupId(groupId);
List<AirlineFileGroupInfo> airlineFileGroupInfoDTOS = iAirlineFileGroupInfoDomain.selectGroupInfoListById(groupId);
if (!CollectionUtils.isEmpty(airlineFileGroupInfoDTOS)) {
List<Long> ids = airlineFileGroupInfoDTOS.stream().map(AirlineFileGroupInfo::getAirlineId).toList();
List<AirlineFileDTO> airlineFileDTOS = iAirlineFileDomain.selectFileListByIds(ids);
dto.setGroupInfos(airlineFileDTOS);
}
return dto;
}
}

View File

@ -0,0 +1,54 @@
package com.ruoyi.airline.service.impl;
import com.ruoyi.airline.domain.api.IAirlineFileGroupInfoDomain;
import com.ruoyi.airline.domain.model.AirlineFileGroupInfo;
import com.ruoyi.airline.service.api.IAirlineFileGroupInfoService;
import com.ruoyi.airline.service.api.IAirlineFileService;
import com.ruoyi.airline.service.convert.AirlineFileGroupInfoServiceConvert;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.airline.service.dto.AirlineFileGroupInfoDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 航线文件Service实现类
*
* @author ruoyi
* @date 2026-01-17
*/
@Service
public class AirlineFileServiceGroupInfoImpl implements IAirlineFileGroupInfoService {
private static final Logger log = LoggerFactory.getLogger(AirlineFileServiceGroupInfoImpl.class);
@Autowired
private IAirlineFileService iAirlineFileService;
@Autowired
private IAirlineFileGroupInfoDomain iAirlineFileGroupInfoDomain;
@Override
public List<AirlineFileGroupInfoDTO> selectGroupInfoListById(Long groupId) {
List<AirlineFileGroupInfo> models = iAirlineFileGroupInfoDomain.selectGroupInfoListById(groupId);
return AirlineFileGroupInfoServiceConvert.toDtoList(models);
}
@Override
public AirlineFileGroupInfoDTO save(AirlineFileGroupInfoDTO dto) throws IOException {
AirlineFileDTO result = iAirlineFileService.save(dto.getAirlineFileDTO());
dto.setAirlineFileDTO(result);
// 保存分组信息
AirlineFileGroupInfo model = AirlineFileGroupInfoServiceConvert.toModel(dto);
AirlineFileGroupInfo airlineFileGroupInfoDTO = iAirlineFileGroupInfoDomain.save(model);
return AirlineFileGroupInfoServiceConvert.toDTO(airlineFileGroupInfoDTO);
}
}

View File

@ -0,0 +1,146 @@
package com.ruoyi.airline.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.airline.api.domain.AirLinePointVO;
import com.ruoyi.airline.domain.api.IAirlineFileDomain;
import com.ruoyi.airline.domain.model.AirlineFile;
import com.ruoyi.airline.domain.model.kml.KmlInfo;
import com.ruoyi.airline.domain.uitl.KmlFileUtils;
import com.ruoyi.airline.domain.uitl.WayPointUitls;
import com.ruoyi.airline.service.api.IAirlineFileService;
import com.ruoyi.airline.service.convert.AirlineFileServiceConvert;
import com.ruoyi.airline.service.dto.AirlineFileDTO;
import com.ruoyi.common.core.exception.base.BaseException;
import com.ruoyi.file.service.ISysFileService;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
* 航线文件Service实现类
*
* @author ruoyi
* @date 2026-01-17
*/
@Service
public class AirlineFileServiceImpl implements IAirlineFileService {
private static final Logger log = LoggerFactory.getLogger(AirlineFileServiceImpl.class);
//
// @Autowired
// private ISysFileService iSysFileService;
@Autowired
private IAirlineFileDomain iAirlineFileDomain;
@Override
public AirlineFileDTO save(AirlineFileDTO dto) {
AirlineFile model = AirlineFileServiceConvert.toModel(dto);
AirlineFile result = iAirlineFileDomain.save(model);
return AirlineFileServiceConvert.toDTO(result);
}
/**
* 上传航线文件如果是KMZ的需要转换成 waypoint 并且需要将 原始航线文件保存
* 并且限制航线修改因为暂时没做到 从waypoingt KMZ
*
* @param file
* @return
*/
@Override
public AirlineFileDTO parseAndUplload(MultipartFile file) {
KmlInfo kmlInfo = new KmlInfo();
try (ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(file.getInputStream()); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
ArchiveEntry entry;
while (!Objects.isNull(entry = archiveInputStream.getNextEntry())) {
String name = entry.getName();
if (name.toLowerCase().endsWith(".kml")) {
// 解KML文件
kmlInfo = KmlFileUtils.parseKml(archiveInputStream);
}
}
if (Objects.isNull(kmlInfo)) {
throw new BaseException("kmz文件内容缺失");
}
String globalHeight = kmlInfo.getDocument().getFolder().getGlobalHeight();
out.write(WayPointUitls.kmz2waypoint(kmlInfo));
String fileUrl = "";
//TODO String fileUrl = iSysFileService.uploadFileByStream(UUID.randomUUID().toString(), "waypoints", out);
AirlineFileDTO dto = new AirlineFileDTO();
dto.setFileUrl(fileUrl);
dto.setAirVendor("");
dto.setAirType("");
// 原始文件 目录存储
// dto.setFileUrl(fileUrl);
return dto;
} catch (IOException e) {
throw new BaseException("Waypoints文件生成失败");
} catch (Exception e) {
log.error("kmz航线转换失败", e);
throw new BaseException("kmz航线转换失败");
}
}
/**
* 航点编辑直接将大疆KMZ转换成waypoints操作就不需要区分大疆还是拓恒了
*
* @param airlineFile 航线文件dto
* @return
*/
@Override
public AirlineFileDTO createOrupdate(AirlineFileDTO airlineFile) {
StringBuilder waypointBuilder = new StringBuilder("QGC WPL 110\n");
List<AirLinePointVO> LineDto = airlineFile.getLinePointDtoList();
// 新建字节输出流,Freemarker操作此输出流写入生成的业务文件.
try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
if (LineDto != null && !LineDto.isEmpty()) {
for (int i = 0; i < LineDto.size(); i++) {
AirLinePointVO point = LineDto.get(i);
waypointBuilder.append(WayPointUitls.formatWaypointLine(point, i)).append("\n");
}
// 生成文件
out.write(waypointBuilder.toString().getBytes());
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
// 上传文件
String fileUrl = "";
//TODO String fileUrl = iSysFileService.uploadFileByStream(UUID.randomUUID().toString(), "waypoints", out);
out.close();
in.close();
//保存航线文件数据
airlineFile.setFileUrl(fileUrl);
airlineFile.setSource("airport");
airlineFile.setStatus(airlineFile.getStatus() == null ? 1 : airlineFile.getStatus());
AirlineFile model = AirlineFileServiceConvert.toModel(airlineFile);
AirlineFile result = iAirlineFileDomain.save(model);
return AirlineFileServiceConvert.toDTO(result);
}
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,10 +1,11 @@
Spring Boot Version: ${spring-boot.version} Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name} Spring Application Name: ${spring.application.name}
_ _ _ _
(_) | | _ _ _ _ _
_ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___ | | | | (_) | (_)
| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ | |_ _ _ ___ | |__ ___ _ __ __ _ ______ __ _ _ _ __| |_ _ __ ___
| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | | | __| | | |/ _ \| '_ \ / _ \ '_ \ / _` |______/ _` | | '__| | | '_ \ / _ \
|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_| | |_| |_| | (_) | | | | __/ | | | (_| | | (_| | | | | | | | | | __/
__/ | __/ | \__|\__,_|\___/|_| |_|\___|_| |_|\__, | \__,_|_|_| |_|_|_| |_|\___|
|___/ |___/ __/ |
|___/

View File

@ -1,15 +1,15 @@
# Tomcat # Tomcat
server: server:
port: 9211 port: 9210
# Spring # Spring
spring: spring:
application: application:
# 应用名称 # 应用名称
name: tuoheng-airline name: tuoheng-airline
profiles: profiles:
# 环境配置 # 环境配置
active: prod active: dev
flyway: flyway:
table: flyway_airline_schema_history # 自定义历史表名 table: flyway_airline_schema_history # 自定义历史表名
baseline-on-migrate: true # 在nocos中也有配置 baseline-on-migrate: true # 在nocos中也有配置
@ -18,12 +18,19 @@ spring:
nacos: nacos:
discovery: discovery:
# 服务注册地址 # 服务注册地址
server-addr: ruoyi-nacos:8848 server-addr: 192.168.192.1:8848
config: config:
# 配置中心地址 # 配置中心地址
server-addr: ruoyi-nacos:8848 server-addr: 192.168.192.1:8848
# 配置文件格式 # 配置文件格式
file-extension: yml file-extension: yml
# 共享配置 # 共享配置
shared-configs: shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# 设备同步配置
device:
sync:
# 设备名称过滤正则表达式(多个用逗号分隔)
# 匹配这些正则表达式的设备将被跳过,不进行同步
# 当前配置:过滤所有以 TH 开头的设备
exclude-patterns: TH.*

View File

@ -0,0 +1,53 @@
-- 创建航线文件表
CREATE TABLE IF NOT EXISTS airline_file (
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(255) NOT NULL COMMENT '航线名称',
air_vendor VARCHAR(255) COMMENT '飞行器厂商',
air_type VARCHAR(255) COMMENT '飞行器类型',
file_name VARCHAR(255) COMMENT '文件名称',
file_url VARCHAR(255) COMMENT '文件地址',
type INT(11) COMMENT '航线类型1,航点航线;2,指点航线;3,指面航线',
source VARCHAR(255) COMMENT '数据来源',
status INT(11) DEFAULT 1 COMMENT '1 启用 0 停用。默认启用。',
file_md5 VARCHAR(255) COMMENT '航线文件对应的 MD5指纹',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME COMMENT '更新时间',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='航线文件表';
-- 创建航线分组表
CREATE TABLE IF NOT EXISTS airline_file_group (
group_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
group_name VARCHAR(255) NOT NULL COMMENT '分组名称',
user_id BIGINT(20) NOT NULL COMMENT '用户ID分组自带用户归属。后期权限都是基于用户ID进行',
del_flag BIGINT(20) DEFAULT 0 COMMENT '删除标识0.未删除默认1已删除',
deleted_by VARCHAR(64) DEFAULT '' COMMENT '删除者',
deleted_time DATETIME COMMENT '删除时间',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME COMMENT '更新时间',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (group_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='航线分组表';
-- 创建航线分组明细表
CREATE TABLE IF NOT EXISTS airline_file_group_info (
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'id,主键',
group_id BIGINT(20) NOT NULL COMMENT '用户ID',
airline_id BIGINT(20) NOT NULL COMMENT '航线id',
del_flag BIGINT(20) DEFAULT 0 COMMENT '删除标识0.未删除默认1已删除',
deleted_by VARCHAR(64) DEFAULT '' COMMENT '删除者',
deleted_time DATETIME COMMENT '删除时间',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME COMMENT '更新时间',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (id),
INDEX idx_group_id (group_id),
INDEX idx_airline_id (airline_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='航线分组明细表';

View File

@ -1,14 +0,0 @@
-- ============================================================
-- Flyway Migration Script
-- ============================================================
-- Version: V1
-- Description: Create tuoheng_airline_temp table
-- Author: ruoyi
-- Date: 2026-01-17
-- ============================================================
-- 创建航线临时表
CREATE TABLE IF NOT EXISTS tuoheng_airline_temp (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='航线临时表';

View File

@ -0,0 +1,633 @@
# Tuoheng Device 模块说明文档
## 目录
- [1. 模块概述](#1-模块概述)
- [2. Flyway 数据库迁移工具使用指南](#2-flyway-数据库迁移工具使用指南)
- [2.1 什么是 Flyway](#21-什么是-flyway)
- [2.2 Flyway 工作原理](#22-flyway-工作原理)
- [2.3 目录结构](#23-目录结构)
- [2.4 迁移脚本命名规则](#24-迁移脚本命名规则)
- [2.5 新增表操作](#25-新增表操作)
- [2.6 修改表结构操作](#26-修改表结构操作)
- [2.7 常见场景示例](#27-常见场景示例)
- [2.8 注意事项](#28-注意事项)
- [2.9 常见问题](#29-常见问题)
---
## 1. 模块概述
`tuoheng-device` 是设备管理模块,负责设备相关的业务逻辑处理。
**核心功能:**
- 设备信息管理
- 数据库表自动管理(基于 Flyway
- RESTful API 接口
**技术栈:**
- Spring Boot 3.x
- MyBatis
- Flyway数据库版本管理
- Nacos配置中心
---
## 2. Flyway 数据库迁移工具使用指南
### 2.1 什么是 Flyway
Flyway 是一个开源的数据库版本管理工具,它可以:
- ✅ 自动管理数据库表的创建和更新
- ✅ 记录数据库变更历史
- ✅ 支持多环境部署(开发、测试、生产)
- ✅ 确保数据库结构的一致性
- ✅ 支持回滚和版本控制
**为什么使用 Flyway**
1. **自动化**:应用启动时自动检查并执行数据库变更
2. **版本化**:每次变更都有明确的版本号,便于追踪
3. **安全性**:不会删除表或数据,只会增量更新
4. **团队协作**:避免手动执行 SQL 导致的环境不一致
---
### 2.2 Flyway 工作原理
#### 启动流程
```
应用启动
Flyway 初始化
检查数据库中是否存在 flyway_schema_history 表
├─ 不存在 → 创建 flyway_schema_history 表
└─ 存在 → 读取已执行的迁移记录
扫描 db/migration 目录下的 SQL 脚本
对比版本号,找出未执行的脚本
按版本号顺序执行未执行的脚本
记录执行结果到 flyway_schema_history 表
应用启动完成
```
#### 版本管理表
Flyway 会自动创建 `flyway_schema_history` 表来记录迁移历史:
| 字段 | 说明 |
|------|------|
| installed_rank | 执行顺序 |
| version | 版本号(如 1, 2, 3 |
| description | 描述信息 |
| type | 类型SQL |
| script | 脚本文件名 |
| checksum | 校验和 |
| installed_by | 执行用户 |
| installed_on | 执行时间 |
| execution_time | 执行耗时 |
| success | 是否成功 |
---
### 2.3 目录结构
```
tuoheng-device/
└── src/
└── main/
└── resources/
└── db/
└── migration/ # Flyway 迁移脚本目录
├── V1__Create_device_temp_table.sql
├── V2__Add_device_name_column.sql
├── V3__Add_device_status_column.sql
└── ...
```
**重要说明:**
- 所有迁移脚本必须放在 `db/migration` 目录下
- Flyway 会自动扫描该目录下的所有 SQL 文件
- 脚本按版本号顺序执行
---
### 2.4 迁移脚本命名规则
#### 命名格式
```
V{版本号}__{描述}.sql
```
**格式说明:**
- `V` - 固定前缀(大写字母 V
- `{版本号}` - 数字版本号,必须递增(如 1, 2, 3 或 1.0, 1.1, 2.0
- `__` - 两个下划线分隔符
- `{描述}` - 英文描述,使用下划线连接单词
- `.sql` - 文件扩展名
#### 命名示例
✅ **正确示例:**
```
V1__Create_device_temp_table.sql
V2__Add_device_name_column.sql
V3__Add_device_status_index.sql
V4__Update_device_type_enum.sql
V1.0__Initial_schema.sql
V1.1__Add_user_table.sql
V2.0__Refactor_device_structure.sql
```
❌ **错误示例:**
```
v1__create_table.sql # V 必须大写
V1_create_table.sql # 只有一个下划线
V1__创建表.sql # 不能使用中文
create_table.sql # 缺少版本号前缀
V1.sql # 缺少描述
```
---
### 2.5 新增表操作
#### 场景:创建一个新表
**步骤 1确定版本号**
查看 `db/migration` 目录下已有的脚本,确定下一个版本号。
```bash
# 假设已有脚本:
V1__Create_device_temp_table.sql
V2__Add_device_name_column.sql
# 新脚本版本号应为V3
```
**步骤 2创建迁移脚本**
`db/migration` 目录下创建新文件:`V3__Create_device_info_table.sql`
```sql
-- ============================================================
-- Flyway Migration Script
-- ============================================================
-- Version: V3
-- Description: Create device_info table
-- Author: your_name
-- Date: 2026-01-15
-- ============================================================
-- 创建设备信息表
CREATE TABLE IF NOT EXISTS device_info (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
device_name VARCHAR(100) NOT NULL COMMENT '设备名称',
device_type VARCHAR(50) COMMENT '设备类型',
status TINYINT DEFAULT 0 COMMENT '状态0-离线 1-在线',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id),
INDEX idx_device_name (device_name),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备信息表';
```
**步骤 3重启应用**
重启应用后Flyway 会自动:
1. 检测到新的迁移脚本 V3
2. 执行 SQL 创建表
3. 记录执行历史到 `flyway_schema_history`
**步骤 4验证**
查询数据库确认表已创建:
```sql
SHOW TABLES LIKE 'device_info';
SELECT * FROM flyway_schema_history WHERE version = '3';
```
---
### 2.6 修改表结构操作
#### 场景 1添加新字段
**步骤 1创建迁移脚本**
文件名:`V4__Add_device_location_column.sql`
```sql
-- ============================================================
-- Flyway Migration Script
-- ============================================================
-- Version: V4
-- Description: Add location column to device_info table
-- Author: your_name
-- Date: 2026-01-15
-- ============================================================
-- 添加位置字段
ALTER TABLE device_info
ADD COLUMN location VARCHAR(200) COMMENT '设备位置' AFTER device_type;
```
**步骤 2重启应用**
Flyway 会自动执行 ALTER TABLE 语句。
---
#### 场景 2修改字段类型
**步骤 1创建迁移脚本**
文件名:`V5__Modify_device_name_length.sql`
```sql
-- ============================================================
-- Flyway Migration Script
-- ============================================================
-- Version: V5
-- Description: Modify device_name column length
-- Author: your_name
-- Date: 2026-01-15
-- ============================================================
-- 修改设备名称字段长度
ALTER TABLE device_info
MODIFY COLUMN device_name VARCHAR(200) NOT NULL COMMENT '设备名称';
```
---
#### 场景 3添加索引
**步骤 1创建迁移脚本**
文件名:`V6__Add_device_type_index.sql`
```sql
-- ============================================================
-- Flyway Migration Script
-- ============================================================
-- Version: V6
-- Description: Add index on device_type column
-- Author: your_name
-- Date: 2026-01-15
-- ============================================================
-- 添加设备类型索引
CREATE INDEX idx_device_type ON device_info(device_type);
```
---
#### 场景 4删除字段谨慎操作
**步骤 1创建迁移脚本**
文件名:`V7__Drop_device_location_column.sql`
```sql
-- ============================================================
-- Flyway Migration Script
-- ============================================================
-- Version: V7
-- Description: Drop location column from device_info table
-- Author: your_name
-- Date: 2026-01-15
-- ============================================================
-- 删除位置字段(谨慎操作,确保该字段不再使用)
ALTER TABLE device_info
DROP COLUMN location;
```
⚠️ **警告:** 删除字段会导致数据丢失,操作前务必确认!
---
### 2.7 常见场景示例
#### 示例 1创建多个表
文件名:`V8__Create_multiple_tables.sql`
```sql
-- 创建设备类型表
CREATE TABLE IF NOT EXISTS device_type (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
type_name VARCHAR(50) NOT NULL COMMENT '类型名称',
type_code VARCHAR(20) NOT NULL COMMENT '类型编码',
PRIMARY KEY (id),
UNIQUE KEY uk_type_code (type_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备类型表';
-- 创建设备日志表
CREATE TABLE IF NOT EXISTS device_log (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
device_id VARCHAR(64) NOT NULL COMMENT '设备ID',
log_type VARCHAR(20) COMMENT '日志类型',
log_content TEXT COMMENT '日志内容',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
INDEX idx_device_id (device_id),
INDEX idx_create_time (create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备日志表';
```
---
#### 示例 2插入初始数据
文件名:`V9__Insert_initial_device_types.sql`
```sql
-- 插入初始设备类型数据
INSERT INTO device_type (id, type_name, type_code) VALUES
('1', '无人机', 'DRONE'),
('2', '地面站', 'GROUND_STATION'),
('3', '传感器', 'SENSOR')
ON DUPLICATE KEY UPDATE type_name = VALUES(type_name);
```
---
#### 示例 3修改表结构并迁移数据
文件名:`V10__Migrate_device_status_to_enum.sql`
```sql
-- 步骤1添加新字段
ALTER TABLE device_info
ADD COLUMN status_new ENUM('OFFLINE', 'ONLINE', 'MAINTENANCE')
DEFAULT 'OFFLINE' COMMENT '设备状态' AFTER status;
-- 步骤2迁移数据
UPDATE device_info
SET status_new = CASE
WHEN status = 0 THEN 'OFFLINE'
WHEN status = 1 THEN 'ONLINE'
ELSE 'OFFLINE'
END;
-- 步骤3删除旧字段
ALTER TABLE device_info DROP COLUMN status;
-- 步骤4重命名新字段
ALTER TABLE device_info
CHANGE COLUMN status_new status ENUM('OFFLINE', 'ONLINE', 'MAINTENANCE')
DEFAULT 'OFFLINE' COMMENT '设备状态';
```
---
### 2.8 注意事项
#### ⚠️ 重要规则
1. **版本号必须递增**
- ❌ 不能修改已执行的脚本
- ❌ 不能删除已执行的脚本
- ✅ 只能创建新的版本脚本
2. **脚本只执行一次**
- Flyway 会记录已执行的脚本
- 相同版本号的脚本不会重复执行
- 如果需要修改,必须创建新版本
3. **不要修改已执行的脚本**
- 已执行的脚本有 checksum 校验
- 修改会导致校验失败,应用启动报错
- 如需修改,创建新的迁移脚本
4. **使用事务**
- 每个迁移脚本在一个事务中执行
- 如果执行失败,会自动回滚
- 确保脚本的原子性
5. **测试脚本**
- 在开发环境先测试脚本
- 确认无误后再部署到生产环境
6. **备份数据**
- 执行重要变更前备份数据库
- 特别是删除字段或表的操作
---
### 2.9 常见问题
#### Q1: 如何查看 Flyway 执行历史?
```sql
SELECT * FROM flyway_schema_history ORDER BY installed_rank;
```
---
#### Q2: 脚本执行失败怎么办?
**情况 1脚本语法错误**
1. 查看应用启动日志,找到错误信息
2. 修复 SQL 语法错误
3. 删除 `flyway_schema_history` 表中失败的记录:
```sql
DELETE FROM flyway_schema_history WHERE success = 0;
```
4. 重启应用
**情况 2脚本逻辑错误如字段已存在**
1. 创建新的修复脚本(版本号递增)
2. 在新脚本中使用 `IF NOT EXISTS``IF EXISTS` 语句
3. 重启应用
---
#### Q3: 如何跳过某个版本的脚本?
**不推荐跳过脚本!** 如果确实需要:
1. 手动在 `flyway_schema_history` 表中插入记录:
```sql
INSERT INTO flyway_schema_history
(installed_rank, version, description, type, script, checksum, installed_by, installed_on, execution_time, success)
VALUES
(999, '5', 'Skipped migration', 'SQL', 'V5__Skipped.sql', 0, 'manual', NOW(), 0, 1);
```
2. 重启应用
---
#### Q4: 如何在多环境中使用 Flyway
Flyway 会自动适配不同环境:
- **开发环境**:本地数据库,自动创建表
- **测试环境**:测试数据库,执行相同的迁移脚本
- **生产环境**:生产数据库,执行相同的迁移脚本
**关键点:**
- 所有环境使用相同的迁移脚本
- Flyway 会根据 `flyway_schema_history` 表判断哪些脚本需要执行
---
#### Q5: 如何禁用 Flyway
在 Nacos 配置中添加:
```yaml
spring:
flyway:
enabled: false
```
---
#### Q6: 迁移脚本可以包含多个 SQL 语句吗?
可以!一个脚本可以包含多个 SQL 语句,用分号分隔:
```sql
CREATE TABLE table1 (...);
CREATE TABLE table2 (...);
INSERT INTO table1 VALUES (...);
```
---
#### Q7: 如何回滚数据库变更?
Flyway 社区版不支持自动回滚。如需回滚:
1. **方式 1创建回滚脚本**
```sql
-- V11__Rollback_device_status_change.sql
ALTER TABLE device_info DROP COLUMN new_column;
```
2. **方式 2手动回滚**
- 备份数据库
- 手动执行回滚 SQL
- 删除 `flyway_schema_history` 中的记录
---
## 3. 开发工作流程
### 3.1 新增表的完整流程
1. **创建 Flyway 迁移脚本**
- 文件:`db/migration/Vx__Create_xxx_table.sql`
2. **创建实体类**
- 文件:`domain/XxxEntity.java`
3. **创建 Mapper 接口**
- 文件:`mapper/XxxMapper.java`
4. **创建 Mapper XML**
- 文件:`resources/mapper/device/XxxMapper.xml`
5. **创建 Service 接口和实现**
- 文件:`service/IXxxService.java`
- 文件:`service/impl/XxxServiceImpl.java`
6. **创建 Controller**
- 文件:`controller/XxxController.java`
7. **重启应用测试**
---
### 3.2 修改表结构的完整流程
1. **创建 Flyway 迁移脚本**
- 文件:`db/migration/Vx__Modify_xxx_table.sql`
2. **更新实体类**
- 添加或修改字段
3. **更新 Mapper XML**
- 更新 resultMap 和 SQL 语句
4. **更新 Service 和 Controller**
- 根据需要调整业务逻辑
5. **重启应用测试**
---
## 4. 最佳实践
### 4.1 脚本编写建议
1. **使用 IF NOT EXISTS / IF EXISTS**
```sql
CREATE TABLE IF NOT EXISTS table_name (...);
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name VARCHAR(100);
```
2. **添加详细注释**
```sql
-- 为什么要做这个变更
-- 影响范围
-- 注意事项
```
3. **一个脚本只做一件事**
- ✅ V1__Create_device_table.sql
- ✅ V2__Add_device_index.sql
- ❌ V1__Create_and_modify_everything.sql
4. **使用事务安全的语句**
- DDL 语句在 MySQL 中会自动提交
- 谨慎使用 DROP、TRUNCATE 等危险操作
---
### 4.2 团队协作建议
1. **版本号管理**
- 团队成员协调版本号,避免冲突
- 使用 Git 管理迁移脚本
2. **代码审查**
- 迁移脚本必须经过 Code Review
- 特别关注 DROP、DELETE 等危险操作
3. **文档记录**
- 在脚本中添加详细的变更说明
- 更新本文档记录重要变更
---
## 5. 参考资料
- [Flyway 官方文档](https://flywaydb.org/documentation/)
- [Flyway 命名规范](https://flywaydb.org/documentation/concepts/migrations#naming)
- [Spring Boot Flyway 集成](https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization.migration-tool.flyway)
---
## 6. 联系方式
如有问题,请联系:
- 技术负责人xxx
- 邮箱xxx@example.com
---
**最后更新时间:** 2026-01-15

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false"> <configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 --> <!-- 日志存放路径 -->
<property name="log.path" value="logs/tupheng-airline" /> <property name="log.path" value="logs/tuoheng-device" />
<!-- 日志输出格式 --> <!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

View File

@ -0,0 +1,52 @@
<?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.ruoyi.airline.mapper.AirlineDataMapper">
<resultMap type="com.ruoyi.airline.mapper.entity.AirlineDataEntity" id="AirlineDataResult">
<result property="id" column="id" />
<result property="flightNumber" column="flight_number" />
<result property="departureCity" column="departure_city" />
<result property="arrivalCity" column="arrival_city" />
<result property="airspeed" column="airspeed" />
<result property="velocity" column="velocity" />
<result property="vspeed" column="vspeed" />
<result property="hspeed" column="hspeed" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectAirlineDataVo">
select id, flight_number, departure_city, arrival_city, airspeed, velocity, vspeed, hspeed, create_by, create_time, update_by, update_time, remark
from tuoheng_airline_data
</sql>
<select id="selectAirlineDataList" parameterType="com.ruoyi.airline.mapper.entity.AirlineDataEntity" resultMap="AirlineDataResult">
<include refid="selectAirlineDataVo"/>
<where>
<if test="id != null"> and id = #{id}</if>
<if test="flightNumber != null and flightNumber != ''"> and flight_number = #{flightNumber}</if>
<if test="departureCity != null and departureCity != ''"> and departure_city = #{departureCity}</if>
<if test="arrivalCity != null and arrivalCity != ''"> and arrival_city = #{arrivalCity}</if>
</where>
</select>
<select id="selectAirlineDataById" parameterType="Long" resultMap="AirlineDataResult">
<include refid="selectAirlineDataVo"/>
where id = #{id}
</select>
<select id="selectPage" parameterType="com.ruoyi.airline.mapper.entity.AirlineDataEntity" resultMap="AirlineDataResult">
<include refid="selectAirlineDataVo"/>
<where>
<if test="flightNumber != null and flightNumber != ''"> and flight_number = #{flightNumber}</if>
<if test="departureCity != null and departureCity != ''"> and departure_city = #{departureCity}</if>
<if test="arrivalCity != null and arrivalCity != ''"> and arrival_city = #{arrivalCity}</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,55 @@
<?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.ruoyi.airline.mapper.AirlineFileGroupInfoMapper">
<!-- 结果映射 -->
<resultMap type="com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity" id="AirlineFileGroupInfoResult">
<id property="id" column="id" />
<result property="groupId" column="group_id" />
<result property="airlineId" column="airline_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="delFlag" column="del_flag" />
<result property="deletedBy" column="deleted_by" />
<result property="deletedTime" column="deleted_time" />
</resultMap>
<!-- 查询分组详情列表 -->
<select id="selectGroupList" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity" resultMap="AirlineFileGroupInfoResult">
select id, group_id, airline_id, create_by, create_time, update_by, update_time, del_flag, deleted_by, deleted_time
from airline_file_group_info
where del_flag = 0
<if test="groupId != null">
and group_id = #{groupId}
</if>
<if test="airlineId != null">
and airline_id = #{airlineId}
</if>
</select>
<!-- 删除分组详情(软删除) -->
<update id="deleteGroupInfo" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity">
update airline_file_group_info
set del_flag = 1,
deleted_by = #{deletedBy},
deleted_time = #{deletedTime}
where id = #{id}
<if test="groupId != null">
and group_id = #{groupId}
</if>
<if test="airlineId != null">
and airline_id = #{airlineId}
</if>
</update>
<!-- 保存分组详情 -->
<insert id="save" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupInfoEntity" useGeneratedKeys="true" keyProperty="id">
insert into airline_file_group_info (group_id, airline_id, create_by, create_time, update_by, update_time, del_flag)
values (#{groupId}, #{airlineId}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, 0)
</insert>
</mapper>

View File

@ -0,0 +1,81 @@
<?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.ruoyi.airline.mapper.AirlineFileGroupMapper">
<!-- 结果映射 -->
<resultMap id="AirlineFileGroupResult" type="com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity">
<id property="groupId" column="group_id" />
<result property="groupName" column="group_name" />
<result property="userId" column="user_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="delFlag" column="del_flag" />
<result property="deletedBy" column="deleted_by" />
<result property="deletedTime" column="deleted_time" />
</resultMap>
<!-- 检查分组名称是否唯一 -->
<select id="checkgroupNameUnique" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity" resultType="java.lang.Integer">
select count(1) from airline_file_group
where group_name = #{groupName}
and del_flag = 0
<if test="groupId != null">
and group_id != #{groupId}
</if>
<if test="userId != null">
and user_id = #{userId}
</if>
</select>
<!-- 删除分组(软删除) -->
<update id="deletegroup" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity">
update airline_file_group
set del_flag = 1,
deleted_by = #{deletedBy},
deleted_time = #{deletedTime}
where group_id = #{groupId}
<if test="userId != null">
and user_id = #{userId}
</if>
</update>
<!-- 更新分组 -->
<update id="updateGroup" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity">
update airline_file_group
set group_name = #{groupName},
update_by = #{updateBy},
update_time = #{updateTime}
where group_id = #{groupId}
and del_flag = 0
<if test="userId != null">
and user_id = #{userId}
</if>
</update>
<!-- 插入分组 -->
<insert id="insertGroup" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity">
insert into airline_file_group (group_name, user_id, create_by, create_time, update_by, update_time, del_flag)
values (#{groupName}, #{userId}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, 0)
</insert>
<!-- 查询分组列表 -->
<select id="selectGroupList" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileGroupEntity" resultMap="AirlineFileGroupResult">
select group_id, group_name, user_id, create_by, create_time, update_by, update_time, del_flag, deleted_by, deleted_time
from airline_file_group
<where>
and del_flag = 0
<if test="groupName != null and groupName != ''">
and group_name like concat('%', #{groupName}, '%')
</if>
<if test="userId != null">
and user_id = #{userId}
</if>
</where>
order by create_time desc
</select>
</mapper>

View File

@ -0,0 +1,42 @@
<?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.ruoyi.airline.mapper.AirlineFileMapper">
<!-- 结果映射 -->
<resultMap type="com.ruoyi.airline.mapper.entity.AirlineFileEntity" id="AirlineFileResult">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="airVendor" column="air_vendor" />
<result property="airType" column="air_type" />
<result property="fileName" column="file_name" />
<result property="fileUrl" column="file_url" />
<result property="type" column="type" />
<result property="source" column="source" />
<result property="status" column="status" />
<result property="fileMd5" column="file_md5" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<!-- 保存航线文件 -->
<insert id="save" parameterType="com.ruoyi.airline.mapper.entity.AirlineFileEntity" useGeneratedKeys="true" keyProperty="id">
insert into airline_file (name, air_vendor, air_type, file_name, file_url, type, source, status, file_md5, create_by, create_time, update_by, update_time, remark)
values (#{name}, #{airVendor}, #{airType}, #{fileName}, #{fileUrl}, #{type}, #{source}, #{status}, #{fileMd5}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{remark})
</insert>
<!-- 根据ID列表查询航线文件 -->
<select id="selectFileListByIds" parameterType="java.util.List" resultMap="AirlineFileResult">
select id, name, air_vendor, air_type, file_name, file_url, type, source, status, file_md5, create_by, create_time, update_by, update_time, remark
from airline_file
where id in
<foreach item="id" collection="list" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -0,0 +1,61 @@
# spring配置
spring:
data:
redis:
host: localhost
port: 6379
password:
datasource:
druid:
stat-view-servlet:
enabled: true
loginUsername: ruoyi
loginPassword: 123456
dynamic:
druid:
initial-size: 5
min-idle: 5
maxActive: 20
maxWait: 60000
connectTimeout: 30000
socketTimeout: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,slf4j
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
datasource:
# 主库数据源
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Root123
# mybatis配置
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.airline
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath:mapper/airline/**/*.xml
# springdoc配置
springdoc:
gatewayUrl: http://ruoyi-gateway:8080/${spring.application.name}
api-docs:
# 是否开启接口文档
enabled: true
info:
# 标题
title: '拓恒航线模块接口文档'
# 描述
description: '拓恒航线模块接口描述'
# 作者信息
contact:
name: TuoHeng
url: https://ruoyi.vip