Commit 767330ab93432aeb8e4f3d073ea0adb6e63d3cee

Authored by zhangmeiyang
1 parent f9cf2428

feat(adopt): 增强客户同步功能并支持Excel文件处理

- 为 fullySyncCustomer 接口增加路径参数以支持多租户管道配置
- 添加对 Excel 文件(xls 和 xlsx)的解析与处理逻辑
- 引入 Apache POI 依赖用于读取电子表格数据
- 新增 ExcelUtils 工具类实现表格数据转换为 Map 列表
- 在 ReceiveMessageCO 中将 systemType 类型从枚举改为字符串
- 更新 controller 和 service 方法签名以传递更多上下文信息
- 添加文件格式校验及空文件名校验防止非法输入
- 优化代码结构并增强异常处理机制确保服务稳定性
@@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
34 <mybatis-plus.version>3.5.14</mybatis-plus.version> 34 <mybatis-plus.version>3.5.14</mybatis-plus.version>
35 <!-- 工具类库 --> 35 <!-- 工具类库 -->
36 <lombok.version>1.18.42</lombok.version> 36 <lombok.version>1.18.42</lombok.version>
  37 + <poi.version>5.5.0</poi.version>
37 </properties> 38 </properties>
38 39
39 <dependencyManagement> 40 <dependencyManagement>
@@ -69,6 +70,16 @@ @@ -69,6 +70,16 @@
69 <artifactId>mysql-connector-j</artifactId> 70 <artifactId>mysql-connector-j</artifactId>
70 <version>${mysql-connector.version}</version> 71 <version>${mysql-connector.version}</version>
71 </dependency> 72 </dependency>
  73 + <dependency>
  74 + <groupId>org.apache.poi</groupId>
  75 + <artifactId>poi</artifactId>
  76 + <version>${poi.version}</version>
  77 + </dependency>
  78 + <dependency>
  79 + <groupId>org.apache.poi</groupId>
  80 + <artifactId>poi-ooxml</artifactId>
  81 + <version>${poi.version}</version>
  82 + </dependency>
72 </dependencies> 83 </dependencies>
73 </dependencyManagement> 84 </dependencyManagement>
74 85
tax-adopt/pom.xml
@@ -8,14 +8,23 @@ @@ -8,14 +8,23 @@
8 <artifactId>tax-agent</artifactId> 8 <artifactId>tax-agent</artifactId>
9 <version>${revision}</version> 9 <version>${revision}</version>
10 </parent> 10 </parent>
  11 + <artifactId>tax-adopt</artifactId>
  12 +
11 <dependencies> 13 <dependencies>
12 <dependency> 14 <dependency>
13 <groupId>com.diligrp</groupId> 15 <groupId>com.diligrp</groupId>
14 <artifactId>tax-central</artifactId> 16 <artifactId>tax-central</artifactId>
15 <version>${revision}</version> 17 <version>${revision}</version>
16 </dependency> 18 </dependency>
  19 + <dependency>
  20 + <groupId>org.apache.poi</groupId>
  21 + <artifactId>poi</artifactId>
  22 + </dependency>
  23 + <dependency>
  24 + <groupId>org.apache.poi</groupId>
  25 + <artifactId>poi-ooxml</artifactId>
  26 + </dependency>
17 </dependencies> 27 </dependencies>
18 28
19 - <artifactId>tax-adopt</artifactId>  
20 29
21 -</project>  
22 \ No newline at end of file 30 \ No newline at end of file
  31 +</project>
tax-adopt/src/main/java/com/diligrp/tax/adopt/api/AdoptMessageController.java
@@ -3,6 +3,7 @@ package com.diligrp.tax.adopt.api; @@ -3,6 +3,7 @@ package com.diligrp.tax.adopt.api;
3 import com.diligrp.tax.adopt.model.ReceiveMessageCO; 3 import com.diligrp.tax.adopt.model.ReceiveMessageCO;
4 import com.diligrp.tax.adopt.service.AdoptMessageService; 4 import com.diligrp.tax.adopt.service.AdoptMessageService;
5 import com.diligrp.tax.central.message.Message; 5 import com.diligrp.tax.central.message.Message;
  6 +import jakarta.validation.constraints.NotNull;
