diff --git a/build.gradle b/build.gradle index 4659349..7cdc054 100644 --- a/build.gradle +++ b/build.gradle @@ -23,10 +23,10 @@ repositories { dependencies { // SpringBoot原生依赖 - implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' + implementation 'org.springframework.boot:spring-boot-starter-actuator' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/src/main/java/com/realtime/protection/configuration/entity/defense/object/ProtectObject.java b/src/main/java/com/realtime/protection/configuration/entity/defense/object/ProtectObject.java index b8d90a5..1605220 100644 --- a/src/main/java/com/realtime/protection/configuration/entity/defense/object/ProtectObject.java +++ b/src/main/java/com/realtime/protection/configuration/entity/defense/object/ProtectObject.java @@ -1,5 +1,7 @@ package com.realtime.protection.configuration.entity.defense.object; +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; @@ -10,42 +12,53 @@ import lombok.Data; @Data public class ProtectObject { @JsonProperty("proobj_id") + @ExcelIgnore private Integer protectObjectId; @JsonProperty("proobj_name") @NotNull(message = "proobj_name should not be empty.") + @ExcelProperty("名称") private String protectObjectName; @JsonProperty("proobj_system_name") + @ExcelProperty("操作系统名称") private String protectObjectSystemName; @JsonProperty("proobj_ip_address") @Pattern(regexp = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$", message = "Invalid IPv4 Address") + @ExcelProperty("IP地址") private String protectObjectIPAddress; @JsonProperty("proobj_port") @NotNull(message = "proobj_port should not be empty.") @Max(value = 65535, message = "port should not be more than 65535") @Min(value = 1, message = "port should not be less than 1") + @ExcelProperty("端口") private Integer protectObjectPort; @JsonProperty("proobj_url") @NotNull(message = "proobj_url should not be empty.") + @ExcelProperty("URL") private String protectObjectURL; @JsonProperty("proobj_protocol") @NotNull(message = "proobj_protocol should not be empty.") + @ExcelProperty("协议") private String protectObjectProtocol; @JsonProperty("proobj_audit_status") + @ExcelIgnore private Integer protectObjectAuditStatus; @JsonProperty("proobj_create_username") + @ExcelIgnore private String protectObjectCreateUsername; @JsonProperty("proobj_create_depart") + @ExcelIgnore private String protectObjectCreateDepart; @JsonProperty("proobj_create_userid") + @ExcelIgnore private Integer protectObjectCreateUserId; } diff --git a/src/main/java/com/realtime/protection/configuration/utils/SqlSessionWrapper.java b/src/main/java/com/realtime/protection/configuration/utils/SqlSessionWrapper.java index 8795f5c..e336f31 100644 --- a/src/main/java/com/realtime/protection/configuration/utils/SqlSessionWrapper.java +++ b/src/main/java/com/realtime/protection/configuration/utils/SqlSessionWrapper.java @@ -16,13 +16,22 @@ public class SqlSessionWrapper { this.sqlSessionFactory = sqlSessionFactory; } + /** 启动批量SQL会话 + * @param mapperClass MyBatis Mapper类型 + * @param batchFunction 批量函数(批量添加、批量删除、批量更新等) + * @param arguments 函数附带的所有参数,可以使用Map进行包装 + * @param Mapper class + * @param Function input + * @param Function output + * @return 被包装的批量函数返回值 + */ public O startBatchSession(Class mapperClass, - Function> wrappedFunction, + Function> batchFunction, I arguments) { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false); M mapper = sqlSession.getMapper(mapperClass); try { - O result = wrappedFunction.apply(mapper).apply(arguments); + O result = batchFunction.apply(mapper).apply(arguments); sqlSession.commit(); sqlSession.clearCache(); diff --git a/src/main/java/com/realtime/protection/server/defense/object/ProjectObjectDataListener.java b/src/main/java/com/realtime/protection/server/defense/object/ProjectObjectDataListener.java index 55e5e75..0629634 100644 --- a/src/main/java/com/realtime/protection/server/defense/object/ProjectObjectDataListener.java +++ b/src/main/java/com/realtime/protection/server/defense/object/ProjectObjectDataListener.java @@ -5,7 +5,6 @@ import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ListUtils; import com.realtime.protection.configuration.entity.defense.object.ProtectObject; -import org.springframework.beans.factory.annotation.Autowired; import java.util.List; @@ -36,7 +35,7 @@ public class ProjectObjectDataListener implements ReadListener { private void saveData() { Boolean success = protectObjectService.newProtectObjects(cachedDataList); if (!success) { - throw new RuntimeException("Error reading data in newProtectObjects"); + throw new RuntimeException("Error reading data in /proobj/new"); } } } diff --git a/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectController.java b/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectController.java index 34ade31..4144d37 100644 --- a/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectController.java +++ b/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectController.java @@ -1,15 +1,18 @@ package com.realtime.protection.server.defense.object; import com.alibaba.excel.EasyExcel; -import com.fasterxml.jackson.annotation.JsonProperty; import com.realtime.protection.configuration.entity.defense.object.ProtectObject; import com.realtime.protection.configuration.response.ResponseResult; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; @RestController @@ -38,13 +41,25 @@ public class ProtectObjectController { .setData("success", true); } - @PutMapping("/new") - public ResponseResult newProtectObjectFromFile(MultipartFile updateFile) throws IOException { - EasyExcel.read(updateFile.getInputStream(), ProtectObject.class, + @PostMapping("/upload") + public ResponseResult uploadFile(MultipartFile uploadFile) throws IOException { + EasyExcel.read(uploadFile.getInputStream(), ProtectObject.class, new ProjectObjectDataListener(protectObjectService)).sheet().doRead(); return ResponseResult.ok(); } + @GetMapping("/download") + public void downloadTemplate(HttpServletResponse response) throws IOException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode("防护对象", StandardCharsets.UTF_8).replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + + EasyExcel.write(response.getOutputStream(), ProtectObject.class) + .sheet("防护对象") + .doWrite(List.of()); + } + @GetMapping("/query") public ResponseResult queryProtectObjects(@RequestParam(value = "proobj_name", required = false) String protectObjectName, @@ -88,7 +103,7 @@ public class ProtectObjectController { } @PostMapping("/delete") - public ResponseResult deleteProtectObject(@RequestBody @JsonProperty("proobj_ids") List protectObjectIds) { + public ResponseResult deleteProtectObject(@RequestBody List protectObjectIds) { return ResponseResult.ok() .setData("proobj_ids", protectObjectIds) .setData("success", protectObjectService.deleteProtectObjects(protectObjectIds)); diff --git a/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectMapper.java b/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectMapper.java index b735f98..76dc0d1 100644 --- a/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectMapper.java +++ b/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectMapper.java @@ -23,7 +23,7 @@ public interface ProtectObjectMapper { Boolean deleteProtectObject(@Param("proobj_id") Integer protectObjectId); - Boolean deleteProtectObjects(@Param("proobj_ids") List protectObjectIds); + void deleteProtectObjects(@Param("proobj_ids") List protectObjectIds); Boolean changeProtectObjectAuditStatus(@Param("proobj_id") Integer protectObjectId, @Param("proobj_audit_status") Integer protectObjectAuditStatus); diff --git a/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectService.java b/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectService.java index 1c82eeb..f671565 100644 --- a/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectService.java +++ b/src/main/java/com/realtime/protection/server/defense/object/ProtectObjectService.java @@ -4,6 +4,7 @@ import com.alibaba.excel.util.ListUtils; import com.realtime.protection.configuration.entity.defense.object.ProtectObject; import com.realtime.protection.configuration.utils.AuditStatusValidator; import com.realtime.protection.configuration.utils.SqlSessionWrapper; +import org.apache.ibatis.exceptions.PersistenceException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,16 +35,22 @@ public class ProtectObjectService { public Boolean newProtectObjects(List protectObjectList) { Function, Boolean>> newProtectObjectFunction = mapper -> list -> { + if (list == null || list.isEmpty()) { + return false; + } + List protectObjectBatch = ListUtils.newArrayListWithExpectedSize(100); for (ProtectObject protectObject : protectObjectList) { protectObjectBatch.add(protectObject); - if (protectObjectBatch.size() < 1000) { + if (protectObjectBatch.size() < 100) { continue; } mapper.newProtectObjects(protectObjectBatch); protectObjectBatch.clear(); } - mapper.newProtectObjects(protectObjectBatch); + if (!protectObjectBatch.isEmpty()) { + mapper.newProtectObjects(protectObjectBatch); + } return true; }; @@ -67,10 +74,12 @@ public class ProtectObjectService { } public Boolean deleteProtectObjects(List protectObjectIds) { - Function, Void>> deleteProtectObjectFunction = mapper -> list -> { + Function, Boolean>> deleteProtectObjectFunction = mapper -> list -> { if (list == null || list.isEmpty()) { - return null; + return false; } + boolean success = true; + Integer result; List protectObjectBatch = ListUtils.newArrayListWithExpectedSize(100); for (Integer protectObjectId : list) { @@ -78,15 +87,16 @@ public class ProtectObjectService { if (protectObjectBatch.size() < 100) { continue; } - mapper.deleteProtectObjects(protectObjectIds); + mapper.deleteProtectObjects(protectObjectBatch); protectObjectBatch.clear(); } - mapper.deleteProtectObjects(protectObjectBatch); - return null; + if (!protectObjectBatch.isEmpty()) { + mapper.deleteProtectObjects(protectObjectBatch);; + } + return success; }; - sqlSessionWrapper.startBatchSession(ProtectObjectMapper.class, deleteProtectObjectFunction, protectObjectIds); - return true; + return sqlSessionWrapper.startBatchSession(ProtectObjectMapper.class, deleteProtectObjectFunction, protectObjectIds); } @Transactional diff --git a/src/test/java/com/realtime/protection/server/defense/object/ProtectObjectServiceTest.java b/src/test/java/com/realtime/protection/server/defense/object/ProtectObjectServiceTest.java index ee2b37e..f02b323 100644 --- a/src/test/java/com/realtime/protection/server/defense/object/ProtectObjectServiceTest.java +++ b/src/test/java/com/realtime/protection/server/defense/object/ProtectObjectServiceTest.java @@ -24,12 +24,6 @@ class ProtectObjectServiceTest { this.protectObjectService = protectObjectService; } - @Test - void testDeleteProtectObject() { - Boolean success = protectObjectService.deleteProtectObjects(List.of(1, 2, 3, 4)); - assertFalse(success); - } - @BeforeEach void setUp() { protectObject = new ProtectObject(); @@ -56,7 +50,7 @@ class ProtectObjectServiceTest { @Test void newProtectObjects() { List protectObjects = new ArrayList<>(); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 1000; i++) { protectObjects.add(protectObject); } @@ -66,10 +60,12 @@ class ProtectObjectServiceTest { @Test void updateProtectObject() { + Integer testId = 300; + protectObject.setProtectObjectName("x-1-1"); - protectObject.setProtectObjectId(10); + protectObject.setProtectObjectId(testId); assertTrue(protectObjectService.updateProtectObject(protectObject)); - assertEquals("x-1-1", protectObjectService.queryProtectObject(10).getProtectObjectName()); + assertEquals("x-1-1", protectObjectService.queryProtectObject(testId).getProtectObjectName()); } @Test @@ -81,16 +77,26 @@ class ProtectObjectServiceTest { break; } } - assertTrue(protectObjectService.deleteProtectObject(testNum)); assertNull(protectObjectService.queryProtectObject(testNum)); } @Test void deleteProtectObjects() { - assertTrue(protectObjectService.deleteProtectObjects(List.of(270, 271))); - assertNull(protectObjectService.queryProtectObject(270)); - assertNull(protectObjectService.queryProtectObject(271)); + ArrayList testNums = new ArrayList<>(); + for (int i = 0; i < 100000; i++ ) { + if (protectObjectService.queryProtectObject(i) != null) { + testNums.add(i); + if (testNums.size() > 5) { + break; + } + } + } + + assertTrue(protectObjectService.deleteProtectObjects(testNums)); + for (Integer testNum : testNums) { + assertNull(protectObjectService.queryProtectObject(testNum)); + } } @Test