Added ExcelMapper
This commit is contained in:
@@ -31,3 +31,4 @@ build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
/target/
|
||||
|
||||
Generated
+2
-1
@@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
@@ -73,7 +74,7 @@
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="homebrew-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.4</version>
|
||||
<version>3.5.7</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.example</groupId>
|
||||
@@ -27,7 +28,7 @@
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -54,12 +55,12 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.2.5</version>
|
||||
<version>5.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.5</version>
|
||||
<version>5.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.example.parser;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
public class FlowableExcelMapper {
|
||||
|
||||
protected static ObjectMapper objectMapper = new ObjectMapper();
|
||||
protected static FlowableExcelParser flowableExcelParser = new FlowableExcelParser();
|
||||
|
||||
public ArrayNode excelToJsonNode(String excelPath) {
|
||||
ArrayList<LinkedHashMap<String, Object>> rowList = flowableExcelParser.parseExcel(excelPath);
|
||||
ArrayNode arrayNode = objectMapper.createArrayNode();
|
||||
for (LinkedHashMap<String, Object> row : rowList) {
|
||||
JsonNode jsonNode = null;
|
||||
Set<Map.Entry<String, Object>> entries = row.entrySet();
|
||||
for (Map.Entry<String, Object> entry : entries) {
|
||||
jsonNode = addNode(jsonNode, entry.getKey(), entry.getValue());
|
||||
}
|
||||
arrayNode.add(jsonNode);
|
||||
}
|
||||
return arrayNode;
|
||||
}
|
||||
|
||||
public JsonNode addNode(JsonNode parent, String path, Object value) {
|
||||
objectMapper = new ObjectMapper();
|
||||
|
||||
if (parent == null) {
|
||||
parent = objectMapper.createObjectNode();
|
||||
}
|
||||
|
||||
int delimiterPosition = indexOfFirstDelimiter(path, ".*");
|
||||
if (delimiterPosition <= 0) {
|
||||
if (parent instanceof ObjectNode) {
|
||||
// Key of a value in an ObjectNode
|
||||
((ObjectNode) parent).set(path, objectMapper.valueToTree(value));
|
||||
} else {
|
||||
// Index of a value in an ArrayNode
|
||||
int index = Integer.parseInt(path);
|
||||
for (int i = 0; parent.size() <= index; i++) {
|
||||
((ArrayNode) parent).add(objectMapper.createObjectNode());
|
||||
}
|
||||
((ArrayNode) parent).set(index, objectMapper.valueToTree(value));
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
String key = path.substring(0, delimiterPosition);
|
||||
String newPath = path.substring(delimiterPosition + 1);
|
||||
String delimiter = path.substring(delimiterPosition, delimiterPosition + 1);
|
||||
JsonNode child = null;
|
||||
if (delimiter.equals(".")) {
|
||||
child = objectMapper.createObjectNode();
|
||||
} else if (delimiter.equals("*")) {
|
||||
child = objectMapper.createArrayNode();
|
||||
}
|
||||
|
||||
JsonNode node;
|
||||
if (parent instanceof ObjectNode) {
|
||||
// Key of a JsonNode in an ObjectNode
|
||||
node = parent.get(key);
|
||||
if (node != null) {
|
||||
// Take the existing ObjectNode as child
|
||||
child = node;
|
||||
}
|
||||
((ObjectNode) parent).set(key, addNode(child, newPath, value));
|
||||
} else {
|
||||
// Index of a JsonNode in an ArrayNode
|
||||
int index = Integer.parseInt(key);
|
||||
node = parent.get(index);
|
||||
if (node != null) {
|
||||
// Take the existing ArrayNode as child
|
||||
child = node;
|
||||
}
|
||||
// Create empty entries to parent ArrayNode
|
||||
for (int i = 0; parent.size() <= index; i++) {
|
||||
((ArrayNode) parent).add(objectMapper.createObjectNode());
|
||||
}
|
||||
((ArrayNode) parent).set(index, addNode(child, newPath, value));
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
public static int indexOfFirstDelimiter(String str, String delimiters) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
for (char c : delimiters.toCharArray()) {
|
||||
if (str.charAt(i) == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class FlowableExcelParser {
|
||||
public ArrayList<LinkedHashMap<String, Object>> parseExcel(String resourcePath, List<Integer> colNumberList) {
|
||||
|
||||
public ArrayList<LinkedHashMap<String, Object>> parseExcel(String resourcePath) {
|
||||
ArrayList<LinkedHashMap<String, Object>> rowList = new ArrayList<>();
|
||||
try (FileInputStream fileInputStream = new FileInputStream(resourcePath)) {
|
||||
Workbook workbook = new XSSFWorkbook(fileInputStream);
|
||||
@@ -22,25 +22,36 @@ public class FlowableExcelParser {
|
||||
for (Row row : sheet) {
|
||||
if (row.getRowNum() == 0) {
|
||||
// Header row
|
||||
for (Integer colNumber : colNumberList) {
|
||||
colHeaders.add(row.getCell(colNumber).getStringCellValue());
|
||||
for (int colNum = 0; colNum < row.getLastCellNum(); colNum++) {
|
||||
Cell cell = row.getCell(colNum);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK || cell.getCellType() == CellType._NONE) {
|
||||
// Take all columns until the first empty header cell
|
||||
break;
|
||||
} else {
|
||||
colHeaders.add(cell.getStringCellValue());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
boolean allCellsNull = true;
|
||||
LinkedHashMap<String, Object> rowMap = new LinkedHashMap<>();
|
||||
for (int i = 0; i < colNumberList.size(); i++) {
|
||||
Integer colNumber = colNumberList.get(i);
|
||||
for (int colNum = 0; colNum < colHeaders.size(); colNum++) {
|
||||
Object content = null;
|
||||
Cell cell = row.getCell(colNumber);
|
||||
Cell cell = row.getCell(colNum);
|
||||
CellValue cellValue = workbook.getCreationHelper().createFormulaEvaluator().evaluate(cell);
|
||||
if (cellValue != null) {
|
||||
if (cellValue != null && cell.getCellType() != CellType.BLANK && cell.getCellType() != CellType._NONE) {
|
||||
switch (cellValue.getCellType()) {
|
||||
case STRING : content = cellValue.getStringValue(); break;
|
||||
case BOOLEAN : content = cellValue.getBooleanValue(); break;
|
||||
case NUMERIC : content = cellValue.getNumberValue(); break;
|
||||
}
|
||||
allCellsNull = false;
|
||||
}
|
||||
rowMap.put(colHeaders.get(i), content);
|
||||
rowMap.put(colHeaders.get(colNum), content);
|
||||
}
|
||||
if (allCellsNull) {
|
||||
// Take all rows until the first empty row
|
||||
return rowList;
|
||||
}
|
||||
rowList.add(rowMap);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SpringBootApplication
|
||||
@@ -32,6 +31,6 @@ public class ParserApp {
|
||||
ClassLoader classLoader = ParserApp.class.getClassLoader();
|
||||
URL resourceUrl = classLoader.getResource("flowableExcelParserExampleData.xlsx");
|
||||
assert resourceUrl != null;
|
||||
logger.info("parsed excel={}", flowableExcelParser.parseExcel(resourceUrl.getPath(), List.of(0,1,2,4,5,6)));
|
||||
logger.info("parsed excel={}", flowableExcelParser.parseExcel(resourceUrl.getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.example.parser;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@SpringBootTest
|
||||
class FlowableExcelMapperTest {
|
||||
|
||||
@Autowired
|
||||
private FlowableExcelMapper flowableExcelMapper;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ParserApp.class);
|
||||
|
||||
|
||||
@Test
|
||||
public void addNodeTest() {
|
||||
JsonNode node = null;
|
||||
node = flowableExcelMapper.addNode(node, "3*0*2", "String1");
|
||||
node = flowableExcelMapper.addNode(node, "3*0*3", "String1");
|
||||
node = flowableExcelMapper.addNode(node, "3*1.1", 234);
|
||||
node = flowableExcelMapper.addNode(node, "3*1.2", 234);
|
||||
node = flowableExcelMapper.addNode(node, "3*2", false);
|
||||
node = flowableExcelMapper.addNode(node, "4.5", "String1");
|
||||
node = flowableExcelMapper.addNode(node, "4.6", 234);
|
||||
node = flowableExcelMapper.addNode(node, "4.7", false);
|
||||
logger.info("node2={}{}", System.lineSeparator(), node.toPrettyString());
|
||||
}
|
||||
|
||||
protected String getResourcePath(String path) {
|
||||
ClassLoader classLoader = FlowableExcelMapperTest.class.getClassLoader();
|
||||
URL resourceUrl = classLoader.getResource(path);
|
||||
Assertions.assertThat(resourceUrl).isNotNull();
|
||||
return resourceUrl.getPath();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excelToJsonNodeTest() {
|
||||
JsonNode node = flowableExcelMapper.excelToJsonNode(getResourcePath("flowableExcelMapperTestData1.xlsx"));
|
||||
logger.info("node2={}{}", System.lineSeparator(), node.toPrettyString());
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,12 @@ class FlowableExcelParserTest {
|
||||
@Autowired
|
||||
private FlowableExcelParser flowableExcelParser;
|
||||
|
||||
private Stream<Arguments> GetArgumentsFromExcel(String path, List<Integer> colNumberList) {
|
||||
private Stream<Arguments> GetArgumentsFromExcel(String path) {
|
||||
ArrayList<Arguments> argumentList = new ArrayList<>();
|
||||
ClassLoader classLoader = FlowableExcelParserTest.class.getClassLoader();
|
||||
URL resourceUrl = classLoader.getResource(path);
|
||||
Assertions.assertThat(resourceUrl).isNotNull();
|
||||
ArrayList<LinkedHashMap<String, Object>> rowList = flowableExcelParser.parseExcel(resourceUrl.getPath(), colNumberList);
|
||||
ArrayList<LinkedHashMap<String, Object>> rowList = flowableExcelParser.parseExcel(resourceUrl.getPath());
|
||||
Assertions.assertThat(rowList).isNotNull();
|
||||
for (LinkedHashMap<String, Object> row : rowList) {
|
||||
LinkedHashMap<String, Object> inputMap = new LinkedHashMap<>();
|
||||
@@ -46,7 +46,7 @@ class FlowableExcelParserTest {
|
||||
|
||||
@NotNull
|
||||
private Stream<Arguments> booleanExcelParserTestDataProvider() {
|
||||
return GetArgumentsFromExcel("flowableExcelParserTestData1.xlsx", List.of(0,1,2,4,5));
|
||||
return GetArgumentsFromExcel("flowableExcelParserTestData1.xlsx");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -67,7 +67,7 @@ class FlowableExcelParserTest {
|
||||
|
||||
@NotNull
|
||||
private Stream<Arguments> stringExcelParserTestDataProvider() {
|
||||
return GetArgumentsFromExcel("flowableExcelParserTestData2.xlsx", List.of(0,1,2,4,5,6));
|
||||
return GetArgumentsFromExcel("flowableExcelParserTestData2.xlsx");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -92,7 +92,7 @@ class FlowableExcelParserTest {
|
||||
|
||||
@NotNull
|
||||
private Stream<Arguments> numberExcelParserTestDataProvider() {
|
||||
return GetArgumentsFromExcel("flowableExcelParserTestData3.xlsx", List.of(0,1,2,4,5,6));
|
||||
return GetArgumentsFromExcel("flowableExcelParserTestData3.xlsx");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user