feat(controller): 添加历史法院公告批量导入功能并优化Excel导入支持
- 新增批量导入历史法院公告接口,支持"历史法院公告"和"历史法庭公告"选项卡 - 实现数据库唯一索引约束防止重复数据导入 - 优化专利导入逻辑,优先读取"专利"选项卡并兼容多sheet格式 - 增强Excel导入头部匹配功能,支持括号标注的表头识别 - 添加全角半角括号统一处理和表头规范化映射 - 实现带括号后缀表头的智能匹配和剥离功能 - 新增专利导入相关单元测试验证括号表头处理
This commit is contained in:
@@ -309,6 +309,137 @@ public class CreditCourtAnnouncementController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入历史法院公告(仅解析“历史法院公告”选项卡;兼容“历史法庭公告”)
|
||||||
|
* 规则:使用数据库唯一索引约束,重复数据不导入。
|
||||||
|
*/
|
||||||
|
@PreAuthorize("hasAuthority('credit:creditCourtAnnouncement:save')")
|
||||||
|
@Operation(summary = "批量导入历史法院公告司法大数据")
|
||||||
|
@PostMapping("/import/history")
|
||||||
|
public ApiResult<List<String>> importHistoryBatch(@RequestParam("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "companyId", required = false) Integer companyId) {
|
||||||
|
List<String> errorMessages = new ArrayList<>();
|
||||||
|
int successCount = 0;
|
||||||
|
Set<Integer> touchedCompanyIds = new HashSet<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史法院公告");
|
||||||
|
if (sheetIndex < 0) {
|
||||||
|
// 兼容旧命名
|
||||||
|
sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史法庭公告");
|
||||||
|
}
|
||||||
|
if (sheetIndex < 0) {
|
||||||
|
return fail("未读取到数据,请确认文件中存在“历史法院公告”选项卡且表头与示例格式一致", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExcelImportSupport.ImportResult<CreditCourtAnnouncementImportParam> importResult = ExcelImportSupport.read(
|
||||||
|
file, CreditCourtAnnouncementImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||||
|
List<CreditCourtAnnouncementImportParam> list = importResult.getData();
|
||||||
|
int usedTitleRows = importResult.getTitleRows();
|
||||||
|
int usedHeadRows = importResult.getHeadRows();
|
||||||
|
int usedSheetIndex = importResult.getSheetIndex();
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(list)) {
|
||||||
|
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
User loginUser = getLoginUser();
|
||||||
|
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
|
||||||
|
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
|
||||||
|
Map<String, String> urlByCaseNumber = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
|
||||||
|
|
||||||
|
final int chunkSize = 500;
|
||||||
|
final int mpBatchSize = 500;
|
||||||
|
List<CreditCourtAnnouncement> chunkItems = new ArrayList<>(chunkSize);
|
||||||
|
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
CreditCourtAnnouncementImportParam param = list.get(i);
|
||||||
|
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||||
|
try {
|
||||||
|
CreditCourtAnnouncement item = convertImportParamToEntity(param);
|
||||||
|
if (item.getCaseNumber() != null) {
|
||||||
|
item.setCaseNumber(item.getCaseNumber().trim());
|
||||||
|
}
|
||||||
|
if (ImportHelper.isBlank(item.getCaseNumber())) {
|
||||||
|
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String link = urlByCaseNumber.get(item.getCaseNumber());
|
||||||
|
if (!ImportHelper.isBlank(link)) {
|
||||||
|
item.setUrl(link.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getCompanyId() == null && companyId != null) {
|
||||||
|
item.setCompanyId(companyId);
|
||||||
|
}
|
||||||
|
if (item.getUserId() == null && currentUserId != null) {
|
||||||
|
item.setUserId(currentUserId);
|
||||||
|
}
|
||||||
|
if (item.getTenantId() == null && currentTenantId != null) {
|
||||||
|
item.setTenantId(currentTenantId);
|
||||||
|
}
|
||||||
|
if (item.getStatus() == null) {
|
||||||
|
item.setStatus(0);
|
||||||
|
}
|
||||||
|
if (item.getDeleted() == null) {
|
||||||
|
item.setDeleted(0);
|
||||||
|
}
|
||||||
|
// 历史导入的数据统一标记为“失效”
|
||||||
|
item.setDataStatus("失效");
|
||||||
|
if (item.getRecommend() == null) {
|
||||||
|
item.setRecommend(0);
|
||||||
|
}
|
||||||
|
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
|
||||||
|
touchedCompanyIds.add(item.getCompanyId());
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkItems.add(item);
|
||||||
|
chunkRowNumbers.add(excelRowNumber);
|
||||||
|
if (chunkItems.size() >= chunkSize) {
|
||||||
|
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||||
|
creditCourtAnnouncementService,
|
||||||
|
chunkItems,
|
||||||
|
chunkRowNumbers,
|
||||||
|
mpBatchSize,
|
||||||
|
CreditCourtAnnouncement::getCaseNumber,
|
||||||
|
"",
|
||||||
|
errorMessages
|
||||||
|
);
|
||||||
|
chunkItems.clear();
|
||||||
|
chunkRowNumbers.clear();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chunkItems.isEmpty()) {
|
||||||
|
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||||
|
creditCourtAnnouncementService,
|
||||||
|
chunkItems,
|
||||||
|
chunkRowNumbers,
|
||||||
|
mpBatchSize,
|
||||||
|
CreditCourtAnnouncement::getCaseNumber,
|
||||||
|
"",
|
||||||
|
errorMessages
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.COURT_ANNOUNCEMENT, touchedCompanyIds);
|
||||||
|
|
||||||
|
if (errorMessages.isEmpty()) {
|
||||||
|
return success("成功导入" + successCount + "条数据", null);
|
||||||
|
}
|
||||||
|
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return fail("导入失败:" + e.getMessage(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载法院公告司法大数据导入模板
|
* 下载法院公告司法大数据导入模板
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -195,8 +195,13 @@ public class CreditPatentController extends BaseController {
|
|||||||
Set<Integer> touchedCompanyIds = new HashSet<>();
|
Set<Integer> touchedCompanyIds = new HashSet<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ExcelImportSupport.ImportResult<CreditPatentImportParam> importResult = ExcelImportSupport.readAnySheet(
|
// 单企业表通常是多 sheet,专利页签名一般为“专利”
|
||||||
file, CreditPatentImportParam.class, this::isEmptyImportRow);
|
int preferredSheetIndex = ExcelImportSupport.findSheetIndex(file, "专利", 0);
|
||||||
|
ExcelImportSupport.ImportResult<CreditPatentImportParam> importResult = ExcelImportSupport.read(
|
||||||
|
file, CreditPatentImportParam.class, this::isEmptyImportRow, preferredSheetIndex);
|
||||||
|
if (CollectionUtils.isEmpty(importResult.getData())) {
|
||||||
|
importResult = ExcelImportSupport.readAnySheet(file, CreditPatentImportParam.class, this::isEmptyImportRow);
|
||||||
|
}
|
||||||
List<CreditPatentImportParam> list = importResult.getData();
|
List<CreditPatentImportParam> list = importResult.getData();
|
||||||
int usedTitleRows = importResult.getTitleRows();
|
int usedTitleRows = importResult.getTitleRows();
|
||||||
int usedHeadRows = importResult.getHeadRows();
|
int usedHeadRows = importResult.getHeadRows();
|
||||||
@@ -345,7 +350,16 @@ public class CreditPatentController extends BaseController {
|
|||||||
if (isImportHeaderRow(param)) {
|
if (isImportHeaderRow(param)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return ImportHelper.isBlank(param.getPublicNo());
|
return ImportHelper.isBlank(param.getName())
|
||||||
|
&& ImportHelper.isBlank(param.getType())
|
||||||
|
&& ImportHelper.isBlank(param.getStatusText())
|
||||||
|
&& ImportHelper.isBlank(param.getRegisterNo())
|
||||||
|
&& ImportHelper.isBlank(param.getRegisterDate())
|
||||||
|
&& ImportHelper.isBlank(param.getPublicNo())
|
||||||
|
&& ImportHelper.isBlank(param.getPublicDate())
|
||||||
|
&& ImportHelper.isBlank(param.getInventor())
|
||||||
|
&& ImportHelper.isBlank(param.getPatentApplicant())
|
||||||
|
&& ImportHelper.isBlank(param.getComments());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isImportHeaderRow(CreditPatentImportParam param) {
|
private boolean isImportHeaderRow(CreditPatentImportParam param) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.gxwebsoft.credit.controller;
|
|||||||
|
|
||||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||||
import cn.afterturn.easypoi.excel.ExcelImportUtil;
|
import cn.afterturn.easypoi.excel.ExcelImportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.annotation.Excel;
|
||||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||||
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
@@ -18,6 +19,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -277,7 +279,7 @@ public class ExcelImportSupport {
|
|||||||
if (workbook.getNumberOfSheets() > sheetIndex) {
|
if (workbook.getNumberOfSheets() > sheetIndex) {
|
||||||
Sheet sheet = workbook.getSheetAt(sheetIndex);
|
Sheet sheet = workbook.getSheetAt(sheetIndex);
|
||||||
if (sheet != null) {
|
if (sheet != null) {
|
||||||
normalizeHeaderCells(sheet, titleRows, headRows);
|
normalizeHeaderCells(sheet, titleRows, headRows, clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
||||||
@@ -289,10 +291,14 @@ public class ExcelImportSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void normalizeHeaderCells(Sheet sheet, int titleRows, int headRows) {
|
private static void normalizeHeaderCells(Sheet sheet, int titleRows, int headRows, Class<?> clazz) {
|
||||||
if (sheet == null || headRows <= 0) {
|
if (sheet == null || headRows <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Map<String, String> expectedHeadersByKey = buildExpectedHeaderKeyMap(clazz);
|
||||||
|
if (expectedHeadersByKey.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int headerStart = Math.max(titleRows, 0);
|
int headerStart = Math.max(titleRows, 0);
|
||||||
int headerEnd = headerStart + headRows - 1;
|
int headerEnd = headerStart + headRows - 1;
|
||||||
for (int r = headerStart; r <= headerEnd; r++) {
|
for (int r = headerStart; r <= headerEnd; r++) {
|
||||||
@@ -317,21 +323,85 @@ public class ExcelImportSupport {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String normalized = normalizeHeaderText(text);
|
String canonical = findCanonicalHeader(text, expectedHeadersByKey);
|
||||||
if (normalized != null && !normalized.equals(text)) {
|
if (canonical != null && !canonical.equals(text)) {
|
||||||
cell.setCellValue(normalized);
|
cell.setCellValue(canonical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String normalizeHeaderText(String text) {
|
private static Map<String, String> buildExpectedHeaderKeyMap(Class<?> clazz) {
|
||||||
if (text == null) {
|
if (clazz == null) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
Class<?> current = clazz;
|
||||||
|
while (current != null && current != Object.class) {
|
||||||
|
Field[] fields = current.getDeclaredFields();
|
||||||
|
for (Field field : fields) {
|
||||||
|
Excel excel = field.getAnnotation(Excel.class);
|
||||||
|
if (excel == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = excel.name();
|
||||||
|
if (name == null || name.trim().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String key = normalizeHeaderKey(name);
|
||||||
|
if (!key.isEmpty()) {
|
||||||
|
// key -> canonical annotation name
|
||||||
|
map.putIfAbsent(key, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current.getSuperclass();
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String findCanonicalHeader(String rawHeaderText, Map<String, String> expectedHeadersByKey) {
|
||||||
|
if (rawHeaderText == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Remove common invisible whitespace characters, including full-width space.
|
String key = normalizeHeaderKey(rawHeaderText);
|
||||||
|
if (key.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String canonical = expectedHeadersByKey.get(key);
|
||||||
|
if (canonical != null) {
|
||||||
|
return canonical;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some upstream templates append explanations in brackets, e.g. "原告/上诉人(申请执行人)".
|
||||||
|
// Only strip trailing bracket groups when the full header doesn't match any known expected header.
|
||||||
|
String strippedKey = stripTrailingBracketSuffix(key);
|
||||||
|
if (!strippedKey.equals(key)) {
|
||||||
|
canonical = expectedHeadersByKey.get(strippedKey);
|
||||||
|
if (canonical != null) {
|
||||||
|
return canonical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize header text for matching purposes only.
|
||||||
|
*
|
||||||
|
* <p>Do NOT drop bracket content (e.g. keep "(元)" or "(公告)" in the middle), because many templates use them as
|
||||||
|
* part of the canonical header name. We only remove whitespace and unify common full-width punctuation.</p>
|
||||||
|
*/
|
||||||
|
private static String normalizeHeaderKey(String text) {
|
||||||
|
if (text == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
String normalized = text
|
String normalized = text
|
||||||
|
// unify common full-width punctuation
|
||||||
.replace("/", "/")
|
.replace("/", "/")
|
||||||
|
.replace("【", "[")
|
||||||
|
.replace("】", "]")
|
||||||
|
// remove common invisible whitespace characters, including full-width space.
|
||||||
.replace(" ", "")
|
.replace(" ", "")
|
||||||
.replace("\t", "")
|
.replace("\t", "")
|
||||||
.replace("\r", "")
|
.replace("\r", "")
|
||||||
@@ -339,10 +409,34 @@ public class ExcelImportSupport {
|
|||||||
.replace("\u00A0", "")
|
.replace("\u00A0", "")
|
||||||
.replace(" ", "")
|
.replace(" ", "")
|
||||||
.trim();
|
.trim();
|
||||||
// Some upstream templates append explanations in brackets, e.g. "原告/上诉人(申请执行人)".
|
|
||||||
// Strip bracketed suffixes so Easypoi can match the canonical header name.
|
// Make ( ) and ( ) comparable by normalizing both to ASCII.
|
||||||
normalized = normalized.replaceAll("[\\((【\\[].*?[\\))】\\]]", "");
|
normalized = normalized.replace('(', '(').replace(')', ')');
|
||||||
return normalized.trim();
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String stripTrailingBracketSuffix(String text) {
|
||||||
|
if (text == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String s = text.trim();
|
||||||
|
while (true) {
|
||||||
|
if (s.endsWith(")")) {
|
||||||
|
int idx = s.lastIndexOf('(');
|
||||||
|
if (idx >= 0) {
|
||||||
|
s = s.substring(0, idx).trim();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.endsWith("]")) {
|
||||||
|
int idx = s.lastIndexOf('[');
|
||||||
|
if (idx >= 0) {
|
||||||
|
s = s.substring(0, idx).trim();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> List<T> filterEmptyRows(List<T> rawList, Predicate<T> emptyRowPredicate) {
|
private static <T> List<T> filterEmptyRows(List<T> rawList, Predicate<T> emptyRowPredicate) {
|
||||||
@@ -557,6 +651,10 @@ public class ExcelImportSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int findColumnIndexByHeader(Sheet sheet, int titleRows, int headRows, String headerName) {
|
private static int findColumnIndexByHeader(Sheet sheet, int titleRows, int headRows, String headerName) {
|
||||||
|
String targetKey = normalizeHeaderKey(headerName);
|
||||||
|
if (targetKey.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
int firstHeaderRow = Math.max(0, titleRows);
|
int firstHeaderRow = Math.max(0, titleRows);
|
||||||
int lastHeaderRow = Math.max(0, titleRows + headRows - 1);
|
int lastHeaderRow = Math.max(0, titleRows + headRows - 1);
|
||||||
for (int r = firstHeaderRow; r <= lastHeaderRow; r++) {
|
for (int r = firstHeaderRow; r <= lastHeaderRow; r++) {
|
||||||
@@ -569,17 +667,10 @@ public class ExcelImportSupport {
|
|||||||
if (cell == null) {
|
if (cell == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (cell.getCellType() == CellType.STRING) {
|
DataFormatter formatter = new DataFormatter();
|
||||||
String value = cell.getStringCellValue();
|
String value = formatter.formatCellValue(cell);
|
||||||
if (headerName.equals(value != null ? value.trim() : null)) {
|
if (targetKey.equals(normalizeHeaderKey(value))) {
|
||||||
return c;
|
return c;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DataFormatter formatter = new DataFormatter();
|
|
||||||
String value = formatter.formatCellValue(cell);
|
|
||||||
if (headerName.equals(value != null ? value.trim() : null)) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package com.gxwebsoft.credit.controller;
|
||||||
|
|
||||||
|
import com.gxwebsoft.credit.param.CreditPatentImportParam;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
class ExcelImportSupportPatentImportTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void import_should_map_parentheses_headers() throws Exception {
|
||||||
|
MultipartFile file = buildPatentWorkbookFile("公开(公告)号", "申请(专利权)人");
|
||||||
|
|
||||||
|
ExcelImportSupport.ImportResult<CreditPatentImportParam> result = ExcelImportSupport.readAnySheet(
|
||||||
|
file,
|
||||||
|
CreditPatentImportParam.class,
|
||||||
|
p -> p == null || (ImportHelper.isBlank(p.getRegisterNo()) && ImportHelper.isBlank(p.getName()))
|
||||||
|
);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1, result.getData().size());
|
||||||
|
CreditPatentImportParam row = result.getData().get(0);
|
||||||
|
assertEquals("CN2024XXXXXXXX.X", row.getRegisterNo());
|
||||||
|
assertEquals("CN1XXXXXXXXX", row.getPublicNo());
|
||||||
|
assertEquals("示例科技有限公司", row.getPatentApplicant());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void import_should_handle_fullwidth_parentheses_headers() throws Exception {
|
||||||
|
MultipartFile file = buildPatentWorkbookFile("公开(公告)号", "申请(专利权)人");
|
||||||
|
|
||||||
|
ExcelImportSupport.ImportResult<CreditPatentImportParam> result = ExcelImportSupport.readAnySheet(
|
||||||
|
file,
|
||||||
|
CreditPatentImportParam.class,
|
||||||
|
p -> p == null || (ImportHelper.isBlank(p.getRegisterNo()) && ImportHelper.isBlank(p.getName()))
|
||||||
|
);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1, result.getData().size());
|
||||||
|
CreditPatentImportParam row = result.getData().get(0);
|
||||||
|
assertEquals("CN2024XXXXXXXX.X", row.getRegisterNo());
|
||||||
|
assertEquals("CN1XXXXXXXXX", row.getPublicNo());
|
||||||
|
assertEquals("示例科技有限公司", row.getPatentApplicant());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MultipartFile buildPatentWorkbookFile(String publicNoHeader, String applicantHeader) throws Exception {
|
||||||
|
try (Workbook workbook = new XSSFWorkbook()) {
|
||||||
|
Sheet sheet = workbook.createSheet("专利");
|
||||||
|
Row header = sheet.createRow(0);
|
||||||
|
header.createCell(0).setCellValue("发明名称");
|
||||||
|
header.createCell(1).setCellValue("专利类型");
|
||||||
|
header.createCell(2).setCellValue("法律状态");
|
||||||
|
header.createCell(3).setCellValue("申请号");
|
||||||
|
header.createCell(4).setCellValue("申请日");
|
||||||
|
header.createCell(5).setCellValue(publicNoHeader);
|
||||||
|
header.createCell(6).setCellValue("公开(公告)日期");
|
||||||
|
header.createCell(7).setCellValue("发明人");
|
||||||
|
header.createCell(8).setCellValue(applicantHeader);
|
||||||
|
header.createCell(9).setCellValue("备注");
|
||||||
|
|
||||||
|
Row row = sheet.createRow(1);
|
||||||
|
row.createCell(0).setCellValue("一种示例装置及方法");
|
||||||
|
row.createCell(1).setCellValue("发明专利");
|
||||||
|
row.createCell(2).setCellValue("有效");
|
||||||
|
row.createCell(3).setCellValue("CN2024XXXXXXXX.X");
|
||||||
|
row.createCell(4).setCellValue("2024-01-01");
|
||||||
|
row.createCell(5).setCellValue("CN1XXXXXXXXX");
|
||||||
|
row.createCell(6).setCellValue("2024-06-01");
|
||||||
|
row.createCell(7).setCellValue("张三;李四");
|
||||||
|
row.createCell(8).setCellValue("示例科技有限公司");
|
||||||
|
row.createCell(9).setCellValue("备注信息");
|
||||||
|
|
||||||
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
||||||
|
workbook.write(bos);
|
||||||
|
return new MockMultipartFile(
|
||||||
|
"file",
|
||||||
|
"patent.xlsx",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
bos.toByteArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user