|
@@ -0,0 +1,294 @@
|
|
|
+package com.zkqy.web.controller.system;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.nio.file.DirectoryStream;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.time.Instant;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.zip.ZipEntry;
|
|
|
+import java.util.zip.ZipOutputStream;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+
|
|
|
+import com.zkqy.common.config.ZkqyConfig;
|
|
|
+import com.zkqy.common.core.domain.entity.DataSource;
|
|
|
+import com.zkqy.common.core.domain.entity.SysUser;
|
|
|
+import com.zkqy.common.utils.DateUtils;
|
|
|
+import com.zkqy.common.utils.SecurityUtils;
|
|
|
+import io.swagger.annotations.Api;
|
|
|
+import io.swagger.annotations.ApiOperation;
|
|
|
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|
|
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
|
|
+import org.apache.commons.compress.utils.IOUtils;
|
|
|
+import org.springframework.core.io.InputStreamResource;
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.http.ResponseEntity;
|
|
|
+import org.springframework.security.access.prepost.PreAuthorize;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.web.bind.annotation.GetMapping;
|
|
|
+import org.springframework.web.bind.annotation.PostMapping;
|
|
|
+import org.springframework.web.bind.annotation.PutMapping;
|
|
|
+import org.springframework.web.bind.annotation.DeleteMapping;
|
|
|
+import org.springframework.web.bind.annotation.PathVariable;
|
|
|
+import org.springframework.web.bind.annotation.RequestBody;
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
+import com.zkqy.common.annotation.Log;
|
|
|
+import com.zkqy.common.core.controller.BaseController;
|
|
|
+import com.zkqy.common.core.domain.AjaxResult;
|
|
|
+import com.zkqy.common.enums.BusinessType;
|
|
|
+import com.zkqy.system.domain.SysEngineering;
|
|
|
+import com.zkqy.system.service.ISysEngineeringService;
|
|
|
+import com.zkqy.common.utils.poi.ExcelUtil;
|
|
|
+import com.zkqy.common.core.page.TableDataInfo;
|
|
|
+import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 工程部署Controller
|
|
|
+ *
|
|
|
+ * @author zkqy
|
|
|
+ * @date 2024-01-03
|
|
|
+ */
|
|
|
+@RestController
|
|
|
+@RequestMapping("/system/engineering")
|
|
|
+public class SysEngineeringController extends BaseController
|
|
|
+{
|
|
|
+ @Autowired
|
|
|
+ private ISysEngineeringService sysEngineeringService;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 查询工程部署列表
|
|
|
+ */
|
|
|
+@PreAuthorize("@ss.hasPermi('system:engineering:list')")
|
|
|
+@GetMapping("/list")
|
|
|
+@ApiOperation(value = "查询工程部署列表")
|
|
|
+ public TableDataInfo list(SysEngineering sysEngineering)
|
|
|
+ {
|
|
|
+ startPage();
|
|
|
+ List<SysEngineering> list = sysEngineeringService.selectSysEngineeringList(sysEngineering);
|
|
|
+ return getDataTable(list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出工程部署列表
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('system:engineering:export')")
|
|
|
+ @Log(title = "工程部署", businessType = BusinessType.EXPORT)
|
|
|
+ @PostMapping("/export")
|
|
|
+ @ApiOperation(value = "导出工程部署列表")
|
|
|
+ public void export(HttpServletResponse response, SysEngineering sysEngineering)
|
|
|
+ {
|
|
|
+ List<SysEngineering> list = sysEngineeringService.selectSysEngineeringList(sysEngineering);
|
|
|
+ ExcelUtil<SysEngineering> util = new ExcelUtil<SysEngineering>(SysEngineering.class);
|
|
|
+ util.exportExcel(response, list, "工程部署数据");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取工程部署详细信息
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('system:engineering:query')")
|
|
|
+ @GetMapping(value = "/{id}")
|
|
|
+ @ApiOperation(value = "获取工程部署详细信息")
|
|
|
+ public AjaxResult getInfo(@PathVariable("id") Long id)
|
|
|
+ {
|
|
|
+ return success(sysEngineeringService.selectSysEngineeringById(id));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增工程部署
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('system:engineering:add')")
|
|
|
+ @Log(title = "工程部署", businessType = BusinessType.INSERT)
|
|
|
+ @PostMapping
|
|
|
+ @ApiOperation(value = "新增工程部署")
|
|
|
+ public AjaxResult add(@RequestBody SysEngineering sysEngineering)
|
|
|
+ {
|
|
|
+ return toAjax(sysEngineeringService.insertSysEngineering(sysEngineering));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改工程部署
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('system:engineering:edit')")
|
|
|
+ @Log(title = "工程部署", businessType = BusinessType.UPDATE)
|
|
|
+ @PutMapping
|
|
|
+ @ApiOperation(value = "修改工程部署")
|
|
|
+ public AjaxResult edit(@RequestBody SysEngineering sysEngineering)
|
|
|
+ {
|
|
|
+ return toAjax(sysEngineeringService.updateSysEngineering(sysEngineering));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除工程部署
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('system:engineering:remove')")
|
|
|
+ @Log(title = "工程部署", businessType = BusinessType.DELETE)
|
|
|
+ @DeleteMapping("/{ids}")
|
|
|
+ @ApiOperation(value = "删除工程部署")
|
|
|
+ public AjaxResult remove(@PathVariable Long[] ids)
|
|
|
+ {
|
|
|
+ return toAjax(sysEngineeringService.deleteSysEngineeringByIds(ids));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载压缩包
|
|
|
+ */
|
|
|
+ @GetMapping("/download")
|
|
|
+ public ResponseEntity<StreamingResponseBody> downloadZip() {
|
|
|
+
|
|
|
+ // 指定要打包的文件或目录路径
|
|
|
+ String sourceFilePath = ZkqyConfig.getUploadPath() + "/engineeringdownload/";
|
|
|
+
|
|
|
+ File dir = new File(sourceFilePath);
|
|
|
+ // 判断文件夹路径是否存在,不存在创建
|
|
|
+ if (!dir.exists()){
|
|
|
+ boolean isCreated = dir.mkdirs();
|
|
|
+ if (!isCreated) {
|
|
|
+ System.out.println("目录 '" + sourceFilePath + "' 创建失败.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //当前用户数据源信息
|
|
|
+ DataSource datasourceInfo = SecurityUtils.getDatasourceInfo();
|
|
|
+ //导出数据库集合
|
|
|
+ Set<String> databaseList = new LinkedHashSet<>();
|
|
|
+ databaseList.add("ry-vue-call");
|
|
|
+// databaseList.add("zkqy-template");
|
|
|
+// databaseList.add("zkqy-call");
|
|
|
+ databaseList.add(datasourceInfo.getDatabaseName());
|
|
|
+ //将sql文件导出到指定目录下
|
|
|
+ exportMultipleDatabasesToLocal(databaseList,sourceFilePath,datasourceInfo);
|
|
|
+
|
|
|
+ //下载成功插入数据
|
|
|
+ SysUser sysUser = SecurityUtils.getLoginUser().getUser();
|
|
|
+ SysEngineering sysEngineering = new SysEngineering();
|
|
|
+ sysEngineering.setCreateTime(DateUtils.getNowDate());
|
|
|
+ sysEngineering.setDownloadTime(DateUtils.getNowDate());
|
|
|
+ sysEngineering.setEngineeringName(sysUser.getTenantName() + "-mes");
|
|
|
+ sysEngineeringService.insertSysEngineering(sysEngineering);
|
|
|
+
|
|
|
+ String zipFileName = new Date().getTime()+".zip";
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + zipFileName + "\"");
|
|
|
+ headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
|
|
+
|
|
|
+ return ResponseEntity.ok()
|
|
|
+ .headers(headers)
|
|
|
+ .contentType(MediaType.APPLICATION_OCTET_STREAM)
|
|
|
+ .body(outputStream -> {
|
|
|
+ try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(sourceFilePath));
|
|
|
+ ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {
|
|
|
+
|
|
|
+ addFilesToZipRecursively(zipOut, Paths.get(sourceFilePath), directoryStream);
|
|
|
+
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException("Failed to create the ZIP stream.", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addFilesToZipRecursively(ZipOutputStream zipOut, Path rootPath, DirectoryStream<Path> dirStream) throws IOException {
|
|
|
+ for (Path filePath : dirStream) {
|
|
|
+ if (Files.isDirectory(filePath)) {
|
|
|
+ // 添加目录条目到ZIP
|
|
|
+ String entryName = filePath.toString().substring(rootPath.toString().length() + 1) + "/";
|
|
|
+ zipOut.putNextEntry(new ZipEntry(entryName));
|
|
|
+ zipOut.closeEntry();
|
|
|
+
|
|
|
+ // 递归处理子目录中的文件
|
|
|
+ try (DirectoryStream<Path> subDirStream = Files.newDirectoryStream(filePath)) {
|
|
|
+ addFilesToZipRecursively(zipOut, rootPath, subDirStream);
|
|
|
+ }
|
|
|
+ } else if (Files.isRegularFile(filePath)) {
|
|
|
+ // 添加文件到ZIP
|
|
|
+ String entryName = filePath.toString().substring(rootPath.toString().length() + 1);
|
|
|
+ zipOut.putNextEntry(new ZipEntry(entryName));
|
|
|
+
|
|
|
+ try (InputStream fileIn = Files.newInputStream(filePath)) {
|
|
|
+ byte[] buffer = new byte[4096];
|
|
|
+ int read;
|
|
|
+ while ((read = fileIn.read(buffer)) != -1) {
|
|
|
+ zipOut.write(buffer, 0, read);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ zipOut.closeEntry();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出数据库文件
|
|
|
+ */
|
|
|
+ public void exportMultipleDatabasesToLocal(Set<String> databaseNames, String outputPath, DataSource dataSource){
|
|
|
+ outputPath = outputPath + "sql/";
|
|
|
+
|
|
|
+ File dir = new File(outputPath);
|
|
|
+ // 判断文件夹路径是否存在,不存在创建
|
|
|
+ if (!dir.exists()){
|
|
|
+ boolean isCreated = dir.mkdirs();
|
|
|
+ if (!isCreated) {
|
|
|
+ System.out.println("目录 '" + outputPath + "' 创建失败.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (String databaseName : databaseNames){
|
|
|
+ try {
|
|
|
+ // 构建命令参数列表
|
|
|
+ List<String> cmd = new ArrayList<>();
|
|
|
+ cmd.add("mysqldump");
|
|
|
+ cmd.add("--column-statistics=0");
|
|
|
+ cmd.add("-h");
|
|
|
+ cmd.add(dataSource.getDatabaseIp());
|
|
|
+ cmd.add("-u");
|
|
|
+ cmd.add(dataSource.getUsername());
|
|
|
+ cmd.add("-p" + dataSource.getPassword());
|
|
|
+ cmd.add(databaseName);
|
|
|
+
|
|
|
+ ProcessBuilder pb = new ProcessBuilder(cmd);
|
|
|
+ // 设置MySQL bin目录到PATH环境变量,确保mysqldump可执行文件能找到
|
|
|
+// Map<String, String> env = pb.environment();
|
|
|
+// env.put("PATH", env.get("PATH") + File.pathSeparator + "D:\\software\\installpath\\mysql-8.0.20\\mysql-8.0.20-winx64\\bin");
|
|
|
+
|
|
|
+ // 创建进程并获取输出流
|
|
|
+ Process process = pb.start();
|
|
|
+
|
|
|
+ // 将mysqldump的输出重定向到文件
|
|
|
+ OutputStream outStream = new FileOutputStream(Paths.get(outputPath+databaseName+".sql").toFile());
|
|
|
+ InputStream processOutput = process.getInputStream();
|
|
|
+ byte[] buffer = new byte[4096];
|
|
|
+ int read;
|
|
|
+ while ((read = processOutput.read(buffer)) != -1) {
|
|
|
+ outStream.write(buffer, 0, read);
|
|
|
+ }
|
|
|
+ outStream.close();
|
|
|
+ processOutput.close();
|
|
|
+
|
|
|
+ // 获取错误流,并打印或处理任何错误信息
|
|
|
+ InputStream errorStream = process.getErrorStream();
|
|
|
+ BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream));
|
|
|
+ String line;
|
|
|
+ while ((line = errorReader.readLine()) != null) {
|
|
|
+ System.err.println(line);
|
|
|
+ }
|
|
|
+ errorReader.close();
|
|
|
+ errorStream.close();
|
|
|
+
|
|
|
+ // 等待进程结束并检查退出码
|
|
|
+ int exitCode = process.waitFor();
|
|
|
+ if (exitCode == 0) {
|
|
|
+ System.out.println("数据库备份成功,导出文件: " + outputPath);
|
|
|
+ } else {
|
|
|
+ System.err.println("mysqldump命令执行失败,退出代码: " + exitCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (IOException | InterruptedException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|