6 import lombok.AllArgsConstructor; 7 import lombok.AllArgsConstructor;
7 import org.springframework.web.bind.annotation.*; 8 import org.springframework.web.bind.annotation.*;
8 import org.springframework.web.multipart.MultipartFile; 9 import org.springframework.web.multipart.MultipartFile;
@@ -18,15 +19,31 @@ public class AdoptMessageController { @@ -18,15 +19,31 @@ public class AdoptMessageController {
18 private final AdoptMessageService adoptMessageService; 19 private final AdoptMessageService adoptMessageService;
19 20
20 21
  22 + /**
  23 + * 接收消息
  24 + *
  25 + * @param receiveMessageCO 接收消息
  26 + * @return {@link Message }<{@link ? }>
  27 + */
21 @PostMapping("/message") 28 @PostMapping("/message")
22 public Message<?> receiveMessage(@RequestBody ReceiveMessageCO receiveMessageCO) { 29 public Message<?> receiveMessage(@RequestBody ReceiveMessageCO receiveMessageCO) {
23 adoptMessageService.convertMessage(receiveMessageCO); 30 adoptMessageService.convertMessage(receiveMessageCO);
24 return Message.success(); 31 return Message.success();
25 } 32 }
26 33
27 - @PostMapping("/fullySyncCustomer")  
28 - public Message<?> fullySyncCustomer(@RequestPart("file")MultipartFile file) {  
29 - adoptMessageService.fullySyncCustomer(file); 34 + /**
  35 + * 完全同步客户
  36 + *
  37 + * @param file 文件
  38 + * @return {@link Message }<{@link ? }>
  39 + */
  40 + @PostMapping("/fullySyncCustomer/{group}/{entity}/{pipelineCode}/{documentType}")
  41 + public Message<?> fullySyncCustomer(@RequestPart("file") @NotNull MultipartFile file,
  42 + @PathVariable("group") String group,
  43 + @PathVariable("entity") String entity,
  44 + @PathVariable("pipelineCode") String pipelineCode,
  45 + @PathVariable("documentType") String documentType) {
  46 + adoptMessageService.fullySyncCustomer(file, group, entity, pipelineCode, documentType);
30 return Message.success(); 47 return Message.success();
31 } 48 }
32 } 49 }
tax-adopt/src/main/java/com/diligrp/tax/adopt/model/ReceiveMessageCO.java
@@ -42,5 +42,8 @@ public class ReceiveMessageCO { @@ -42,5 +42,8 @@ public class ReceiveMessageCO {
42 */ 42 */
43 private Map<String, Object> msgBody; 43 private Map<String, Object> msgBody;
44 44
45 - private SystemType systemType; 45 + /**
  46 + * 系统类型
  47 + */
  48 + private String systemType;
46 } 49 }
tax-adopt/src/main/java/com/diligrp/tax/adopt/service/AdoptMessageService.java
1 package com.diligrp.tax.adopt.service; 1 package com.diligrp.tax.adopt.service;
2 2
3 import com.diligrp.tax.adopt.model.ReceiveMessageCO; 3 import com.diligrp.tax.adopt.model.ReceiveMessageCO;
  4 +import jakarta.validation.constraints.NotNull;
4 import org.springframework.web.multipart.MultipartFile; 5 import org.springframework.web.multipart.MultipartFile;
5 6
6 /** 7 /**
@@ -9,6 +10,8 @@ import org.springframework.web.multipart.MultipartFile; @@ -9,6 +10,8 @@ import org.springframework.web.multipart.MultipartFile;
9 public interface AdoptMessageService { 10 public interface AdoptMessageService {
10 11
11 /** 12 /**
  13 + * 转换消息
  14 + *
12 * @param receiveMessageCO 接收消息 15 * @param receiveMessageCO 接收消息
13 */ 16 */
14 void convertMessage(ReceiveMessageCO receiveMessageCO); 17 void convertMessage(ReceiveMessageCO receiveMessageCO);
@@ -16,7 +19,11 @@ public interface AdoptMessageService { @@ -16,7 +19,11 @@ public interface AdoptMessageService {
16 /** 19 /**
17 * 完全同步客户 20 * 完全同步客户
18 * 21 *
19 - * @param file 22 + * @param file 文件
  23 + * @param group 群
  24 + * @param entity 实体
  25 + * @param pipelineCode 管道代码
  26 + * @param documentType
20 */ 27 */
21 - void fullySyncCustomer(MultipartFile file); 28 + void fullySyncCustomer(@NotNull MultipartFile file, String group, String entity, String pipelineCode, String documentType);
22 } 29 }
tax-adopt/src/main/java/com/diligrp/tax/adopt/service/impl/AdoptMessageServiceImpl.java
@@ -2,19 +2,25 @@ package com.diligrp.tax.adopt.service.impl; @@ -2,19 +2,25 @@ package com.diligrp.tax.adopt.service.impl;
2 2
3 import com.diligrp.tax.adopt.model.ReceiveMessageCO; 3 import com.diligrp.tax.adopt.model.ReceiveMessageCO;
4 import com.diligrp.tax.adopt.service.AdoptMessageService; 4 import com.diligrp.tax.adopt.service.AdoptMessageService;
  5 +import com.diligrp.tax.adopt.util.ExcelUtils;
