diff --git a/orion-ops-service/src/main/java/com/orion/ops/consts/export/ExportConst.java b/orion-ops-service/src/main/java/com/orion/ops/consts/export/ExportConst.java
new file mode 100644
index 00000000..51b72c6d
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/consts/export/ExportConst.java
@@ -0,0 +1,31 @@
+package com.orion.ops.consts.export;
+
+import com.orion.utils.Strings;
+import com.orion.utils.time.Dates;
+
+/**
+ * 导出常量
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/26 16:14
+ */
+public class ExportConst {
+
+ private ExportConst() {
+ }
+
+ public static final String MACHINE_EXPORT_NAME = "机器导出信息{}.xlsx";
+
+
+ /**
+ * 格式导出文件名
+ *
+ * @param name name
+ * @return name
+ */
+ public static String getFileName(String name) {
+ return Strings.format(name, Dates.current(Dates.YMD_HM2));
+ }
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/consts/export/ExportType.java b/orion-ops-service/src/main/java/com/orion/ops/consts/export/ExportType.java
new file mode 100644
index 00000000..26491278
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/consts/export/ExportType.java
@@ -0,0 +1,39 @@
+package com.orion.ops.consts.export;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 导出类型
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/27 17:17
+ */
+@AllArgsConstructor
+@Getter
+public enum ExportType {
+
+ /**
+ * 导出机器
+ */
+ MACHINE(10),
+
+ ;
+
+ private final Integer type;
+
+
+ public static ExportType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (ExportType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageClassify.java b/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageClassify.java
index ba8943a1..97ddf722 100644
--- a/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageClassify.java
+++ b/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageClassify.java
@@ -19,6 +19,11 @@ public enum MessageClassify {
*/
SYSTEM(10),
+ /**
+ * 数据导入
+ */
+ IMPORT(20),
+
;
private final Integer classify;
diff --git a/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageType.java b/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageType.java
index 644c9ec9..d7f95bf7 100644
--- a/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageType.java
+++ b/orion-ops-service/src/main/java/com/orion/ops/consts/message/MessageType.java
@@ -14,6 +14,8 @@ import lombok.Getter;
@Getter
public enum MessageType {
+ // -------------------- 系统消息 --------------------
+
/**
* 命令执行完成
*/
@@ -84,6 +86,18 @@ public enum MessageType {
*/
PIPELINE_EXEC_FAILURE(1140, MessageClassify.SYSTEM, "应用流水线 ${name} ${title} 执行失败"),
+ // -------------------- 导入通知 --------------------
+
+ /**
+ * 导入机器成功
+ */
+ MACHINE_IMPORT_SUCCESS(2010, MessageClassify.IMPORT, "您在 ${time} 进行的机器导入操作执行完成"),
+
+ /**
+ * 导入机器失败
+ */
+ MACHINE_IMPORT_FAILURE(2020, MessageClassify.IMPORT, "您在 ${time} 进行的机器导入操作执行失败"),
+
;
private final Integer type;
diff --git a/orion-ops-service/src/main/java/com/orion/ops/controller/DataExportController.java b/orion-ops-service/src/main/java/com/orion/ops/controller/DataExportController.java
new file mode 100644
index 00000000..93b30e95
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/controller/DataExportController.java
@@ -0,0 +1,41 @@
+package com.orion.ops.controller;
+
+import com.orion.ops.annotation.EventLog;
+import com.orion.ops.consts.event.EventType;
+import com.orion.ops.consts.export.ExportConst;
+import com.orion.ops.entity.request.DataExportRequest;
+import com.orion.ops.service.api.DataExportService;
+import com.orion.servlet.web.Servlets;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 数据导出 controller
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/26 14:02
+ */
+@RestController
+@RequestMapping("/orion/api/data-export")
+public class DataExportController {
+
+ @Resource
+ private DataExportService dataExportService;
+
+ /**
+ * 导出机器
+ */
+ @RequestMapping("/machine")
+ @EventLog(EventType.DATA_EXPORT_MACHINE)
+ public void exportMachine(@RequestBody DataExportRequest request, HttpServletResponse response) throws IOException {
+ Servlets.setDownloadHeader(response, ExportConst.getFileName(ExportConst.MACHINE_EXPORT_NAME));
+ dataExportService.exportMachine(request, response);
+ }
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/entity/dto/MachineInfoExportDTO.java b/orion-ops-service/src/main/java/com/orion/ops/entity/dto/MachineInfoExportDTO.java
new file mode 100644
index 00000000..f622cb9f
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/entity/dto/MachineInfoExportDTO.java
@@ -0,0 +1,87 @@
+package com.orion.ops.entity.dto;
+
+import com.orion.office.excel.annotation.ExportField;
+import com.orion.office.excel.annotation.ExportSheet;
+import com.orion.office.excel.annotation.ExportTitle;
+import com.orion.ops.consts.machine.MachineAuthType;
+import com.orion.ops.entity.domain.MachineInfoDO;
+import com.orion.utils.convert.TypeStore;
+import lombok.Data;
+
+/**
+ * 机器信息导出
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/26 14:01
+ */
+@Data
+@ExportTitle(title = "机器信息导出")
+@ExportSheet(name = "机器信息", height = 22, freezeHeader = true, filterHeader = true)
+public class MachineInfoExportDTO {
+
+ /**
+ * 机器名称
+ */
+ @ExportField(index = 0, header = "机器名称", width = 30)
+ private String name;
+
+ /**
+ * 机器标签
+ */
+ @ExportField(index = 1, header = "唯一标识", width = 25)
+ private String tag;
+
+ /**
+ * 机器主机
+ */
+ @ExportField(index = 2, header = "机器主机", width = 30)
+ private String host;
+
+ /**
+ * ssh 端口
+ */
+ @ExportField(index = 3, header = "ssh 端口", width = 10)
+ private Integer port;
+
+ /**
+ * 用户名
+ */
+ @ExportField(index = 4, header = "用户名", width = 20)
+ private String username;
+
+ /**
+ * 密码 (密文)
+ */
+ @ExportField(index = 5, header = "导出密码 (密文)", width = 20, wrapText = true)
+ private String encryptPassword;
+
+ /**
+ * 导入密码 (明文)
+ */
+ @ExportField(index = 6, header = "导入密码 (明文)", width = 20, wrapText = true)
+ private String importPassword;
+
+ /**
+ * 描述
+ */
+ @ExportField(index = 7, header = "描述", width = 25, wrapText = true)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(MachineInfoDO.class, MachineInfoExportDTO.class, p -> {
+ MachineInfoExportDTO dto = new MachineInfoExportDTO();
+ dto.setName(p.getMachineName());
+ dto.setTag(p.getMachineTag());
+ dto.setHost(p.getMachineHost());
+ dto.setPort(p.getSshPort());
+ dto.setUsername(p.getUsername());
+ if (MachineAuthType.PASSWORD.getType().equals(p.getAuthType())) {
+ dto.setEncryptPassword(p.getPassword());
+ }
+ dto.setDescription(p.getDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/entity/request/DataExportRequest.java b/orion-ops-service/src/main/java/com/orion/ops/entity/request/DataExportRequest.java
new file mode 100644
index 00000000..bfaddb2e
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/entity/request/DataExportRequest.java
@@ -0,0 +1,28 @@
+package com.orion.ops.entity.request;
+
+import lombok.Data;
+
+/**
+ * 数据导出请求
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/26 16:10
+ */
+@Data
+public class DataExportRequest {
+
+ /**
+ * 是否导出密码
+ *
+ * @see com.orion.ops.consts.Const#ENABLE
+ * @see com.orion.ops.consts.Const#DISABLE
+ */
+ private Integer exportPassword;
+
+ /**
+ * 保护密码
+ */
+ private String protectPassword;
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/service/api/DataExportService.java b/orion-ops-service/src/main/java/com/orion/ops/service/api/DataExportService.java
new file mode 100644
index 00000000..0d9c5a59
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/service/api/DataExportService.java
@@ -0,0 +1,26 @@
+package com.orion.ops.service.api;
+
+import com.orion.ops.entity.request.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 数据导出服务
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/26 16:18
+ */
+public interface DataExportService {
+
+ /**
+ * 导出机器
+ *
+ * @param request request
+ * @param response response
+ * @throws IOException IOException
+ */
+ void exportMachine(DataExportRequest request, HttpServletResponse response) throws IOException;
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/service/impl/DataExportServiceImpl.java b/orion-ops-service/src/main/java/com/orion/ops/service/impl/DataExportServiceImpl.java
new file mode 100644
index 00000000..b49a8daa
--- /dev/null
+++ b/orion-ops-service/src/main/java/com/orion/ops/service/impl/DataExportServiceImpl.java
@@ -0,0 +1,82 @@
+package com.orion.ops.service.impl;
+
+import com.orion.office.excel.writer.exporting.ExcelExport;
+import com.orion.ops.consts.Const;
+import com.orion.ops.consts.export.ExportType;
+import com.orion.ops.consts.system.SystemEnvAttr;
+import com.orion.ops.dao.MachineInfoDAO;
+import com.orion.ops.entity.domain.MachineInfoDO;
+import com.orion.ops.entity.dto.MachineInfoExportDTO;
+import com.orion.ops.entity.request.DataExportRequest;
+import com.orion.ops.service.api.DataExportService;
+import com.orion.ops.utils.Currents;
+import com.orion.ops.utils.PathBuilders;
+import com.orion.utils.Strings;
+import com.orion.utils.convert.Converts;
+import com.orion.utils.io.FileWriters;
+import com.orion.utils.io.Files1;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 数据导出服务
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/5/26 16:18
+ */
+@Service("dataExportService")
+public class DataExportServiceImpl implements DataExportService {
+
+ @Resource
+ private MachineInfoDAO machineInfoDAO;
+
+ @Override
+ public void exportMachine(DataExportRequest request, HttpServletResponse response) throws IOException {
+ // 查询数据
+ List machineList = machineInfoDAO.selectList(null);
+ List exportList = Converts.toList(machineList, MachineInfoExportDTO.class);
+ if (!Const.ENABLE.equals(request.getExportPassword())) {
+ exportList.forEach(s -> s.setEncryptPassword(null));
+ }
+ // 导出
+ ExcelExport exporter = new ExcelExport<>(MachineInfoExportDTO.class).init();
+ exporter.addRows(exportList);
+ // 写入
+ this.writeWorkbook(request, response, exporter, ExportType.MACHINE);
+ }
+
+ /**
+ * 写入 workbook
+ *
+ * @param request request
+ * @param response response
+ * @param exporter exporter
+ * @param type type
+ * @throws IOException IOException
+ */
+ private void writeWorkbook(DataExportRequest request, HttpServletResponse response,
+ ExcelExport> exporter, ExportType type) throws IOException {
+ // 写入 workbook 到 byte
+ ByteArrayOutputStream store = new ByteArrayOutputStream();
+ String password = request.getProtectPassword();
+ if (!Strings.isBlank(password)) {
+ exporter.write(store, password);
+ } else {
+ exporter.write(store);
+ }
+ // 设置 http 返回
+ byte[] excelData = store.toByteArray();
+ response.getOutputStream().write(excelData);
+ // 保存至本地
+ String exportPath = PathBuilders.getExportDataJsonPath(Currents.getUserId(), type.getType(), Strings.def(password));
+ String path = Files1.getPath(SystemEnvAttr.LOG_PATH.getValue(), exportPath);
+ FileWriters.write(path, excelData);
+ }
+
+}
diff --git a/orion-ops-service/src/main/java/com/orion/ops/utils/PathBuilders.java b/orion-ops-service/src/main/java/com/orion/ops/utils/PathBuilders.java
index e135e8d5..2f14e190 100644
--- a/orion-ops-service/src/main/java/com/orion/ops/utils/PathBuilders.java
+++ b/orion-ops-service/src/main/java/com/orion/ops/utils/PathBuilders.java
@@ -177,6 +177,39 @@ public class PathBuilders {
return Const.PACKAGE_DIR + "/" + fileToken + "." + Const.SUFFIX_ZIP;
}
+ /**
+ * 获取导出数据 xlsx 文件路径
+ *
+ * @param userId userId
+ * @param type type
+ * @return path
+ */
+ public static String getExportDataJsonPath(Long userId, Integer type, String password) {
+ return Const.EXPORT_DIR
+ + "/" + type
+ + "/" + Dates.current(Dates.YMD_HMS2)
+ + "-" + userId
+ + "-" + password
+ + "." + Const.SUFFIX_XLSX;
+ }
+
+ /**
+ * 获取导入数据 json 文件路径
+ *
+ * @param userId userId
+ * @param type type
+ * @param token token
+ * @return path
+ */
+ public static String getImportDataJsonPath(Long userId, Integer type, String token) {
+ return Const.IMPORT_DIR
+ + "/" + type
+ + "/" + Dates.current(Dates.YMD_HMS2)
+ + "-" + userId
+ + "-" + token
+ + "." + Const.SUFFIX_JSON;
+ }
+
/**
* 获取用户根目录
*