上传项目设计图,将项目设计图dxf文件转化为geojson文件并将存储信息保存到数据库

This commit is contained in:
lcj
2025-04-23 17:53:57 +08:00
parent a2c6bb7ba9
commit 5abef3716e
24 changed files with 1208 additions and 95 deletions

View File

@ -76,9 +76,9 @@ spring:
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
max-file-size: 100MB
# 设置总上传的文件大小
max-request-size: 20MB
max-request-size: 200MB
mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**

View File

@ -0,0 +1,64 @@
package org.dromara.test;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
/**
* @author lcj
* @date 2025/4/23 10:15
*/
@SpringBootTest
public class CmdTest {
@Test
public void test() {
// 获取当前项目根目录
String projectRoot = System.getProperty("user.dir");
// EXE 和参数
String exePath = projectRoot + File.separator + "file" + File.separator + "resource" + File.separator + "dxf" + File.separator + "main.exe";
String inputDXF = "file/resource/dxf/1897160897167638529/桩点图.dxf";
String outputJSON = "file/resource/dxf/1897160897167638529/output.json";
String sourceEPSG = "4524";
String targetEPSG = "4326";
// 构造命令行
List<String> command = Arrays.asList(
exePath,
inputDXF,
outputJSON,
sourceEPSG,
targetEPSG
);
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true); // 合并标准错误和输出
try {
Process process = builder.start();
// 读取输出
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), "GBK")
);
String line;
System.out.println("程序输出:");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
int exitCode = process.waitFor();
System.out.println("程序退出码:" + exitCode);
reader.close();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -34,6 +34,7 @@
<module>ruoyi-common-tenant</module>
<module>ruoyi-common-websocket</module>
<module>ruoyi-common-sse</module>
<module>ruoyi-common-mapbox</module>
</modules>
<artifactId>ruoyi-common</artifactId>

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-mapbox</artifactId>
<description>
ruoyi-common-mapbox 地图工具模块
</description>
<dependencies>
<dependency>
<groupId>com.mapbox.mapboxsdk</groupId>
<artifactId>mapbox-sdk-geojson</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>com.mapbox.mapboxsdk</groupId>
<artifactId>mapbox-sdk-services</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>com.mapbox.mapboxsdk</groupId>
<artifactId>mapbox-sdk-turf</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>com.mapbox.mapboxsdk</groupId>
<artifactId>mapbox-sdk-core</artifactId>
<version>7.4.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>mapbox-repo</id>
<url>https://api.mapbox.com/downloads/v2/releases/maven</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,24 @@
package org.dromara.constant;
import java.io.File;
/**
* @author lcj
* @date 2025/4/23 11:09
*/
public interface DxfFileConstant {
String DXF_BASE_PATH = "file" + File.separator + "resource" + File.separator + "dxf";
/**
* WGS 84
*/
String EPSG4326 = "4326";
String EPSG4524 = "4524";
static String getDxfProjectPath(Long projectId) {
return DXF_BASE_PATH + File.separator + projectId;
}
}

View File

