Browse Source

init code: 初始化项目

zoujie 4 years ago
commit
8b3232e8ab

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
+logs

+ 53 - 0
pom.xml

@@ -0,0 +1,53 @@
+<?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"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>pub.vie</groupId>
+    <artifactId>excel</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.26</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.7.5</version>
+        </dependency>
+
+        <!--excel操作-->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>RELEASE</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>RELEASE</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>

+ 25 - 0
src/main/java/pub/vie/excel/common/annotation/ExcelEntity.java

@@ -0,0 +1,25 @@
+package pub.vie.excel.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @Descrption :
+ * @Author: zoujie
+ * @Date: 2020-4-15
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelEntity {
+
+    String classPathSource() default "";
+
+    int sheetAt() default 0;
+
+    int skip() default 0;
+
+    int limitRow() default -1;
+
+}

+ 21 - 0
src/main/java/pub/vie/excel/common/annotation/ExcelField.java

@@ -0,0 +1,21 @@
+package pub.vie.excel.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @Descrption :
+ * @Author: zoujie
+ * @Date: 2020-4-15
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelField {
+
+    int colIndex();
+
+    String dataFormat() default "yyyy-MM-dd";
+
+}

+ 35 - 0
src/main/java/pub/vie/excel/common/constant/ExcelCellIndex.java

@@ -0,0 +1,35 @@
+package pub.vie.excel.common.constant;
+
+/**
+ * @Descrption :
+ * @Author: zoujie
+ * @Date: 2020-4-15
+ */
+public interface ExcelCellIndex {
+    short CELL_INDEX_A = 0;
+    short CELL_INDEX_B = 1;
+    short CELL_INDEX_C = 2;
+    short CELL_INDEX_D = 3;
+    short CELL_INDEX_E = 4;
+    short CELL_INDEX_F = 5;
+    short CELL_INDEX_G = 6;
+    short CELL_INDEX_H = 7;
+    short CELL_INDEX_I = 8;
+    short CELL_INDEX_J = 9;
+    short CELL_INDEX_K = 10;
+    short CELL_INDEX_L = 11;
+    short CELL_INDEX_M = 12;
+    short CELL_INDEX_N = 13;
+    short CELL_INDEX_O = 14;
+    short CELL_INDEX_P = 15;
+    short CELL_INDEX_Q = 16;
+    short CELL_INDEX_R = 17;
+    short CELL_INDEX_S = 18;
+    short CELL_INDEX_T = 19;
+    short CELL_INDEX_U = 20;
+    short CELL_INDEX_V = 21;
+    short CELL_INDEX_W = 22;
+    short CELL_INDEX_X = 23;
+    short CELL_INDEX_Y = 24;
+    short CELL_INDEX_Z = 25;
+}

+ 45 - 0
src/main/java/pub/vie/excel/common/utils/CommonUtils.java

