From 56ca6a4796b5843000a8c3d299b0d935ec1e8934 Mon Sep 17 00:00:00 2001
From: sim-wangyan <8966188@qq.com>
Date: Tue, 11 Apr 2023 17:51:26 +0800
Subject: [PATCH] init
---
.gitignore | 10 +
pom.xml | 149 ++++++++++
src/main/java/io/xream/sspoin/CellError.java | 27 ++
.../java/io/xream/sspoin/ErrorAppender.java | 49 ++++
src/main/java/io/xream/sspoin/Errors.java | 57 ++++
src/main/java/io/xream/sspoin/ErrorsRO.java | 126 +++++++++
.../java/io/xream/sspoin/ExcelReader.java | 256 ++++++++++++++++++
.../sspoin/NonRepeatableSavingFilter.java | 142 ++++++++++
src/main/java/io/xream/sspoin/Parsed.java | 196 ++++++++++++++
src/main/java/io/xream/sspoin/Result.java | 33 +++
src/main/java/io/xream/sspoin/RowError.java | 29 ++
.../java/io/xream/sspoin/SavedFinder.java | 18 ++
src/main/java/io/xream/sspoin/Template.java | 30 ++
src/main/java/io/xream/sspoin/Templated.java | 11 +
14 files changed, 1133 insertions(+)
create mode 100644 .gitignore
create mode 100644 pom.xml
create mode 100644 src/main/java/io/xream/sspoin/CellError.java
create mode 100644 src/main/java/io/xream/sspoin/ErrorAppender.java
create mode 100644 src/main/java/io/xream/sspoin/Errors.java
create mode 100644 src/main/java/io/xream/sspoin/ErrorsRO.java
create mode 100644 src/main/java/io/xream/sspoin/ExcelReader.java
create mode 100644 src/main/java/io/xream/sspoin/NonRepeatableSavingFilter.java
create mode 100644 src/main/java/io/xream/sspoin/Parsed.java
create mode 100644 src/main/java/io/xream/sspoin/Result.java
create mode 100644 src/main/java/io/xream/sspoin/RowError.java
create mode 100644 src/main/java/io/xream/sspoin/SavedFinder.java
create mode 100644 src/main/java/io/xream/sspoin/Template.java
create mode 100644 src/main/java/io/xream/sspoin/Templated.java
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eb5c88b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+target/
+*/target/
+*/classes/
+*.jar
+*.class
+*/application-test.properties
+*/application-prod.properties
+*.iml
+.idea/
+.settings/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..871d289
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,149 @@
+
+
+
+ io.xream.sspoin
+ 0.0.1
+ 4.0.0
+ sspoin
+
+
+ UTF-8
+ 1.8
+ 1.8
+ 1.8
+ true
+ 3.17
+ 3.12.0
+
+
+
+ scm:git:https://github.com/x-ream/sspoin
+ scm:git:https://github.com/x-ream/sspoin
+ scm:git:https://github.com/x-ream/sspoin
+ 0.0.1
+
+
+
+
+ Apache 2
+ http://www.apache.org/licenses/LICENSE-2.0
+ repo
+ A business-friendly OSS license
+
+
+
+
+
+ Sim Wang
+ 8966188@qq.com
+
+
+
+
+
+ oss-s
+ sqli snapshots repo
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ oss-r
+ sqli release repo
+ https://oss.sonatype.org/service/local/staging/deploy/maven2
+
+
+
+
+
+ org.apache.poi
+ poi
+ ${poi.version}
+
+
+ org.apache.poi
+ poi-ooxml
+ ${poi.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.7
+
+ false
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.1.1
+
+ UTF-8
+ UTF-8
+ UTF-8
+ -Xdoclint:none
+
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.0
+
+ true
+
+
+
+ source-jar
+ compile
+
+ jar
+
+
+
+
+
+
+
+
+ src/main/resources
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/xream/sspoin/CellError.java b/src/main/java/io/xream/sspoin/CellError.java
new file mode 100644
index 0000000..4aa6578
--- /dev/null
+++ b/src/main/java/io/xream/sspoin/CellError.java
@@ -0,0 +1,27 @@
+package io.xream.sspoin;
+
+/**
+ * @author Sim
+ */
+public class CellError {
+
+ private String meta;
+ private String error;
+
+ public String getMeta() {
+ return meta;
+ }
+
+ public void setMeta(String meta) {
+ this.meta = meta;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/io/xream/sspoin/ErrorAppender.java b/src/main/java/io/xream/sspoin/ErrorAppender.java
new file mode 100644
index 0000000..7866093
--- /dev/null
+++ b/src/main/java/io/xream/sspoin/ErrorAppender.java
@@ -0,0 +1,49 @@
+package io.xream.sspoin;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Sim
+ */
+public interface ErrorAppender {
+
+ static void append(Errors errors, List list) {
+
+ Set rowNumSet = new HashSet();
+
+ for (Object t : list) {
+ Templated obj = (Templated) t;
+ final List cellErrorList = obj.getRowError().getCellErrors();
+ if (!cellErrorList.isEmpty()) {
+ int rowNum = obj.getRowNum();
+ RowError rowErrorExist = null;
+ for (RowError rowError : errors.getRowErrors()){
+ if (rowNum == rowError.getRowNum()){
+ rowErrorExist = rowError;
+ break;
+ }
+ }
+ if (rowErrorExist == null) {
+ rowErrorExist = new RowError();
+ rowErrorExist.setRowNum(rowNum);
+ errors.getRowErrors().add(rowErrorExist);
+ }
+ rowErrorExist.getCellErrors().addAll(cellErrorList);
+
+ rowNumSet.add(obj.getRowNum());
+ }
+ }
+
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ Templated obj = iterator.next();
+ Integer v = obj.getRowNum();
+ if (rowNumSet.contains(v)) {
+ iterator.remove();
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/xream/sspoin/Errors.java b/src/main/java/io/xream/sspoin/Errors.java
new file mode 100644
index 0000000..1a6c109
--- /dev/null
+++ b/src/main/java/io/xream/sspoin/Errors.java
@@ -0,0 +1,57 @@
+package io.xream.sspoin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Sim
+ */
+public class Errors {
+
+ private String fileName;
+ private int rowOffset;
+ private List metas = new ArrayList<>();
+ private List rowErrors;
+
+ private Errors(Parsed parsed,String fileName) {
+ this.fileName = fileName;
+ this.rowOffset = parsed.getMetaRow();
+ this.rowErrors = new ArrayList<>();
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public int getRowOffset() {
+ return rowOffset;
+ }
+
+ public void setRowOffset(int rowOffset) {
+ this.rowOffset = rowOffset;
+ }
+
+ public List getMetas() {
+ return metas;
+ }
+
+ public List getRowErrors() {
+ return rowErrors;
+ }
+
+ public void setRowErrors(List rowErrors) {
+ this.rowErrors = rowErrors;
+ }
+
+ public static Errors of(Parsed parsed, String fileName) {
+ if (parsed == null){
+ throw new IllegalArgumentException("parsed before, then init errors");
+ }
+ return new Errors(parsed,fileName);
+ }
+
+}
diff --git a/src/main/java/io/xream/sspoin/ErrorsRO.java b/src/main/java/io/xream/sspoin/ErrorsRO.java
new file mode 100644
index 0000000..3302273
--- /dev/null
+++ b/src/main/java/io/xream/sspoin/ErrorsRO.java
@@ -0,0 +1,126 @@
+package io.xream.sspoin;
+
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.xssf.streaming.SXSSFRow;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author Sim
+ */
+public class ErrorsRO {
+
+ private String fileName;
+ private int rowOffset;
+ private List metas;
+ private List rowErrors;
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public int getRowOffset() {
+ return rowOffset;
+ }
+
+ public void setRowOffset(int rowOffset) {
+ this.rowOffset = rowOffset;
+ }
+
+ public List getMetas() {
+ return metas;
+ }
+
+ public void setMetas(List metas) {
+ this.metas = metas;
+ }
+
+ public List getRowErrors() {
+ return rowErrors;
+ }
+
+ public void setRowErrors(List rowErrors) {
+ this.rowErrors = rowErrors;
+ }
+
+
+ public byte[] toBuffer() throws IOException {
+ if (rowErrors.isEmpty())
+ throw new IllegalArgumentException("Missing Errors");
+ if (metas.isEmpty())
+ throw new IllegalArgumentException("Missing Metas");
+
+ final String fileNamePrex = "ERROR_DATA";
+
+ List headerList = new ArrayList<>();
+ headerList.add("Error_num");
+ headerList.addAll(metas);
+
+ ByteArrayOutputStream os = null;
+ SXSSFWorkbook wb = new SXSSFWorkbook();
+ try {
+ createExcel(wb, fileNamePrex, headerList.toArray(), rowErrors, rowOffset);
+ os = new ByteArrayOutputStream();
+ wb.write(os);
+ return os.toByteArray();
+ } finally {
+ if (wb != null) {
+ wb.close();
+ }
+ if (os != null) {
+ os.close();
+ }
+ }
+ }
+
+
+ private void createExcel(SXSSFWorkbook workbook, String sheetName, Object[] headers, List rowErrors, int rowOffset) {
+
+ SXSSFSheet sheet = workbook.createSheet(sheetName);
+
+ int i = 0;
+ SXSSFRow row = sheet.createRow(i++);
+ CellStyle style = workbook.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+
+ for (int j = 0; j < headers.length; j++) {
+ Cell cell = row.createCell(j);
+ cell.setCellValue((String) headers[j]);
+ cell.setCellStyle(style);
+ }
+
+ rowErrors.sort(Comparator.comparing(RowError::getRowNum));
+
+ for (RowError rowError : rowErrors) {
+ row = sheet.createRow(i++);
+ int j = 0;
+ row.createCell(j++).setCellValue(rowError.getRowNum() + rowOffset);
+
+ for (; j < headers.length; j++) {
+ String meta = (String) headers[j];
+ Cell cell = row.createCell(j);
+ for (CellError error : rowError.getCellErrors()) {
+ if (meta.equals(error.getMeta())) {
+ cell.setCellValue(error.getError());
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/src/main/java/io/xream/sspoin/ExcelReader.java b/src/main/java/io/xream/sspoin/ExcelReader.java
new file mode 100644
index 0000000..0c8f0c4
--- /dev/null
+++ b/src/main/java/io/xream/sspoin/ExcelReader.java
@@ -0,0 +1,256 @@
+package io.xream.sspoin;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.*;
+
+/**
+ * @author Sim
+ */
+public class ExcelReader {
+
+ public static Result read(
+ Errors errors,
+ Parsed parsed,
+ String filename, InputStream stream) throws Exception {
+
+ if (parsed == null) {
+ throw new IllegalArgumentException("parsed can not null");
+ }
+
+ if (errors == null) {
+ throw new IllegalArgumentException("errors can not null, init errors after parsed");
+ }
+
+ List list = read0(errors,parsed, filename, stream);
+
+ repeated(parsed, list);
+
+ ErrorAppender.append(errors, list);
+
+ List nonRepeatedProps = parseNonRepeateableProps(parsed);
+
+ return new Result(list, nonRepeatedProps);
+
+ }
+
+
+ private static List parseNonRepeateableProps(Parsed parsed) {
+ List list = new ArrayList();
+ for (Map.Entry entry : parsed.getNonRepeatableMap().entrySet()) {
+ Field field = entry.getKey();
+ Boolean nonRepeated = entry.getValue();
+ if (nonRepeated) {
+ list.add(field.getName());
+ }
+ }
+ return list;
+ }
+
+ private static void repeated(Parsed parsed, List list) {
+
+ Map map = parsed.getNonRepeatableMap();
+
+ for (Map.Entry entry : map.entrySet()) {
+ Field field = entry.getKey();
+ Boolean nonRepeated = entry.getValue();
+ if (nonRepeated) {
+ Set set = new HashSet<>();
+ for (Object t : list) {
+ Templated obj = (Templated) t;
+ try {
+ Object o = field.get(obj);
+ String v = String.valueOf(o);
+ if (!set.add(v)) {
+ String meta = parsed.getMetaMap().get(field);
+ CellError error = new CellError();
+ error.setMeta(meta);
+ error.setError(v + "," + parsed.getRepeatedError());
+ obj.getRowError().getCellErrors().add(error);
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ }
+
+
+ private static List read0(Errors errors, Parsed parsed, String filename, InputStream stream) throws Exception {
+
+ List list = new ArrayList<>();
+
+ Workbook workbook = null;
+ try {
+ boolean isXls = filename.toLowerCase().endsWith(".xls");
+ if (isXls) {
+ workbook = new HSSFWorkbook(stream);
+ } else if (filename.endsWith(".xlsx")) {
+ workbook = new XSSFWorkbook(stream);
+ }
+
+ Sheet sheet = StringUtils.isBlank(parsed.getSheetName()) ? workbook.getSheetAt(0) : workbook.getSheet(parsed.getSheetName());
+
+ int i = 0;
+ Map metaMap = new HashMap<>();
+ Map requiredMap = new HashMap<>();
+ Row row = sheet.getRow(parsed.getMetaRow());
+ if (row == null) {
+ throw new IllegalArgumentException("META not found");
+ }
+ Iterator cellIte = row.cellIterator();
+ while (cellIte.hasNext()) {
+ Cell cell = cellIte.next();
+ String value = cell.getStringCellValue();
+ if (StringUtils.isBlank(value))
+ continue;
+ String str = value.trim();
+ String meta = null;
+ if (str.contains(parsed.getRequiredTag())) {
+ str = str.replace(parsed.getRequiredTag(), "---");
+ if (str.startsWith("---"))
+ throw new IllegalArgumentException(value +", "+parsed.getRequiredTag() + " cat not be as prefix, put it as suffix");
+ String[] arr = str.split("---");
+ meta = arr[0].trim();
+ requiredMap.put(i, true);
+ } else {
+ meta = str;
+ requiredMap.put(i, false);
+ }
+ metaMap.put(i, meta);
+ errors.getMetas().add(meta);
+ i++;
+ }
+
+ int cLen = metaMap.size();
+ int lastRow = sheet.getLastRowNum();
+ for (int startRow = parsed.getStartRow(); startRow <= lastRow; startRow++) {
+ row = sheet.getRow(startRow);
+ // read to map
+ Map dataMap = new HashMap<>();
+ for (int j = 0; j < cLen; j++) {
+ Cell cell = row.getCell(j);
+ if (cell == null) {
+ dataMap.put(j, null);
+ } else {
+ CellType type = cell.getCellTypeEnum();
+ switch (type) {
+ case STRING:
+ dataMap.put(j, cell.getStringCellValue().trim());
+ break;
+ case NUMERIC:
+ dataMap.put(j, cell.getNumericCellValue());
+ break;
+ case BOOLEAN:
+ dataMap.put(j, cell.getBooleanCellValue());
+ break;
+ case BLANK:
+ dataMap.put(j, null);
+ break;
+ }
+ }
+ }
+
+ Object notBlankObj = dataMap.get(parsed.getRowIgnoreIfBlankAt());
+ if (notBlankObj == null
+ || (notBlankObj instanceof String && StringUtils.isBlank(String.valueOf(notBlankObj))))
+ continue;
+
+ Templated obj = parsed.getClzz().newInstance();
+ list.add((T) obj);
+ obj.setRowNum(startRow);
+
+ // map to templated object
+ for (Map.Entry entry : dataMap.entrySet()) {
+
+ Integer j = entry.getKey();
+
+ String meta = metaMap.get(j);
+
+ Field field = parsed.getFieldByMeta(meta);
+
+ if (sheet == null) {
+ throw new IllegalArgumentException("sheet meta not same as annotation: " + meta);
+ }
+
+ Object value = entry.getValue();
+
+ final boolean isRequired = requiredMap.get(j);
+
+ if (isRequired &&
+ (value == null || StringUtils.isBlank(value + ""))
+ ) { //BLANK
+ CellError error = new CellError();
+ error.setMeta(meta);
+ error.setError(meta + parsed.getBlankError());
+ obj.getRowError().getCellErrors().add(error);
+ } else {
+ String str = String.valueOf(value);
+ if (field.getType() == String.class) {
+ field.set(obj, str);
+ } else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
+ int bn = Integer.valueOf(str);
+ field.set(obj, bn == 0 ? false : true);
+ } else if (field.getType() == Date.class) {
+ try {
+ Date date = parsed.getDateFormat().parse(str);
+ field.set(obj, date);
+ } catch (Exception e) {
+ if (isRequired) {
+ CellError error = new CellError();
+ error.setMeta(meta);
+ error.setError(str + " ?|(" + parsed.getDateFormat().toPattern() + ")");
+ obj.getRowError().getCellErrors().add(error);
+ }
+ }
+ } else {
+ BigDecimal bg = new BigDecimal(str);
+ if (bg.compareTo(BigDecimal.ZERO) == 0 && isRequired) {
+ CellError error = new CellError();
+ error.setMeta(meta);
+ error.setError(meta + parsed.getZeroError());
+ obj.getRowError().getCellErrors().add(error);
+ } else {
+ if (field.getType() == Long.class || field.getType() == long.class) {
+ field.set(obj, bg.longValue());
+ } else if (field.getType() == Integer.class || field.getType() == int.class) {
+ field.set(obj, bg.intValue());
+ } else if (field.getType() == Double.class || field.getType() == double.class) {
+ field.set(obj, bg.doubleValue());
+ } else if (field.getType() == BigDecimal.class) {
+ field.set(obj, bg);
+ } else {
+ throw new IllegalStateException("not supported field type: " + field.getName() + "," + field.getType());
+ }
+ }
+ }
+ }
+
+ i++;
+ }
+
+ }
+ } finally {
+ if (workbook != null) {
+ try {
+ workbook.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return list;
+ }
+
+
+}
diff --git a/src/main/java/io/xream/sspoin/NonRepeatableSavingFilter.java b/src/main/java/io/xream/sspoin/NonRepeatableSavingFilter.java
new file mode 100644
index 0000000..c55bf66
--- /dev/null
+++ b/src/main/java/io/xream/sspoin/NonRepeatableSavingFilter.java
@@ -0,0 +1,142 @@
+package io.xream.sspoin;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * @author Sim
+ */
+public class NonRepeatableSavingFilter {
+
+
+ public static void filter(
+ Errors errors,Parsed parsed, Result result,
+ Class poClzz,
+ SavedFinder.NonRepeatableSavedCond nonRepeatableSavedCond,
+ SavedFinder savedFinder) {
+
+ if (errors == null) {
+ throw new IllegalArgumentException("errors can not null");
+ }
+
+ if (nonRepeatableSavedCond == null) {
+ throw new IllegalArgumentException("nonRepeatableSavedCond can not null");
+ }
+
+ if (savedFinder == null) {
+ throw new IllegalArgumentException("savedFinder can not null");
+ }
+
+ Set poPropSet = poFieldNames(poClzz);
+
+ Object cond = nonRepeatableSavedCond.build(
+ buildSelectList(poPropSet,result),
+ buildInConditions(poPropSet,result)
+ );
+
+ List |