5 import com.diligrp.tax.central.exception.TaxAgentServiceException; 6 import com.diligrp.tax.central.exception.TaxAgentServiceException;
6 import com.diligrp.tax.central.model.PipelineBusinessKeyword; 7 import com.diligrp.tax.central.model.PipelineBusinessKeyword;
7 import com.diligrp.tax.central.model.TenantPipeline; 8 import com.diligrp.tax.central.model.TenantPipeline;
8 import com.diligrp.tax.central.service.ITaxPipelineBusinessKeywordService; 9 import com.diligrp.tax.central.service.ITaxPipelineBusinessKeywordService;
9 import com.diligrp.tax.central.service.ITaxTenantService; 10 import com.diligrp.tax.central.service.ITaxTenantService;
  11 +import com.diligrp.tax.central.type.TaxSystemType;
10 import com.diligrp.tax.central.utils.AdoptUtils; 12 import com.diligrp.tax.central.utils.AdoptUtils;
11 import com.diligrp.tax.central.utils.JsonUtils; 13 import com.diligrp.tax.central.utils.JsonUtils;
12 import lombok.AllArgsConstructor; 14 import lombok.AllArgsConstructor;
  15 +import org.apache.commons.io.FilenameUtils;
  16 +import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  17 +import org.apache.poi.xssf.usermodel.XSSFWorkbook;
13 import org.springframework.amqp.rabbit.core.RabbitTemplate; 18 import org.springframework.amqp.rabbit.core.RabbitTemplate;
14 import org.springframework.stereotype.Service; 19 import org.springframework.stereotype.Service;
15 import org.springframework.util.CollectionUtils; 20 import org.springframework.util.CollectionUtils;
16 import org.springframework.web.multipart.MultipartFile; 21 import org.springframework.web.multipart.MultipartFile;
17 22
  23 +import java.io.IOException;