@ -7,15 +7,18 @@ import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.facility.domain.req.photovoltaicpanelparts.PhotovoltaicPanelPartsCreateReq;
import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 设施-光伏板桩点、立柱、支架
*
* @author lcj
* @date 2025/4/21 16:33
* @date 2025/4/21
*/
@Validated
@RestController
@RequestMapping("/facility/photovoltaicPanelPoint/parts")
public class FacPhotovoltaicPanelPartsController {

View File

@ -1,8 +1,6 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@ -28,11 +26,6 @@ import org.dromara.project.service.IBusProjectService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
/**
@ -128,14 +121,4 @@ public class BusProjectController extends BaseController {
return toAjax(projectService.deleteWithValidByIds(List.of(ids), true));
}
@GetMapping("/json")
public R<JSONObject> test() throws IOException {
// 1. 指定文件相对于 classpath 的路径
Path path = Paths.get(System.getProperty("user.dir"), "geo.json");
// 2. 把文件内容读成字节数组,再转成字符串
String json = Files.readString(path, StandardCharsets.UTF_8);
JSONObject json1 = JSONUtil.parseObj(json);
return R.ok(json1);
}
}

View File

@ -0,0 +1,119 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.req.projectfile.ProjectFileQueryReq;
import org.dromara.project.domain.req.projectfile.ProjectFileUpdateReq;
import org.dromara.project.domain.req.projectfile.ProjectFileUploadDxfReq;
import org.dromara.project.domain.vo.BusProjectFileVo;
import org.dromara.project.service.IBusProjectFileService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 项目文件存储
*
* @author lcj
* @date 2025-04-23
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/project/projectFile")
public class BusProjectFileController extends BaseController {
private final IBusProjectFileService busProjectFileService;
/**
* 查询项目文件存储列表
*/
@SaCheckPermission("project:projectFile:list")
@GetMapping("/list")
public TableDataInfo<BusProjectFileVo> list(ProjectFileQueryReq req, PageQuery pageQuery) {
return busProjectFileService.queryPageList(req, pageQuery);
}
/**
* 导出项目文件存储列表
*/
@SaCheckPermission("project:projectFile:export")
@Log(title = "项目文件存储", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ProjectFileQueryReq req, HttpServletResponse response) {
List<BusProjectFileVo> list = busProjectFileService.queryList(req);
ExcelUtil.exportExcel(list, "项目文件存储", BusProjectFileVo.class, response);
}
/**
* 获取项目文件存储详细信息
*
* @param id 主键
*/
@SaCheckPermission("project:projectFile:query")
@GetMapping("/{id}")
public R<BusProjectFileVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busProjectFileService.queryById(id));
}
/**
* 修改项目文件存储
*/
@SaCheckPermission("project:projectFile:edit")
@Log(title = "项目文件存储", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ProjectFileUpdateReq req) {
return toAjax(busProjectFileService.updateByBo(req));
}
/**
* 删除项目文件存储
*
* @param ids 主键串
*/
@SaCheckPermission("project:projectFile:remove")
@Log(title = "项目文件存储", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busProjectFileService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 上传 dxf 文件并解析为 json
*/
@Log(title = "项目文件存储", businessType = BusinessType.IMPORT)
@PostMapping("/upload/dxf")
public R<Long> uploadDxf2Json(@RequestParam("file") MultipartFile file, ProjectFileUploadDxfReq req) {
return R.ok(busProjectFileService.uploadDxf2Json(file, req));
}
/**
* 获取JSON文件详细信息
*
* @param id 主键
*/
@SaCheckPermission("project:projectFile:query")
@GetMapping("/json/{id}")
public R<JSONObject> getJSONFile(@NotNull(message = "主键不能为空")
@PathVariable Long id){
return R.ok(busProjectFileService.getJSONFile(id));
}
}

View File

@ -0,0 +1,65 @@
package org.dromara.project.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 项目文件存储对象 bus_project_file
*
* @author lcj
* @date 2025-04-23
*/
@Data
@TableName("bus_project_file")
public class BusProjectFile implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 文件类型
*/
private String fileType;
/**
* 文件名称
*/
private String fileName;
/**
* 文件路径
*/
private String filePath;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
}

View File

@ -0,0 +1,33 @@
package org.dromara.project.domain.req.projectfile;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/23 14:16
*/
@Data
public class ProjectFileQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 399401709402729491L;
/**
* 项目id
*/
private Long projectId;
/**
* 文件类型
*/
private String fileType;
/**
* 文件名称
*/
private String fileName;
}

View File

@ -0,0 +1,43 @@
package org.dromara.project.domain.req.projectfile;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/23 14:18
*/
@Data
public class ProjectFileUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = -5620479296452749930L;
/**
* 主键
*/
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 文件类型
*/
private String fileType;
/**
* 文件名称
*/
private String fileName;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,23 @@
package org.dromara.project.domain.req.projectfile;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/23 11:43
*/
@Data
public class ProjectFileUploadDxfReq implements Serializable {
@Serial
private static final long serialVersionUID = -7096688035548954702L;
/**
* 项目id
*/
private Long projectId;
}