@@ -0,0 +1,45 @@
+package pub.vie.excel.common.utils;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * @Descrption :
+ * @Author: zoujie
+ * @Date: 2020-4-14
+ */
+public class CommonUtils {
+
+    public static void close(Closeable... closeables){
+        if(closeables != null &&  closeables.length > 0){
+            for (Closeable closeable : closeables) {
+                try {
+                    if(closeable != null) {
+                        closeable.close();
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static boolean isBlank(CharSequence cs){
+        int strLen;
+        if (cs != null && (strLen = cs.length()) != 0) {
+            for(int i = 0; i < strLen; ++i) {
+                if (!Character.isWhitespace(cs.charAt(i))) {
+                    return false;
+                }
+            }
+
+            return true;
+        } else {
+            return true;
+        }
+    }
+
+    public static boolean arrayEmpty(Object[] objects) {
+        return objects == null || objects.length < 1;
+    }
+}

+ 44 - 0
src/main/java/pub/vie/excel/example/Example.java

@@ -0,0 +1,44 @@
+package pub.vie.excel.example;
+
+import pub.vie.excel.example.entity.studentInfo;
+import pub.vie.excel.example.entity.studentInfo2;
+import pub.vie.excel.read.ExcelReader;
+
+import java.util.List;
+
+
+/**
+ * @Descrption :
+ * @Author: zoujie
+ * @Date: 2020-4-15
+ */
+public class Example {
+
+    public static final String virtualPath = "students.xlsx";
+
+
+    public static void main(String[] args) {
+        Example example = new Example();
+        example.testReadWithAnnotation();
+    }
+
+
+    public void testRead() {
+        ExcelReader<studentInfo> reader = new ExcelReader<>();
+        List<studentInfo> read = reader.read(ExcelReader.getStreamOnClassPath(virtualPath),1, studentInfo.class);
+
+        if (read != null) {
+            System.out.println(read.size());
+        }
+    }
+
+    public void testReadWithAnnotation() {
+        ExcelReader<studentInfo2> reader = new ExcelReader<>();
+        List<studentInfo2> read = reader.read(studentInfo2.class);
+
+        if (read != null) {
+            System.out.println(read.size());
+        }
+    }
+
+}

+ 15 - 0
src/main/java/pub/vie/excel/example/entity/studentInfo.java

@@ -0,0 +1,15 @@
+package pub.vie.excel.example.entity;
+
+import java.util.Date;
+
+public class studentInfo {
+
+        private String id;
+
+        private String name;
+
+        private int age;
+
+        private Date entranceDate;
+
+    }

+ 24 - 0
src/main/java/pub/vie/excel/example/entity/studentInfo2.java

@@ -0,0 +1,24 @@
+package pub.vie.excel.example.entity;
+
+import pub.vie.excel.common.annotation.ExcelEntity;
+import pub.vie.excel.common.annotation.ExcelField;
+import pub.vie.excel.common.constant.ExcelCellIndex;
+
+import java.util.Date;
+
+@ExcelEntity(classPathSource = "students.xlsx", sheetAt = 0, skip = 1, limitRow = -1)
+public class studentInfo2 {
+
+    @ExcelField(colIndex = ExcelCellIndex.CELL_INDEX_A)
+    private String id;
+
+    @ExcelField(colIndex = ExcelCellIndex.CELL_INDEX_B)
+    private String name;
+
+//    @ExcelField(colIndex = ExcelCellIndex.CELL_INDEX_C)
+//    private int age;
+
+    @ExcelField(colIndex = ExcelCellIndex.CELL_INDEX_D)
+    private Date entranceDate;
+
+}

+ 390 - 0
src/main/java/pub/vie/excel/read/ExcelReader.java

@@ -0,0 +1,390 @@
+package pub.vie.excel.read;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pub.vie.excel.common.annotation.ExcelEntity;
+import pub.vie.excel.common.annotation.ExcelField;
+import pub.vie.excel.common.utils.CommonUtils;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+import static pub.vie.excel.common.utils.CommonUtils.arrayEmpty;
+import static pub.vie.excel.common.utils.CommonUtils.isBlank;
+
+/**
+ * @Descrption :
+ * @Author: zoujie
+ * @Date: 2020-4-13
+ */
+public class ExcelReader<T> {
+
+    private static Logger log = LoggerFactory.getLogger(ExcelReader.class);
+
+    private static final String DEFAULT_DATE_FORMATE = "yyyy-MM-dd";
+
+    public static InputStream getStreamOnClassPath(String virtualPath) {
+        return ExcelReader.class.getClassLoader().getResourceAsStream(virtualPath);
+    }
+
+    public static String getRealPathOnClassPath(String virtualPath) {
+        URL resource = getClassLoader().getResource(virtualPath);
+        if (resource == null) {
+            return null;
+        }
+        String realPath;
+        try {
+            realPath = URLDecoder.decode(resource.getPath(), StandardCharsets.UTF_8.toString());
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+            return null;
+        }
+        return realPath;
+    }
+
+    public List<T> read(InputStream inputStream, Class<T> dataClass) {
+        return read(inputStream, 0, 0, -1, dataClass);
+    }
+
+    public List<T> read(InputStream inputStream,int skip, Class<T> dataClass) {
+        return read(inputStream, 0, skip, -1, dataClass);
+    }
+
+    public List<T> read(InputStream inputStream, int sheetAt, int skip, int limitRow, Class<T> dataClass) {
+        return baseRead(dataClass,inputStream,sheetAt,skip,limitRow,false);
+    }
+
+    public List<T> read(Class<T> dataClass) {
+        ExcelReadProperties excelReadProperties = excelReadProperties(dataClass);
+        if (excelReadProperties == null) {
+            throw new IllegalArgumentException(dataClass.getName() + "不含有ExcelEntity注解信息,无法解析excel");
+        }
+
+        String classPathSource = excelReadProperties.classPathSource;
+        if (isBlank(classPathSource)) {
+            throw new IllegalArgumentException(dataClass.getName() + "该方法ExcelEntity注解配置的classPathSource不能为空");
+        }
+
+        int sheetAt = excelReadProperties.sheetAt;
+        int skip = excelReadProperties.skip;
+        int limitRow = excelReadProperties.limitRow;
+
+        InputStream inputStream = getStreamOnClassPath(classPathSource);
+
+        return baseRead(dataClass, inputStream, sheetAt, skip, limitRow,true);
+    }
+
+    public List<T> read(Class<T> dataClass, InputStream inputStream) {
+        ExcelReadProperties excelReadProperties = excelReadProperties(dataClass);
+        if (excelReadProperties == null) {
+            throw new IllegalArgumentException(dataClass.getName() + "不含有ExcelEntity注解信息,无法解析excel");
+        }
+
+        int sheetAt = excelReadProperties.sheetAt;
+        int skip = excelReadProperties.skip;
+        int limitRow = excelReadProperties.limitRow;
+        return baseRead(dataClass, inputStream, sheetAt, skip, limitRow,true);
+    }
+
+    private List<T> baseRead(Class<T> dataClass, InputStream inputStream, int sheetAt, int skip, int limitRow, boolean useAnnotation) {
+        Workbook workbook = null;
+        List<T> resList = null;
+        if (inputStream == null) {
+            log.error("excel inputStream 为 null");
+            return null;
+        }
+        BufferedInputStream bufferedInputStream = convertInputStream(inputStream);
+
+        try {
+            workbook = WorkbookFactory.create(bufferedInputStream);
+            Sheet sheet = workbook.getSheetAt(sheetAt);
+            if (sheet == null) {
+                log.info("获取工作簿sheetAt[{}]为空");
+                return null;
+            }
+
+            int lastRowNum = sheet.getLastRowNum();
+            if (skip > lastRowNum) {
+                log.warn("sheet 总条数[{}] 跳过[{}]条不合法直接返回", lastRowNum, skip);
+                return null;
+            }
+
+            resList = new ArrayList<>();
+
+            if (skip < 0) {
+                skip = 0;
+            }
+
+            //最大条数
+            int end;
+            if (limitRow <= 0 || skip + limitRow > lastRowNum) {
+                end = lastRowNum;
+            } else {
+                end = skip + limitRow - 1;
+            }
+
+            for (int i = skip; i <= end; i++) {
+                Row row = sheet.getRow(i);
+                if (row == null) {
+                    break;
+                }
+
+                if (useAnnotation) {
+                    resList.add(handleRow(dataClass, row));
+                } else {
+                    resList.add(handleRow(row, dataClass));
+                }
+
+            }
+
+            log.info("总条数[{}] 成功处理了{}条excel数据,跳过了{}条excel数据", end, resList.size(), skip);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            CommonUtils.close(workbook, bufferedInputStream);
+        }
+
+        return resList;
+    }
+
+    private static ClassLoader getClassLoader() {
+        return ExcelReader.class.getClassLoader();
+    }
+
+    private T handleRow(Row row, Class<T> resDataClass) {
+        T resData;
+        try {
+            resData = resDataClass.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            e.printStackTrace();
+            return null;
+        }
+
+        short lastCellNum = row.getLastCellNum();
+        if (lastCellNum < 0) {
+            throw new IllegalArgumentException("数据列小于1");
+        }
+
+
+        Field[] declaredFields = resDataClass.getDeclaredFields();
+        if (arrayEmpty(declaredFields)) {
+            throw new IllegalArgumentException(resDataClass.getName() + "未定义任何属性匹配excel文件");
+        }
+
+        int limit = declaredFields.length > lastCellNum ? lastCellNum : declaredFields.length;
+
+        List<Cell> cellList = getCellList(row, limit);
+        handleRow(Arrays.asList(declaredFields), cellList, resData, limit);
+        return resData;
+    }
+
+    private void handleRow(List<Field> fieldList, List<Cell> cellList, Object object, int limit) {
+        if (CollectionUtils.isEmpty(cellList) || CollectionUtils.isEmpty(fieldList)) {
+            return;
+        }
+
+        if (limit > cellList.size() || limit > fieldList.size()) {
+            throw new IndexOutOfBoundsException("cellList.size = " + cellList.size() + "fieldList.size=" + fieldList.size() + "max index=" + limit);
+        }
+
+        for (int i = 0; i < limit; i++) {
+            Field field = fieldList.get(i);
+            Cell cell = cellList.get(i);
+            try {
+                convertAndSet(field, object, cell);
+            } catch (IllegalAccessException e) {
+                log.error(e.getLocalizedMessage(), e);
+            }
+        }
+        log.debug("解析到内容并封装为对象:[{}]", object);
+    }
+
+    private T handleRow(Class<T> dataClass, Row row) {
+        Field[] declaredFields = dataClass.getDeclaredFields();
+
+        Map<Integer, Field> colIndexFieldMap = selectFieldsToMap(declaredFields);
+        if (colIndexFieldMap == null) {
+            return null;
+        }
+
+        T dataObject;
+        try {
+            dataObject = dataClass.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+
+        short lastCellNum = row.getLastCellNum();
+        for (Map.Entry entry : colIndexFieldMap.entrySet()) {
+
+            Integer key = (Integer) entry.getKey();
+            Field value = (Field) entry.getValue();
+
+            if (key < lastCellNum) {
+                try {
+                    convertAndSet(value, dataObject, row.getCell(key));
+                } catch (IllegalAccessException e) {
+                    log.error(e.getLocalizedMessage(), e);
+                }
+            }
+        }
+
+        return dataObject;
+    }
+
+    private BufferedInputStream convertInputStream(InputStream inputStream) {
+        if (!(inputStream instanceof BufferedInputStream)) {
+            return new BufferedInputStream(inputStream);
+        } else {
+            return (BufferedInputStream) inputStream;
+        }
+    }
+
+    private List<Cell> getCellList(Row row, int limit) {
+        List<Cell> cellList = new ArrayList<>();
+        for (int j = 0; j < limit; j++) {
+            cellList.add(row.getCell(j));
+        }
+        return cellList;
+    }
+
+    private void convertAndSet(Field field, Object object, Cell cell) throws IllegalAccessException {
+        CellType cellType = cell.getCellType();
+        field.setAccessible(true);
+        Class<?> type = field.getType();
+        switch (cellType) {
+            case _NONE:
+                log.debug("row[{}] cell[{}] 单元格内容未知类型", cell.getRowIndex(), cell.getColumnIndex());
+                break;
+            case NUMERIC:
+                Double numericCellValue = cell.getNumericCellValue();
+                if (Double.TYPE.equals(type) || Double.class.equals(type)) {
+                    field.set(object, numericCellValue);
+                } else if (Date.class.equals(type)) {
+                    field.set(object, new Date(numericCellValue.longValue()));
+                }else if(String.class.equals(type)){
+                    field.set(object, String.valueOf(numericCellValue));
+                }else if(Integer.TYPE.equals(type) || Integer.class.equals(type)){
+                    field.set(object, numericCellValue.intValue());
+                }else if(Long.TYPE.equals(type) || Long.class.equals(type)){
+                    field.set(object, numericCellValue.longValue());
+                }
+                log.debug("row[{}] cell[{}] 单元格内容[{}]为数字", cell.getRowIndex(), cell.getColumnIndex(), cell.getNumericCellValue());
+                break;
+            case STRING:
+                String stringCellValue = cell.getStringCellValue();
+                if (String.class.equals(type)) {
+                    field.set(object, stringCellValue);
+
+                } else if (Date.class.equals(type)) {
+                    SimpleDateFormat dateFormat = getDateFormat(field);
+                    try {
+                        Date parse = dateFormat.parse(stringCellValue);
+                        field.set(object, parse);
+                    } catch (Exception e) {
+                        log.error("row[{}] col[{}] 内容为非日期类字符串,不能按照日期格式转换为Date类型或ExcelField注解配置的时间格式有误,detail message:\n{}", cell.getRowIndex(), cell.getColumnIndex(), e.getLocalizedMessage());
+                    }
+
+                } else if (Boolean.TYPE.equals(type) || Boolean.class.equals(type)) {
+
+                    try {
+                        boolean booleanCellValue = Boolean.valueOf(stringCellValue);
+                        field.set(object, booleanCellValue);
+                    } catch (Exception e) {
+                        log.error("row[{}] col[{}] 内容为非boolean类型字符串,不能转换为boolean类型,detail message:\n{}", cell.getRowIndex(), cell.getColumnIndex(), e.getLocalizedMessage());
+                    }
+                }
+
+                log.debug("row[{}] cell[{}] 单元格内容[{}]为字符串", cell.getRowIndex(), cell.getColumnIndex(), stringCellValue);
+                break;
+            case FORMULA:
+                if (String.class.equals(type)) {
+                    String formulaCellValue = cell.getCellFormula();
+                    field.set(object, formulaCellValue);
+                }
+                log.debug("row[{}] cell[{}] 单元格内容[{}]为公式字符串", cell.getRowIndex(), cell.getColumnIndex(), cell.getCellFormula());
+                break;
+            case BLANK:
+                log.debug("row[{}] cell[{}] 单元格内容为空", cell.getRowIndex(), cell.getColumnIndex());
+                break;
+            case BOOLEAN:
+                if (Boolean.TYPE.equals(type) || Boolean.class.equals(type)) {
+                    boolean booleanCellValue = cell.getBooleanCellValue();
+                    field.set(object, booleanCellValue);
+                }
+                log.debug("row[{}] cell[{}] 单元格内容[{}]为boolean", cell.getRowIndex(), cell.getColumnIndex(), cell.getBooleanCellValue());
+                break;
+            case ERROR:
+                log.debug("row[{}] cell[{}] 单元格内容错误", cell.getRowIndex(), cell.getColumnIndex());
+                break;
+            default:
+                break;
+        }
+    }
+
+    private SimpleDateFormat getDateFormat(Field field) {
+        ExcelField[] annotationsByType = field.getAnnotationsByType(ExcelField.class);
+        SimpleDateFormat format;
+        if (arrayEmpty(annotationsByType)) {
+            format = new SimpleDateFormat(DEFAULT_DATE_FORMATE);
+        } else {
+            format = new SimpleDateFormat(annotationsByType[0].dataFormat());
+        }
+        return format;
+    }
+
+    private ExcelReadProperties excelReadProperties(Class<T> tClass) {
+        ExcelEntity[] annotationsByType = tClass.getAnnotationsByType(ExcelEntity.class);
+        if (arrayEmpty(annotationsByType)) {
+            return null;
+        }
+
+        ExcelEntity excelEntity = annotationsByType[0];
+        ExcelReadProperties properties = new ExcelReadProperties();
+        properties.classPathSource = excelEntity.classPathSource();
+        properties.limitRow = excelEntity.limitRow();
+        properties.sheetAt = excelEntity.sheetAt();
+        properties.skip = excelEntity.skip();
+
+        return properties;
+    }
+
+    private Map<Integer, Field> selectFieldsToMap(Field[] fields) {
+        if (CommonUtils.arrayEmpty(fields)) {
+            return null;
+        }
+        Map<Integer, Field> selectMap = new HashMap<>();
+        for (Field field : fields) {
+            ExcelField[] annotationsByType = field.getAnnotationsByType(ExcelField.class);
+            if (CommonUtils.arrayEmpty(annotationsByType)) {
+                continue;
+            }
+            int i = annotationsByType[0].colIndex();
+            if (i >= 0) {
+                selectMap.put(annotationsByType[0].colIndex(), field);
+            }
+        }
+        return selectMap;
+    }
+
+    private class ExcelReadProperties {
+        public String classPathSource;
+
+        public int sheetAt;
+
+        public int skip;
+
+        public int limitRow;
+    }
+
+}

BIN
src/main/resources/students.xlsx