18 import java.util.List; 24 import java.util.List;
19 import java.util.Map; 25 import java.util.Map;
20 import java.util.Optional; 26 import java.util.Optional;
@@ -46,14 +52,38 @@ public class AdoptMessageServiceImpl implements AdoptMessageService { @@ -46,14 +52,38 @@ public class AdoptMessageServiceImpl implements AdoptMessageService {
46 Map<String, Object> map = AdoptUtils.handleAdopt(pipelineBusinessKeywords, json); 52 Map<String, Object> map = AdoptUtils.handleAdopt(pipelineBusinessKeywords, json);
47 receiveMessageCO.setMsgBody(map); 53 receiveMessageCO.setMsgBody(map);
48 Optional<TenantPipeline> byTenantAndPipelineCode = taxTenantService.findByTenantAndPipelineCode(receiveMessageCO.getGroup(), receiveMessageCO.getEntity(), receiveMessageCO.getPipelineCode()); 54 Optional<TenantPipeline> byTenantAndPipelineCode = taxTenantService.findByTenantAndPipelineCode(receiveMessageCO.getGroup(), receiveMessageCO.getEntity(), receiveMessageCO.getPipelineCode());
49 - byTenantAndPipelineCode.ifPresent(tenantPipeline -> receiveMessageCO.setSystemType(tenantPipeline.getSystemType())); 55 + byTenantAndPipelineCode.ifPresent(tenantPipeline -> receiveMessageCO.setSystemType(tenantPipeline.getSystemType().code));
50 // 发送mq 56 // 发送mq
51 String messageJson = JsonUtils.toJsonString(receiveMessageCO); 57 String messageJson = JsonUtils.toJsonString(receiveMessageCO);
52 rabbitTemplate.convertAndSend(NORMAL_EXCHANGE, NORMAL_ROUTING, messageJson); 58 rabbitTemplate.convertAndSend(NORMAL_EXCHANGE, NORMAL_ROUTING, messageJson);
53 } 59 }
54 60
55 @Override 61 @Override
56 - public void fullySyncCustomer(MultipartFile file) {  
57 - 62 + public void fullySyncCustomer(MultipartFile file, String group, String entity, String pipelineCode, String documentType) {
  63 + try (var inputStream = file.getInputStream()) {
  64 + Optional.ofNullable(file.getOriginalFilename()).orElseThrow(() -> new TaxAgentServiceException(TaxSystemType.MISSING_BUSINESS_INFORMATION, "未找到文件"));
  65 + String originalFilename = file.getOriginalFilename();
  66 + String extension = FilenameUtils.getExtension(originalFilename).toLowerCase();
  67 + var book = switch (extension) {
  68 + case "xlsx" -> new XSSFWorkbook(inputStream);
  69 + case "xls" -> new HSSFWorkbook(inputStream);
  70 + default -> throw new TaxAgentServiceException(TaxSystemType.BUSINESS_MATCHES_ARE_INCORRECT, "未支持的文件格式");
  71 + };
  72 + List<Map<String, Object>> list = ExcelUtils.processSheet(book);
  73 + Optional<TenantPipeline> pipelineOptional = taxTenantService.findByTenantAndPipelineCode(group, entity, pipelineCode);
  74 + TenantPipeline pipeline = pipelineOptional.orElseThrow(() -> new TaxAgentServiceException(TaxSystemType.NO_MATCHING_SET_OF_ACCOUNTS_FOUND, "未找到匹配账套"));
  75 + list.forEach(map -> {
  76 + ReceiveMessageCO receiveMessageCO = new ReceiveMessageCO();
  77 + receiveMessageCO.setMsgBody(map);
  78 + receiveMessageCO.setGroup(group);
  79 + receiveMessageCO.setEntity(entity);
  80 + receiveMessageCO.setPipelineCode(pipelineCode);
  81 + receiveMessageCO.setSystemType(pipeline.getSystemType().code);
  82 + receiveMessageCO.setDocumentType(documentType);
  83 + rabbitTemplate.convertAndSend(NORMAL_EXCHANGE, NORMAL_ROUTING, JsonUtils.toJsonString(receiveMessageCO));
  84 + });
  85 + } catch (IOException e) {
  86 + throw new TaxAgentServiceException(e.getMessage());
  87 + }
58 } 88 }
59 } 89 }
tax-adopt/src/main/java/com/diligrp/tax/adopt/util/ExcelUtils.java 0 → 100644
  1 +package com.diligrp.tax.adopt.util;
  2 +
  3 +import com.diligrp.tax.central.exception.TaxAgentServiceException;
  4 +import com.diligrp.tax.central.type.TaxSystemType;
  5 +import org.apache.poi.ss.usermodel.Workbook;
  6 +
  7 +import java.util.*;
  8 +
  9 +/**
  10 + * @Author: zhangmeiyang
  11 + * @CreateTime: 2025-11-19 15:11
  12 + * @Version: todo
  13 + */
  14 +public class ExcelUtils {
  15 + public static List<Map<String, Object>> processSheet(Workbook book) {
  16 + var res = new ArrayList<Map<String, Object>>();
  17 + Optional.ofNullable(book).orElseThrow(() -> new TaxAgentServiceException(TaxSystemType.ABNORMAL_PARAMETERS, "文件转换异常"));
  18 + book.sheetIterator().forEachRemaining(sheet -> sheet.rowIterator().forEachRemaining(row -> {
  19 + var map = new HashMap<String, Object>();
  20 + row.cellIterator().forEachRemaining(cell -> map.put(cell.getStringCellValue(), cell.getStringCellValue()));
  21 + res.add(map);
  22 + }));
  23 + return res;
  24 + }
  25 +}