View File

@ -0,0 +1,50 @@
package org.dromara.project.domain.vo;
import org.dromara.project.domain.BusProjectFile;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 项目文件存储视图对象 bus_project_file
*
* @author lcj
* @date 2025-04-23
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusProjectFile.class)
public class BusProjectFileVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 文件类型
*/
@ExcelProperty(value = "文件类型")
private String fileType;
/**
* 文件名称
*/
@ExcelProperty(value = "文件名称")
private String fileName;
/**
* 文件路径
*/
@ExcelProperty(value = "文件路径")
private String filePath;
}

View File

@ -160,6 +160,11 @@ public class BusProjectVo implements Serializable {
@ExcelProperty(value = "安全协议书")
private String securityAgreement;
/**
* 设计文件id
*/
private Long designId;
/**
* 显示隐藏0显示 1隐藏
*/

View File

@ -0,0 +1,15 @@
package org.dromara.project.mapper;
import org.dromara.project.domain.BusProjectFile;
import org.dromara.project.domain.vo.BusProjectFileVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 项目文件存储Mapper接口
*
* @author lcj
* @date 2025-04-23
*/
public interface BusProjectFileMapper extends BaseMapperPlus<BusProjectFile, BusProjectFileVo> {
}

View File

@ -0,0 +1,110 @@
package org.dromara.project.service;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.domain.BusProjectFile;
import org.dromara.project.domain.req.projectfile.ProjectFileQueryReq;
import org.dromara.project.domain.req.projectfile.ProjectFileUpdateReq;
import org.dromara.project.domain.req.projectfile.ProjectFileUploadDxfReq;
import org.dromara.project.domain.vo.BusProjectFileVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.List;
/**
* 项目文件存储Service接口
*
* @author lcj
* @date 2025-04-23
*/
public interface IBusProjectFileService extends IService<BusProjectFile> {
/**
* 查询项目文件存储
*
* @param id 主键
* @return 项目文件存储
*/
BusProjectFileVo queryById(Long id);
/**
* 分页查询项目文件存储列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 项目文件存储分页列表
*/
TableDataInfo<BusProjectFileVo> queryPageList(ProjectFileQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的项目文件存储列表
*
* @param req 查询条件
* @return 项目文件存储列表
*/
List<BusProjectFileVo> queryList(ProjectFileQueryReq req);
/**
* 修改项目文件存储
*
* @param req 项目文件存储
* @return 是否修改成功
*/
Boolean updateByBo(ProjectFileUpdateReq req);
/**
* 校验并批量删除项目文件存储信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据id获取JSON文件
*
* @param id 主键
* @return JSON文件
*/
JSONObject getJSONFile(Long id);
/**
* 上传dxf文件并转换为json
*
* @param file 文件
* @param req 请求
* @return 主键
*/
Long uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req);
/**
* 获取项目文件存储视图对象
*
* @param projectFile 项目文件存储对象
* @return 项目文件存储视图对象
*/
BusProjectFileVo getVo(BusProjectFile projectFile);
/**
* 获取项目文件存储查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
LambdaQueryWrapper<BusProjectFile> buildQueryWrapper(ProjectFileQueryReq req);
/**
* 获取项目文件存储分页对象视图
*
* @param projectFilePage 项目文件存储分页对象
* @return 项目文件存储分页对象视图
*/
Page<BusProjectFileVo> getVoPage(Page<BusProjectFile> projectFilePage);
}

View File

@ -0,0 +1,322 @@
package org.dromara.project.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.constant.DxfFileConstant;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusProjectFile;
import org.dromara.project.domain.req.projectfile.ProjectFileQueryReq;
import org.dromara.project.domain.req.projectfile.ProjectFileUpdateReq;
import org.dromara.project.domain.req.projectfile.ProjectFileUploadDxfReq;
import org.dromara.project.domain.vo.BusProjectFileVo;
import org.dromara.project.mapper.BusProjectFileMapper;
import org.dromara.project.service.IBusProjectFileService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.DxfUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* 项目文件存储Service业务层处理
*
* @author lcj
* @date 2025-04-23
*/
@Slf4j
@Service
public class BusProjectFileServiceImpl extends ServiceImpl<BusProjectFileMapper, BusProjectFile>
implements IBusProjectFileService {
@Resource
private IBusProjectService projectService;
/**
* 查询项目文件存储
*
* @param id 主键
* @return 项目文件存储
*/
@Override
public BusProjectFileVo queryById(Long id) {
BusProjectFile projectFile = this.getById(id);
if (projectFile == null) {
throw new ServiceException("对应项目文件存储信息不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(projectFile);
}
/**
* 分页查询项目文件存储列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 项目文件存储分页列表
*/
@Override
public TableDataInfo<BusProjectFileVo> queryPageList(ProjectFileQueryReq req, PageQuery pageQuery) {
Page<BusProjectFile> projectFilePage = this.page(pageQuery.build(), this.buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(projectFilePage));
}
/**
* 查询符合条件的项目文件存储列表
*
* @param req 查询条件
* @return 项目文件存储列表
*/
@Override
public List<BusProjectFileVo> queryList(ProjectFileQueryReq req) {
LambdaQueryWrapper<BusProjectFile> lqw = this.buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 修改项目文件存储
*
* @param req 项目文件存储
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(ProjectFileUpdateReq req) {
// 将实体类和 DTO 进行转换
BusProjectFile projectFile = new BusProjectFile();
BeanUtils.copyProperties(req, projectFile);
// 数据校验
validEntityBeforeSave(projectFile, false);
// 判断是否存在
BusProjectFile oldProjectFile = this.getById(projectFile.getId());
if (oldProjectFile == null) {
throw new ServiceException("修改项目文件存储失败,数据不存在", HttpStatus.NOT_FOUND);
}
// 操作数据库
boolean update = this.updateById(projectFile);
if (!update) {
throw new ServiceException("修改项目文件存储失败,数据库异常", HttpStatus.ERROR);
}
return true;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusProjectFile entity, Boolean create) {
// TODO 做一些数据校验,如唯一约束
Long projectId = entity.getProjectId();
if (create) {
if (projectId == null) {
throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST);
}
}
if (projectId != null && projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
}
}
/**
* 校验并批量删除项目文件存储信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 根据id获取JSON文件
*
* @param id 主键
* @return JSON文件
*/
@Override
public JSONObject getJSONFile(Long id) {
BusProjectFile projectFile = this.getById(id);
if (projectFile == null) {
throw new ServiceException("对应项目文件存储信息不存在", HttpStatus.NOT_FOUND);
}
String filePath = projectFile.getFilePath();
String suffix = FileUtil.getSuffix(FileUtil.getName(filePath));
if (!suffix.equals("json")) {
throw new ServiceException("文件格式不正确只能解析json文件", HttpStatus.BAD_REQUEST);
}
JSONObject jsonObject;
try {
String property = System.getProperty("user.dir");
Path path = Paths.get(property, filePath);
String jsonStr = Files.readString(path, StandardCharsets.UTF_8);
jsonObject = JSONUtil.parseObj(jsonStr);
} catch (IOException e) {
throw new ServiceException("文件读取失败", HttpStatus.ERROR);
}
return jsonObject;
}
/**
* 上传dxf文件并转换为json
*
* @param file 文件
* @param req 请求
* @return 主键
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long uploadDxf2Json(MultipartFile file, ProjectFileUploadDxfReq req) {
// 校验文件是否为空
if (file == null) {
throw new ServiceException("dxf文件不能为空", HttpStatus.BAD_REQUEST);
}
// 校验是否为 dxf 文件
String fileName = file.getOriginalFilename();
String suffix = FileUtil.getSuffix(fileName);
if (!Objects.equals(suffix, "dxf")) {
throw new ServiceException("文件格式不正确,只能上传.dxf文件", HttpStatus.BAD_REQUEST);
}
// 校验项目是否存在
Long projectId = req.getProjectId();
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND);
}
// 获取当前项目根目录
String projectRoot = System.getProperty("user.dir");
// 构造保存 DXF 的目录
String bashPath = DxfFileConstant.getDxfProjectPath(projectId);
String filePath = projectRoot + File.separator + bashPath;
if (!FileUtil.exist(filePath)) {
FileUtil.mkdir(filePath);
}
String inputDXFPath = filePath + File.separator + fileName;
try {
// 保存文件
File savedFile = new File(inputDXFPath);
file.transferTo(savedFile);
} catch (IOException e) {
throw new ServiceException("dxf 文件保存失败");
}
// 构造 JSON 输出路径
String uuid = IdUtil.fastSimpleUUID();
String outputJSONPath = filePath + File.separator + uuid + ".json";
// 获取 dxf2json.exe 路径
String exePath = projectRoot + File.separator + DxfFileConstant.DXF_BASE_PATH + File.separator + "main.exe";
String sourceEPSG = DxfFileConstant.EPSG4524;
String targetEPSG = DxfFileConstant.EPSG4326;
// 构造命令行参数
DxfUtils.dxf2json(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
// 删除之前的数据库记录和文件
BusProjectFile oldProjectFile = this.lambdaQuery()
.eq(BusProjectFile::getProjectId, projectId)
.one();
if (oldProjectFile != null) {
boolean result = this.removeById(oldProjectFile);
if (!result) {
throw new ServiceException("删除项目文件存储失败,数据库异常", HttpStatus.ERROR);
}
// 删除之前的文件
try {
FileUtil.del(oldProjectFile.getFilePath());
} catch (Exception e) {
log.error("删除项目文件失败", e);
}
}
// 保存项目文件存储
BusProjectFile projectFile = new BusProjectFile();
projectFile.setProjectId(projectId);
projectFile.setFileName(FileUtil.getPrefix(fileName) + ".json");
projectFile.setFilePath(bashPath + File.separator + uuid + ".json");
boolean save = this.save(projectFile);
if (!save) {
throw new ServiceException("保存项目文件存储失败,数据库异常", HttpStatus.ERROR);
}
return projectFile.getId();
}
/**
* 获取项目文件存储视图对象
*
* @param projectFile 项目文件存储对象
* @return 项目文件存储视图对象
*/
@Override
public BusProjectFileVo getVo(BusProjectFile projectFile) {
// 对象转封装类
BusProjectFileVo projectFileVo = new BusProjectFileVo();
if (projectFile == null) {
return projectFileVo;
}
BeanUtils.copyProperties(projectFile, projectFileVo);
return projectFileVo;
}
/**
* 获取项目文件存储查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
@Override
public LambdaQueryWrapper<BusProjectFile> buildQueryWrapper(ProjectFileQueryReq req) {
LambdaQueryWrapper<BusProjectFile> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long projectId = req.getProjectId();
String fileType = req.getFileType();
String fileName = req.getFileName();
lqw.like(StringUtils.isNotBlank(fileName), BusProjectFile::getFileName, fileName);
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusProjectFile::getProjectId, projectId);
lqw.eq(StringUtils.isNotBlank(fileType), BusProjectFile::getFileType, fileType);
return lqw;
}
/**
* 获取项目文件存储分页对象视图
*
* @param projectFilePage 项目文件存储分页对象
* @return 项目文件存储分页对象视图
*/
@Override
public Page<BusProjectFileVo> getVoPage(Page<BusProjectFile> projectFilePage) {
List<BusProjectFile> projectFileList = projectFilePage.getRecords();
Page<BusProjectFileVo> projectFileVoPage = new Page<>(
projectFilePage.getCurrent(),
projectFilePage.getSize(),
projectFilePage.getTotal());
if (CollUtil.isEmpty(projectFileList)) {
return projectFileVoPage;
}
List<BusProjectFileVo> projectFileVoList = projectFileList.stream().map(this::getVo).toList();
projectFileVoPage.setRecords(projectFileVoList);
return projectFileVoPage;
}
}

View File

@ -19,6 +19,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.project.domain.BusContractor;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusProjectFile;
import org.dromara.project.domain.BusUserProjectRelevancy;
import org.dromara.project.domain.req.project.ProjectCreateReq;
import org.dromara.project.domain.req.project.ProjectQueryReq;
@ -27,6 +28,7 @@ import org.dromara.project.domain.resp.project.ProjectContractorListResp;
import org.dromara.project.domain.vo.BusProjectVo;
import org.dromara.project.mapper.BusProjectMapper;
import org.dromara.project.service.IBusContractorService;
import org.dromara.project.service.IBusProjectFileService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusUserProjectRelevancyService;
import org.springframework.beans.BeanUtils;
@ -55,6 +57,10 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
@Resource
private IBusContractorService contractorService;
@Lazy
@Resource
private IBusProjectFileService projectFileService;
/**
* 查询项目
*
@ -206,7 +212,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
throw new ServiceException("修改项目失败,数据不存在", HttpStatus.NOT_FOUND);
}
// 判断名称是否重复
if (!req.getProjectName().equals(oldProject.getProjectName())) {
if (req.getProjectName() != null && !req.getProjectName().equals(oldProject.getProjectName())) {
Long count = this.lambdaQuery().eq(BusProject::getProjectName, req.getProjectName()).count();
if (count > 0) {
throw new ServiceException("项目名称重复", HttpStatus.BAD_REQUEST);
@ -287,6 +293,13 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
projectVo.setPlayCardStart(split[0]);
projectVo.setPlayCardEnd(split[1]);
}
// 关联设计id
BusProjectFile projectFile = projectFileService.lambdaQuery()
.eq(BusProjectFile::getProjectId, project.getId())
.one();
if (projectFile != null) {
projectVo.setDesignId(projectFile.getId());
}
return projectVo;
}
@ -351,8 +364,29 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
if (CollUtil.isEmpty(projectList)) {
return projectVoPage;
}
// 获取项目文件id
Set<Long> projectIdList = projectList.stream().map(BusProject::getId).collect(Collectors.toSet());
Map<Long, List<BusProjectFile>> projectFileMap = projectFileService.lambdaQuery()
.in(BusProjectFile::getProjectId, projectIdList).list()
.stream().collect(Collectors.groupingBy(BusProjectFile::getProjectId));
// 对象列表 => 封装对象列表
List<BusProjectVo> projectVoList = projectList.stream().map(this::getVo).toList();
List<BusProjectVo> projectVoList = projectList.stream().map(project -> {
// 对象转封装类
BusProjectVo projectVo = new BusProjectVo();
BeanUtils.copyProperties(project, projectVo);
String punchRange = project.getPunchRange();
if (StringUtils.isNotBlank(punchRange)) {
String[] split = punchRange.split(",");
projectVo.setPlayCardStart(split[0]);
projectVo.setPlayCardEnd(split[1]);
}
// 关联设计id
List<BusProjectFile> projectFileList = projectFileMap.get(project.getId());
if (CollUtil.isNotEmpty(projectFileList)) {
projectVo.setDesignId(projectFileList.get(0).getId());
}
return projectVo;
}).toList();
projectVoPage.setRecords(projectVoList);
return projectVoPage;
}

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.constant.HttpStatus;
@ -13,6 +14,7 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
@ -54,6 +56,7 @@ import java.util.zip.ZipOutputStream;
* @author lcj
* @date 2025-04-16
*/
@Slf4j
@Service
public class BusQualityConstructionLogServiceImpl extends ServiceImpl<BusQualityConstructionLogMapper, BusQualityConstructionLog>
implements IBusQualityConstructionLogService {
@ -320,6 +323,17 @@ public class BusQualityConstructionLogServiceImpl extends ServiceImpl<BusQuality
}
Map<String, String> replacementMap = getReplacementMap(qualityConstructionLog);
Path targetDir = Paths.get(QualityConstant.getQualityConstructionLogFileUrl(qualityConstructionLog));
// 如果存在目录则直接返回,不存在则生成文件并返回
if (!Files.exists(targetDir)) {
// 清理旧文件
String baseUrl = QualityConstant.QUALITY_CONSTRUCTION_LOG_FILE_URL + qualityConstructionLog.getId();
try {
Path dirPath = Paths.get(baseUrl);
FileUtils.deleteDirectory(dirPath);
} catch (IOException e) {
log.error("文件目录:{},清理失败", baseUrl, e);
}
// 生成文件
try (FileInputStream fis = new FileInputStream(QualityConstant.QUALITY_CONSTRUCTION_LOG_TEMPLATE_PATH);
XWPFDocument document = new XWPFDocument(fis)) {
// 替换段落中的文本
@ -349,7 +363,8 @@ public class BusQualityConstructionLogServiceImpl extends ServiceImpl<BusQuality
} catch (IOException | InvalidFormatException e) {
throw new OssException("生成Word文件失败错误信息: " + e.getMessage());
}
// 设置响应头
}
// 设置响应头返回ZIP文件
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
DocumentUtils.zipDirectory(targetDir, targetDir, zos);

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.constant.HttpStatus;
@ -13,6 +14,7 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
@ -58,6 +60,7 @@ import java.util.zip.ZipOutputStream;
* @author lcj
* @date 2025-04-16
*/
@Slf4j
@Service
public class BusQualityInspectionServiceImpl extends ServiceImpl<BusQualityInspectionMapper, BusQualityInspection>
implements IBusQualityInspectionService {
@ -372,6 +375,17 @@ public class BusQualityInspectionServiceImpl extends ServiceImpl<BusQualityInspe
}
Map<String, String> replacementMap = getReplacementMap(qualityInspection);
Path targetDir = Paths.get(QualityConstant.getQualityInspectionFileUrl(qualityInspection));
// 如果存在目录则直接返回,不存在则生成文件并返回
if (!Files.exists(targetDir)) {
// 清理旧文件
String baseUrl = QualityConstant.QUALITY_INSPECTION_FILE_URL + qualityInspection.getId();
try {
Path dirPath = Paths.get(baseUrl);
FileUtils.deleteDirectory(dirPath);
} catch (IOException e) {
log.error("文件目录:{},清理失败", baseUrl, e);
}
// 生成文件
try (FileInputStream fis = new FileInputStream(QualityConstant.QUALITY_INSPECTION_TEMPLATE_PATH);
XWPFDocument document = new XWPFDocument(fis)) {
// 替换段落中的文本
@ -401,7 +415,8 @@ public class BusQualityInspectionServiceImpl extends ServiceImpl<BusQualityInspe
} catch (IOException | InvalidFormatException e) {
throw new OssException("生成Word文件失败错误信息: " + e.getMessage());
}
// 设置响应头
}
// 设置响应头返回ZIP文件
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
DocumentUtils.zipDirectory(targetDir, targetDir, zos);

View File

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.dromara.common.core.constant.HttpStatus;
@ -14,6 +15,7 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
@ -59,6 +61,7 @@ import java.util.zip.ZipOutputStream;
* @author lcj
* @date 2025-03-20
*/
@Slf4j
@Service
public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspectionMapper, BusSafetyInspection>
implements IBusSafetyInspectionService {
@ -334,6 +337,17 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspect
}
Map<String, String> replacementMap = getReplacementMap(safetyInspection);
Path targetDir = Paths.get(SafetyConstant.getSafetyInspectionFileUrl(safetyInspection));
// 如果存在目录则直接返回,不存在则生成文件并返回
if (!Files.exists(targetDir)) {
// 清理旧文件
String baseUrl = SafetyConstant.SAFETY_INSPECTION_FILE_URL + safetyInspection.getId();
try {
Path dirPath = Paths.get(baseUrl);
FileUtils.deleteDirectory(dirPath);
} catch (IOException e) {
log.error("文件目录:{},清理失败", baseUrl, e);
}
// 生成文件
try (FileInputStream fis = new FileInputStream(SafetyConstant.SAFETY_INSPECTION_TEMPLATE_PATH);
XWPFDocument document = new XWPFDocument(fis)) {
// 替换段落中的文本
@ -363,7 +377,8 @@ public class BusSafetyInspectionServiceImpl extends ServiceImpl<BusSafetyInspect
} catch (IOException | InvalidFormatException e) {
throw new OssException("生成Word文件失败错误信息: " + e.getMessage());
}
// 设置响应头
}
// 设置响应头返回ZIP文件
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
DocumentUtils.zipDirectory(targetDir, targetDir, zos);

View File

@ -0,0 +1,98 @@
package org.dromara.utils;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
/**
* @author lcj
* @date 2025/4/23 10:42
*/
@Slf4j
public class DxfUtils {
/**
* dxf转json
*
* @param exePath dxf2json.exe路径
* @param inputDXFPath 输入dxf文件路径
* @param outputJSONPath 输出json文件路径
* @param sourceEPSG 源坐标系
* @param targetEPSG 目标坐标系
*/
public static void dxf2json(String exePath, String inputDXFPath, String outputJSONPath, String sourceEPSG, String targetEPSG) {
// 判断对应文件是否存在
File exeFile = new File(exePath);
if (!exeFile.exists()) {
throw new ServiceException("转换程序不存在!");
}
File inputDXFFile = new File(inputDXFPath);
if (!inputDXFFile.exists()) {
throw new ServiceException("待转换 dxf 文件不存在!");
}
// 构造命令行参数
List<String> parameters = buildParameter(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
// 执行命令行
ProcessBuilder builder = new ProcessBuilder(parameters);
// 合并标准错误和输出
builder.redirectErrorStream(true);
try {
Process process = builder.start();
// 读取输出
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), "GBK")
);
String line;
log.info("dxf 转 json 程序开始执行,程序路径:{},输入 dxf 路径:{},输出 json 文件路径:{},源坐标系:{},模板坐标系:{}",
exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
while ((line = reader.readLine()) != null) {
log.info("dxf 转 json 程序执行中:{}", line);
}
int exitCode = process.waitFor();
log.info("dxf 转 json 程序执行完毕,程序退出码:{}", exitCode);
reader.close();
} catch (IOException | InterruptedException e) {
log.error("执行 dxf 转 json 命令行时出错", e);
}finally {
// 删除dxf文件
if (inputDXFFile.exists()) {
boolean delete = inputDXFFile.delete();
if (!delete) {
log.error("dxf文件删除失败路径{}", inputDXFPath);
}
}
}
}
/**
* 构造命令行参数
*
* @param exePath dxf2json.exe路径
* @param inputDXFPath 输入dxf文件路径
* @param outputJSONPath 输出json文件路径
* @param sourceEPSG 源坐标系
* @param targetEPSG 目标坐标系
* @return 命令行参数
*/
public static List<String> buildParameter(String exePath,
String inputDXFPath,
String outputJSONPath,
String sourceEPSG,
String targetEPSG) {
// 构造命令行
return Arrays.asList(
exePath,
inputDXFPath,
outputJSONPath,
sourceEPSG,
targetEPSG
);
}
}

View File

@ -0,0 +1,7 @@
<?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="org.dromara.project.mapper.BusProjectFileMapper">
</mapper>

View File

@ -924,3 +924,18 @@ CREATE TABLE `fac_box_transformer`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-箱变' COLLATE = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_project_file`;
CREATE TABLE `bus_project_file`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint not null comment '项目id',
`file_type` char(2) null comment '文件类型',
`file_name` varchar(255) null comment '文件名称',
`file_path` varchar(1024) null comment '文件路径',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`remark` varchar(512) null comment '备注',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) comment = '项目文件存储' collate = utf8mb4_unicode_ci;