当前位置: 代码网 > it编程>编程语言>Java > Java自定义注解导入和导出合并一对多单元格工具类方式

Java自定义注解导入和导出合并一对多单元格工具类方式

2026年04月07日 Java 我要评论
excel工具类对poi的封装,所以需要导入poi的依赖,我用的是4.1.0版本,如果是4以下,工具里面的poi的相关api需要改变;导入/导出支持:一对多合并(不限制层级数,但每个类只能有一个子集)

excel工具类对poi的封装,所以需要导入poi的依赖,我用的是4.1.0版本,如果是4以下,工具里面的poi的相关api需要改变;

导入/导出支持:一对多合并(不限制层级数,但每个类只能有一个子集)、必填字段检测(读取的时候能用到)、排序(导出能用到)、动态隐藏字段(导入导出会忽略该字段)

1、导入依赖

    <dependencies>
        <dependency>
            <groupid>org.apache.poi</groupid>
            <artifactid>poi</artifactid>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupid>org.apache.poi</groupid>
            <artifactid>poi-ooxml</artifactid>
            <version>4.1.0</version>
        </dependency>

2、创建注解iexcel注解

  • name: 用作excel列名
  • isson:用作判断是否是子集(默认false,如果有子集,在子集成员变量上标注: @iexcel(isson = true))
  • hiddenfield:隐藏字段(默认为:false,当为true时,导入导出会忽略该字段,用法: iexcelutils.hidecolumn( clazz,columnname, target),参数依次为:需要修改的class对象、需要修改的字段名、修改的值,也就是true/false),注意 :iexcelutils.hidecolumn()方法需要用在导入导出前才有效
  • sortno: 排序号(默认为0,不进行排序,如果需要排序,在字段上标注@iexcel(sortno=正整数),从1开始排序)
  • 注意:如果有子集,子集也是从1开始排序
  • isnotblank: 设置字段不为空(默认false;在导入时,如果希望某个字段必填不然该条数据就不要读取,就需要在该字段上标注:@iexcel(isnotblank=true);如需要获取没有读取的字段信息,用 iexcelutils.geterrrowinfo()方法可以获取到)
  • booleanformatter:布尔类型字段转换(处理布尔值的转换,注意:请将表示true的标识写在分割符"|“的左边,表示false的标识写在分割符“|”的右边 ;默认"是|否”)
  • dateformat:日期转换(默认:“yyyy/mm/dd”;导入导出时,日期格式化)
package com.ph.excel.annotation;
import com.ph.excel.iexcelutils;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
/**
 * excel
 */
@retention(retentionpolicy.runtime)
@target(elementtype.field)
public @interface iexcel {
    /**
     * 列名称,不能重复
     * @return
     */
    string name() default "";
    /**
     * 是否是子集
     * @return
     */
    boolean isson() default false;
    /**
     * 隐藏字段
     * @return
     */
    boolean hiddenfield() default false;
    /**
     * 排序号
     * @return
     */
    int sortno() default 0;
    /**
     * 字段必填,不为空
     * @return
     */
    boolean isnotblank() default false;
    //处理布尔值的转换,注意:请将表示true的标识写在分割符"|"的左边,表示false的标识写在分割符“|”的右边 ;默认"是|否"
    string booleanformatter() default "是|否";
    /**
     * 日期格式化
     * @return
     */
    string dateformat() default iexcelutils.iexcel_date_default_format;
}

3、iexcelutils工具类代码

package com.ph.excel;

import com.ph.excel.annotation.iexcel;
import com.sun.istack.internal.notnull;
import org.apache.poi.hssf.usermodel.hssfdateutil;
import org.apache.poi.hssf.usermodel.hssfworkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.cellrangeaddress;
import org.apache.poi.xssf.usermodel.*;

import javax.servlet.http.httpservletresponse;
import java.io.*;
import java.lang.reflect.*;
import java.math.bigdecimal;
import java.net.urlencoder;
import java.text.decimalformat;
import java.text.simpledateformat;
import java.util.*;
import java.util.concurrent.atomic.atomicboolean;
import java.util.concurrent.atomic.atomicinteger;
import java.util.concurrent.atomic.atomicreference;
import java.util.stream.collectors;
import java.util.stream.stream;

/**
 * @classname: iexcelutils
 * @description: 读取或导出excel工具类
 * @date: 2023/6/1 9:57
 * @author: ph9527
 * @version: 1.0
 */
public class iexcelutils {

    /**
     * 获取获取大标题行数时循环的行数
     */
    private final static integer find_title_size = 10;
    /**
     * iexcel与当前exceldate类型共有的日期格式
     */
    public final static string iexcel_date_default_format = "yyyy/mm/dd";

    /**
     * 处理布尔值的转换,注意:请将表示true的标识写在分割符"|"的左边,表示false的标识写在分割符“|”的右边 ;默认"是|否"
     */
    public final static string iexcel_boolean_true_default_flag = "\\|";
    /**
     * 默认标题合并列
     */
    public final static int excel_default_title_mergernum = 6;


    /**
     * 因缺失必填字段为读取的数据信息
     */
    private static list<blankrowinfo> errrowinfo;

    /**
     * excel映射顶级对象class
     */
    private static class clazz;


    static class classvoiexcelentity {
        /**
         * 当前所属对象class
         */
        private class clazz;

        private class parentclass;

        //当前等级
        private integer levelindex;
        /**
         * 所有标注iexcel注解的各属性值
         */
        private list<classvofieldiexcel> fields;
        /**
         * 标注iexcel的子集
         */
        private classvoiexcelentity sonclassvo;
    }


    static class classvofieldiexcel {
        private string classvofieldname;

        private iexcel iexcel;
    }

    private static class celltitlevalueentity {
        private string celltitlename;
        private integer cellindex;
        //在当前行字段对应对象的第一个元素
        private boolean isexcelobjfirstfield;
        //在当前行字段对应对象的最后一个元素
        private boolean isexcelobjlastfield;
    }

    private static class mergedrowinfo {
        private boolean ismerge;
        private integer firstrow;
        private integer lastrow;
    }

    public static class blankrowinfo {
        //缺失信息的行号
        public long rowno;

        //当前对象级别
        public integer objlevel;
        //缺失信息的列名
        public list<string> blanktitlenames;
    }


    private static class exportcolumn {
        private string excelcolumnname;
        private string value;
    }

    private static class exportrow {
        private list<exportcolumn> values;
        private list<exportrow> sons;
        private integer levelindex;
        private integer mergenum;
    }

    private static class titleentity {
        private string name;
        private integer sortno;
    }


    /**
     * 读取excel文件
     *
     * @param inputstream 前端上传到后端的文件用的是multipartfile接收,免得转file,就用inputstream做参数
     * @param filename    文件名,必填,需要根据文件名判断是否是excel文件以及判断是xlsx或者xls,直接用file.getname()就行了
     * @param sourceclass
     * @param <t>
     * @return
     */
    public static <t> list<t> readexcel(@notnull inputstream inputstream, @notnull string filename, @notnull class<t> sourceclass) {
        //初始化
        clazz = null;
        list<t> data = new arraylist<>();
        workbook wb = null;
        try {
            //检测是否是excel文件
            if (!isexcelfile(filename)) {
                throw new runtimeexception("当前文件不是excel文件");
            }
            //检测是否是xlsx,如果文件名为空,则默认xlsx
            wb = isxlsx(filename) ? new xssfworkbook(inputstream) : new hssfworkbook(inputstream);
        } catch (exception e) {
            data = new arraylist<>();
            throw new runtimeexception("excel文件解析错误:" + e);
        }
        if (wb != null) {
            //给顶级对象赋值
            clazz = sourceclass;
            errrowinfo = new arraylist<>();
            sheet sheet0 = wb.getsheetat(0);
            int lastrownum = sheet0.getlastrownum();
            //总行数小于等于标题行则代表没有数据,直接返回;
            int rowcount = lastrownum + 1;
            //获取映射对象字段值
            list<string> iexcelnames = new arraylist<>();
            classvoiexcelentity classvoiexcelentity = new classvoiexcelentity();
            classvoiexcelentity.clazz = clazz;
            classvoiexcelentity.levelindex = 0;
            setallclassvoiexcelentity(classvoiexcelentity, iexcelnames);
            int titlecount = gettitlecount(iexcelnames, sheet0);
            if (rowcount <= titlecount) {
                return data;
            }

            //读取数据
            try {
                readdata(sheet0, titlecount, classvoiexcelentity, data);
            } catch (exception e) {
                throw new runtimeexception("读取excel数据错误:" + e);
            }
        }

        return data;

    }


    /**
     * 导出excel
     *
     * @param filename
     * @param titlename
     * @param response
     * @param data
     * @param sourceclass
     */
    public static void exportexcel(@notnull string filename, @notnull string titlename, @notnull httpservletresponse response, @notnull list data, class sourceclass) throws filenotfoundexception {
        int rowindex = 0;

        workbook workbook = null;
        outputstream outputstream = null;

        try {
            // 创建一个excel工作簿
            workbook = new xssfworkbook();
            // 创建一个工作表
            xssfsheet sheet = (xssfsheet) workbook.createsheet();
            clazz = sourceclass;
            //获取映射对象字段值

            classvoiexcelentity classvoiexcelentity = new classvoiexcelentity();
            classvoiexcelentity.clazz = clazz;
            classvoiexcelentity.levelindex = 0;
            setallclassvoiexcelentity(classvoiexcelentity, new arraylist<>());
            //获取排序好的所有列名
            list<string> iexcelnames = new arraylist<>();
            getiexcelnames(classvoiexcelentity, iexcelnames);

            //获取最后的层级,从0开始的
            integer lastindex = getlastlevel(classvoiexcelentity);

            sheet.setdefaultcolumnwidth(15);

            //设置大标题
            if (strisnotblank(titlename)) {
                createbigtitle(sheet, iexcelnames, titlename, rowindex);
                rowindex++;
            }

            if (listisnotempty(iexcelnames)) {
                //设置小标题
                createsmalltitles(sheet, iexcelnames, rowindex);
                rowindex++;
                if (listisnotempty(data)) {
                    list<exportrow> exportrows = new arraylist<>();
                    //设置数据与exportrow的对应关系
                    setexportdatamapping(classvoiexcelentity, data, exportrows);
                    //设置数据合并行数
                    setmergerowforexportrow(exportrows, lastindex);
                    //将数据输入到excel表格中
                    setdatatoexcel(exportrows, sheet, iexcelnames, rowindex);

                }
            }

            // 告诉浏览器用什么软件可以打开此文件
            response.setheader("content-type", "application/octet-stream;charset=utf-8");
            // 下载文件的默认名称
            response.setheader("content-disposition", "attachment;filename=" + urlencoder.encode(filename + ".xlsx", "utf-8"));
            outputstream = response.getoutputstream();
            workbook.write(outputstream);
        } catch (exception e) {
            e.printstacktrace();
        } finally {
            if (outputstream != null) {
                try {
                    outputstream.close();
                } catch (ioexception e) {
                    throw new runtimeexception(e);
                }
            }

            if (workbook != null) {
                try {
                    workbook.close();
                } catch (ioexception e) {
                    throw new runtimeexception(e);
                }
            }
        }

    }

    private static void setdatatoexcel(list<exportrow> exportrows, xssfsheet sheet, list<string> iexcelnames, int startrowindex) {
        for (exportrow exportrow : exportrows) {
            integer mergenum = exportrow.mergenum;
            list<exportcolumn> values = exportrow.values;
            xssfrow row = nextrow(sheet, startrowindex);
            int cellindex = 0;
            boolean mergeflag = !(mergenum == 0 || mergenum == 1);
            for (; cellindex < values.size(); cellindex++) {
                xssfcell cell = row.createcell(cellindex);
                cell.setcellvalue(getvaluefromexportcolumn(iexcelnames.get(cellindex), values));
                if (mergeflag) {
                    int endindex = startrowindex + mergenum - 1;
                    sheet.addmergedregion(new cellrangeaddress(startrowindex, endindex, cellindex, cellindex));
                }
            }

            list<exportrow> sons = exportrow.sons;
            if (listisnotempty(sons)) {
                setsondatatoexcel(sons, sheet, iexcelnames, startrowindex, cellindex);
            }
            if (mergeflag) {
                startrowindex += mergenum;
            } else {
                startrowindex += 1;
            }
        }
    }

    /**
     * 设置子集的值到excel中
     *
     * @param sons
     * @param sheet
     * @param startrowindex
     * @param startcellindex
     */
    private static void setsondatatoexcel(list<exportrow> sons, xssfsheet sheet, list<string> iexcelnames, int startrowindex, int startcellindex) {
        integer rowindex = startrowindex;

        for (exportrow exportrow : sons) {
            integer cellindex = startcellindex;
            integer mergenum = exportrow.mergenum;
            list<exportcolumn> values = exportrow.values;
            xssfrow row = null;
            if (sheet.getrow(rowindex) == null) {
                row = nextrow(sheet, rowindex);
            } else {
                row = sheet.getrow(rowindex);
            }

            integer endcellindex = values.size() + startcellindex;

            //合并标识
            boolean mergeflag = !(mergenum == 0 || mergenum == 1);

            for (; cellindex < endcellindex; cellindex++) {
                xssfcell cell = row.createcell(cellindex);
                cell.setcellvalue(getvaluefromexportcolumn(iexcelnames.get(cellindex), values));
                if (mergeflag) {
                    int endindex = rowindex + mergenum - 1;
                    sheet.addmergedregion(new cellrangeaddress(rowindex, endindex, cellindex, cellindex));
                }
            }

            list<exportrow> sons1 = exportrow.sons;

            if (mergeflag) {
                rowindex += mergenum;
            } else {
                rowindex += 1;
            }
            if (listisnotempty(sons1)) {
                setsondatatoexcel(sons1, sheet, iexcelnames, row.getrownum(), startcellindex + values.size());
            }
        }


    }


    /**
     * 根据列名获取值
     *
     * @param name
     * @param values
     * @return
     */
    private static string getvaluefromexportcolumn(string name, list<exportcolumn> values) {
        for (exportcolumn exportcolumn : values) {
            if (name.equals(exportcolumn.excelcolumnname)) {
                return exportcolumn.value;
            }
        }
        return null;
    }


    /**
     * 获取最后的层级数
     *
     * @param classvoiexcelentity
     * @return
     */
    private static integer getlastlevel(classvoiexcelentity classvoiexcelentity) {
        classvoiexcelentity sonclassvo = classvoiexcelentity.sonclassvo;
        if (sonclassvo == null) {
            return classvoiexcelentity.levelindex;
        } else {
            return getlastlevel(sonclassvo);
        }
    }

    /**
     * 设置合并行数
     *
     * @param exportrows
     * @param lastindex
     */
    private static void setmergerowforexportrow(list<exportrow> exportrows, integer lastindex) {
        for (exportrow exportrow : exportrows) {
            list<exportrow> sons = exportrow.sons;
            if (lastindex == 0) {
                exportrow.mergenum = 1;
            } else {
                exportrow.mergenum = getmergenum(sons, lastindex);
                if (listisnotempty(sons)) {
                    setmergerowforexportrow(sons, lastindex);
                }
            }


        }
    }

    private static int getmergenum(list<exportrow> sons, integer lastindex) {
        if (listisnotempty(sons)) {
            exportrow exportrow = sons.get(0);
            if (exportrow.levelindex == lastindex - 1) {
                atomicinteger count = new atomicinteger();
                sons.foreach(item -> {
                    list<exportrow> sons1 = item.sons;
                    if (listisnotempty(sons1)) {
                        count.addandget(sons1.size());
                    }
                });
                return count.get();
            } else if (exportrow.levelindex == lastindex) {
                return sons.size();
            } else {
                atomicinteger flag = new atomicinteger();
                sons.foreach(item -> {
                    flag.addandget(getmergenum(item.sons, lastindex));
                });
                return flag.get();
            }
        }
        return 0;
    }

    /**
     * 获取所有excel列名,并按顺序排列
     *
     * @param classvoiexcelentity
     * @return
     */
    private static void getiexcelnames(classvoiexcelentity classvoiexcelentity, list<string> names) {
        if (classvoiexcelentity != null) {
            list<classvofieldiexcel> fields = classvoiexcelentity.fields;
            classvoiexcelentity sonclassvo = classvoiexcelentity.sonclassvo;
            if (listisnotempty(fields)) {
                list<iexcel> excelssorted = new arraylist<>();
                list<iexcel> excels = new arraylist<>();
                for (int i = 0; i < fields.size(); i++) {
                    classvofieldiexcel classvofieldiexcel = fields.get(i);
                    iexcel iexcel = classvofieldiexcel.iexcel;
                    if (iexcel != null && !iexcel.isson()) {
                        if (iexcel.sortno() == 0) {
                            excels.add(iexcel);
                        } else {
                            excelssorted.add(iexcel);
                        }
                    }
                }
                //合并
                list<string> newnames = stream.concat(
                        excelssorted.stream().sorted(comparator.comparingint(iexcel::sortno)).map(item -> item.name()),
                        excels.stream().map(item -> item.name())
                ).collect(collectors.tolist());

                names.addall(newnames);
            }

            //是否是有集
            if (sonclassvo != null) {
                getiexcelnames(classvoiexcelentity.sonclassvo, names);
            }
        }


    }

    /**
     * 设置数据与excel每列的对应关系
     *
     * @param classvoiexcelentity
     * @param data
     * @param exportrows
     */
    private static void setexportdatamapping(classvoiexcelentity classvoiexcelentity, list data, list<exportrow> exportrows) {
        for (int i = 0; i < data.size(); i++) {
            exportrow exportrow = new exportrow();
            list<exportrow> sonexportrow = null;
            object obj = data.get(i);
            class<?> objclass = obj.getclass();
            classvoiexcelentity classentity = getclassentitybyclass(classvoiexcelentity, objclass);
            if (classentity != null) {
                list<classvofieldiexcel> fieldiexcels = classentity.fields;
                list<exportcolumn> columnlist = new arraylist<>();
                fieldiexcels.foreach(fieldiexcel -> {
                    try {
                        if (!fieldiexcel.iexcel.isson()) {
                            field field = objclass.getdeclaredfield(fieldiexcel.classvofieldname);
                            if (field != null) {
                                field.setaccessible(true);
                                exportcolumn exportcolumn = new exportcolumn();
                                exportcolumn.value = getfieldvalue(obj, field, fieldiexcel.iexcel);
                                exportcolumn.excelcolumnname = fieldiexcel.iexcel.name();
                                columnlist.add(exportcolumn);
                            }
                        }
                    } catch (exception e) {
                        throw new runtimeexception(e);
                    }
                });

                exportrow.values = columnlist;
                exportrow.levelindex = classentity.levelindex;
                classvoiexcelentity sonclassvo = classentity.sonclassvo;
                if (sonclassvo != null) {
                    sonexportrow = new arraylist<>();
                    list sondata = getsondata(obj);
                    if (listisnotempty(sondata)) {
                        setexportdatamapping(classvoiexcelentity, sondata, sonexportrow);
                        exportrow.sons = sonexportrow;
                    }
                }
                exportrows.add(exportrow);
            }

        }
    }

    /**
     * 获取对象的属性值
     *
     * @param obj
     * @param <t>
     * @return
     */
    private static <t> string getfieldvalue(object obj, field field, iexcel annotation) throws exception {
        string value = null;
        field.setaccessible(true);
        if (field.gettype() == boolean.class || field.gettype() == boolean.class) {
            if (annotation != null) {
                string s = annotation.booleanformatter();
                string[] split = s.split(iexcel_boolean_true_default_flag);
                object o = field.get(obj);
                if (o != null) {
                    boolean aboolean = (boolean) field.get(obj);
                    value = aboolean ? split[0] : split[1];
                } else {
                    value = "";
                }


            }
        } else if (field.gettype() == date.class) {
            if (annotation != null) {
                string dateformatter = annotation.dateformat();
                object o = field.get(obj);
                if (o != null) {
                    date date = (date) field.get(obj);
                    simpledateformat simpledateformat = new simpledateformat(dateformatter);
                    value = simpledateformat.format(date);
                } else {
                    value = "";
                }

            }
        } else {
            object o = field.get(obj);
            value = o != null ? o.tostring() : "";

        }

        return value;
    }

    /**
     * 获取子集
     *
     * @param obj
     * @return
     */
    private static list getsondata(object obj) {
        field[] declaredfields = obj.getclass().getdeclaredfields();
        for (field field : declaredfields) {
            class<?> type = field.gettype();
            if (type == list.class) {
                iexcel annotation = field.getannotation(iexcel.class);
                if (annotation != null && annotation.isson()) {
                    try {
                        field.setaccessible(true);
                        return (list) field.get(obj);
                    } catch (illegalaccessexception e) {
                        throw new runtimeexception(e);
                    }
                }
            }

        }

        return null;
    }

    /**
     * 根据class获取对应的classvoiexcelentity
     *
     * @param classvoiexcelentity
     * @param aclass
     * @return
     */
    private static classvoiexcelentity getclassentitybyclass(classvoiexcelentity classvoiexcelentity, class<?> aclass) {
        if (classvoiexcelentity == null) return null;
        class clazz1 = classvoiexcelentity.clazz;
        if (clazz1.gettypename().equals(aclass.gettypename())) return classvoiexcelentity;
        classvoiexcelentity sonclassvo = classvoiexcelentity.sonclassvo;
        return getclassentitybyclass(sonclassvo, aclass);
    }


    /**
     * 创建大标题样式
     *
     * @param wb
     * @return
     */
    public static xssfcellstyle createbigtitlecellstyle(xssfworkbook wb) {
        // 标题样式(加粗,垂直居中)
        xssfcellstyle titlecellstyle = wb.createcellstyle();
        titlecellstyle.setalignment(horizontalalignment.center);//水平居中
        titlecellstyle.setverticalalignment(verticalalignment.center);//垂直居中
        xssffont fontstyle = wb.createfont();
        fontstyle.setbold(true);   //加粗
        fontstyle.setfontheightinpoints((short) 16);  //设置标题字体大小
        titlecellstyle.setfont(fontstyle);
        return titlecellstyle;
    }


    /**
     * 创建小标题样式
     *
     * @param wb
     * @return
     */
    public static xssfcellstyle createsmalltitlecellstyle(xssfworkbook wb) {
        //设置表头样式,表头居中
        xssfcellstyle style = wb.createcellstyle();
        //设置单元格样式
        style.setalignment(horizontalalignment.center);
        style.setverticalalignment(verticalalignment.center);

        //设置字体
        xssffont font = wb.createfont();
        font.setfontheightinpoints((short) 14);
        style.setfont(font);
        return style;
    }

    /**
     * 设置大标题
     *
     * @param sheet
     * @param iexcelnames
     * @param titlename
     * @param rowindex
     */
    private static void createbigtitle(xssfsheet sheet, list<string> iexcelnames, string titlename, int rowindex) {
        xssfcellstyle style = createbigtitlecellstyle(sheet.getworkbook());
        xssfrow rowbigtitle = nextrow(sheet, rowindex);
        //大标题
        xssfcell cell = rowbigtitle.createcell(0);
        cell.setcellvalue(titlename);
        cell.setcellstyle(style);
        sheet.addmergedregion(new cellrangeaddress(0, 0, 0, listisnotempty(iexcelnames) ? iexcelnames.size() - 1 : excel_default_title_mergernum));
    }

    /**
     * 设置小标题
     *
     * @param sheet
     * @param iexcelnames
     * @param rowindex
     */
    private static void createsmalltitles(xssfsheet sheet, list<string> iexcelnames, int rowindex) {
        xssfcellstyle style = createsmalltitlecellstyle(sheet.getworkbook());
        xssfrow rowsmalltitle = nextrow(sheet, rowindex);
        for (int i = 0; i < iexcelnames.size(); i++) {
            xssfcell cell = rowsmalltitle.createcell(i);
            cell.setcellvalue(iexcelnames.get(i));
            cell.setcellstyle(style);
        }

    }

    /**
     * 获取下一行
     *
     * @param sheet
     * @param rowindex
     * @return
     */
    private static xssfrow nextrow(xssfsheet sheet, int rowindex) {
        xssfrow row = sheet.createrow(rowindex);
        return row;
    }

    /**
     * 读取数据
     *
     * @param sheet
     * @param titlecount
     * @param classvoiexcelentity
     * @param data
     * @param <t>
     */
    private static <t> void readdata(sheet sheet, integer titlecount, classvoiexcelentity classvoiexcelentity, list<t> data) throws exception {
        //定义一个数组,存放各个层级的当前对象
        list levelsobjs = new arraylist();
        //获取excel的所有小标题
        list<celltitlevalueentity> celltitles = getcelltitles(sheet, titlecount);
        if (listisnotempty(celltitles)) {
            //设置哪些是当前行的第一个元素
            setfirstandlastfield(celltitles, classvoiexcelentity);
            //开始读取数据
            int startdataindex = titlecount + 1;
            int allrownums = sheet.getlastrownum() + 1;
            try {
                //循环excel每一行
                for (int i = startdataindex; i < allrownums; i++) {
                    row row = sheet.getrow(i);
                    if (row != null && checkrowdataisnotblank(celltitles, row)) {
                        for (int j = 0; j < celltitles.size(); j++) {
                            celltitlevalueentity celltitlevalueentity = celltitles.get(j);
                            integer nowcellindex = celltitlevalueentity.cellindex;
                            cell cell = row.getcell(nowcellindex);
                            if (cell == null) {
                                cell = row.createcell(nowcellindex);
                            }
                            string cellvalue = getcellvalue(cell);
                            //获取当前字段的所属class
                            classvoiexcelentity classvoiexcelentitynow = getclassvoexcelentitybyexcelcelltitle(celltitlevalueentity.celltitlename, classvoiexcelentity);
                            integer levelindex = classvoiexcelentitynow.levelindex;
                            if (classvoiexcelentitynow != null) {
                                //当前单元格是否为第一个字段
                                boolean isexcelobjfirstfield = celltitlevalueentity.isexcelobjfirstfield;
                                boolean isexcelobjlastfieldfield = celltitlevalueentity.isexcelobjlastfield;
                                //获取合并信息
                                mergedrowinfo mergedrowinfo = getmergedrowinfo(cell, sheet);
                                boolean ismerge = mergedrowinfo.ismerge;
                                integer firstrow = mergedrowinfo.firstrow;
                                integer lastrow = mergedrowinfo.lastrow;


                                //判断是否需要新建对象
                                if (isexcelobjfirstfield && (!ismerge || i == firstrow)) {
                                    if (!listisnotempty(levelsobjs) || levelsobjs.size() < levelindex + 1) {
                                        levelsobjs.add(classvoiexcelentitynow.clazz.newinstance());
                                    } else {
                                        levelsobjs.set(levelindex, classvoiexcelentitynow.clazz.newinstance());
                                    }
                                }
                                //获取当前对象
                                object nowobj = levelsobjs.get(classvoiexcelentitynow.levelindex);

                                //获取当前单元格对应对象的字段名
                                string fieldname = getfieldnamebycelltitlename(celltitlevalueentity.celltitlename, classvoiexcelentitynow);

                                //给属性设置值
                                if (strisnotblank(cellvalue)) {
                                    setcellvaluetoobjfield(nowobj, fieldname, cellvalue);
                                }

                                //获取当前对象的上级对象
                                object parentobj = getparentobj(classvoiexcelentitynow, levelsobjs);
                                list sonlist = getsonlistbyparentobj(parentobj);
                                //判断当前单元格是否是所属对象最后的一个对应,借此判断当前行当前对象是否填充完成
                                if (isexcelobjlastfieldfield && (!ismerge || i == lastrow)) {
                                    //判断必填字段是否都有值
                                    blankrowinfo blankrowinfo = checkobjisnotblankfield(classvoiexcelentitynow, nowobj, (long) (i + 1));
                                    if (blankrowinfo == null) {
                                        if (parentobj != null) {
                                            sonlist.add(nowobj);
                                        } else {
                                            data.add((t) nowobj);
                                        }
                                    } else {
                                        errrowinfo.add(blankrowinfo);
                                        setsonfieldvaluetonull(nowobj);
                                        break;
                                    }

                                }


                            }

                        }

                    }
                }
            } catch (exception e) {
                e.printstacktrace();
            }
        }
    }


    /**
     * 获取未被读取的错误信息
     *
     * @return
     */
    public static list<blankrowinfo> geterrrowinfo() {
        return errrowinfo;
    }

    /**
     * 设置子集值为空
     *
     * @param nowobj
     */
    private static void setsonfieldvaluetonull(object nowobj) {
        if (nowobj != null) {
            class<?> parentobjclass = nowobj.getclass();
            field[] declaredfields = parentobjclass.getdeclaredfields();
            for (field field : declaredfields) {
                iexcel annotation = field.getannotation(iexcel.class);
                if (annotation != null) {
                    if (annotation.isson()) {
                        field.setaccessible(true);
                        class<?> type = field.gettype();
                        if (type == list.class) {
                            try {
                                field.set(nowobj, null);
                            } catch (illegalaccessexception e) {
                                throw new runtimeexception(e);
                            }
                        }

                    }
                }
            }
        }
    }

    /**
     * 检查当前对象必填字段是否都有值
     *
     * @param classvoiexcelentitynow
     * @param nowobj
     */
    private static blankrowinfo checkobjisnotblankfield(classvoiexcelentity classvoiexcelentitynow, object nowobj, long rowno) {
        atomicreference<blankrowinfo> blankrowinfo = new atomicreference<>();
        list<classvofieldiexcel> fields = classvoiexcelentitynow.fields;
        if (nowobj != null && listisnotempty(fields)) {
            class<?> clazz = nowobj.getclass();
            field[] declaredfields = clazz.getdeclaredfields();
            arrays.stream(declaredfields).foreach(field -> {
                field.setaccessible(true);
                try {
                    object fieldvalueobj = field.get(nowobj);
                    iexcel iexcel = field.getannotation(iexcel.class);
                    if (fieldvalueobj == null && iexcel != null && iexcel.isnotblank()) {
                        if (blankrowinfo.get() == null) {
                            blankrowinfo.set(new blankrowinfo());
                            blankrowinfo.get().rowno = rowno;
                            blankrowinfo.get().objlevel = classvoiexcelentitynow.levelindex;
                            blankrowinfo.get().blanktitlenames = new arraylist<>();
                        }
                        blankrowinfo.get().blanktitlenames.add(iexcel.name());
                    }

                } catch (illegalaccessexception e) {
                    throw new runtimeexception(e);
                }

            });


        }
        return blankrowinfo.get();
    }


    /**
     * 获取上级对象的子集
     *
     * @param parentobj
     * @return
     */
    private static list getsonlistbyparentobj(object parentobj) {
        if (parentobj != null) {
            class<?> parentobjclass = parentobj.getclass();
            field[] declaredfields = parentobjclass.getdeclaredfields();
            for (field field : declaredfields) {
                iexcel annotation = field.getannotation(iexcel.class);
                if (annotation != null) {
                    if (annotation.isson()) {
                        field.setaccessible(true);
                        class<?> type = field.gettype();
                        if (type == list.class) {
                            try {
                                object son = field.get(parentobj);
                                if (son != null) {
                                    return (list) son;
                                }
                                list sonlist = new arraylist<>();
                                field.set(parentobj, sonlist);
                                return sonlist;
                            } catch (illegalaccessexception e) {
                                throw new runtimeexception(e);
                            }
                        }

                    }
                }
            }
        }
        return null;


    }

    /**
     * 获取父级对象
     *
     * @param classvoiexcelentitynow
     * @param levelsobjs
     * @return
     */
    private static object getparentobj(classvoiexcelentity classvoiexcelentitynow, list levelsobjs) {
        object parentobj = null;
        class parentclass = classvoiexcelentitynow.parentclass;
        if (parentclass != null) {
            string typename = parentclass.gettypename();
            for (object item : levelsobjs) {
                if (typename.equals(item.getclass().gettypename())) {
                    parentobj = item;
                    break;
                }
            }
        }


        return parentobj;
    }

    /**
     * 获取当前单元格对应对象的字段名
     *
     * @param celltitlename
     * @param classvoiexcelentitynow
     * @return
     */
    private static string getfieldnamebycelltitlename(string celltitlename, classvoiexcelentity classvoiexcelentitynow) {
        list<classvofieldiexcel> fields = classvoiexcelentitynow.fields;
        for (classvofieldiexcel classvofieldiexcel : fields) {
            if (classvofieldiexcel.iexcel.name().equals(celltitlename)) {
                return classvofieldiexcel.classvofieldname;
            }
        }
        return null;
    }

    /**
     * 给属性设置值
     *
     * @param obj
     * @param filedname
     * @param cellvalue
     * @param <t>
     */
    private static <t> void setcellvaluetoobjfield(object obj, string filedname, object cellvalue) throws exception {
        class<?> clazz = obj.getclass();
        field declaredfield = clazz.getdeclaredfield(filedname);
        declaredfield.setaccessible(true);
        class<?> type = declaredfield.gettype();
        if (type == integer.class || type == int.class) {
            declaredfield.set(obj, integer.parseint(cellvalue.tostring()));
        } else if (type == long.class || type == long.class) {
            declaredfield.set(obj, long.parselong(cellvalue.tostring()));
        } else if (type == boolean.class || type == boolean.class) {
            iexcel annotation = declaredfield.getannotation(iexcel.class);
            string s = annotation.booleanformatter();
            string[] split = s.split(iexcel_boolean_true_default_flag);
            declaredfield.set(obj, split[0].trim().equals(cellvalue.tostring().trim()) ? true : false);
        } else if (type == date.class) {
            iexcel annotation = declaredfield.getannotation(iexcel.class);
            string s = annotation.dateformat();
            simpledateformat format = new simpledateformat(s);
            declaredfield.set(obj, format.parse(cellvalue.tostring()));
        } else if (type == double.class || type == double.class) {
            declaredfield.set(obj, double.valueof(cellvalue.tostring()));
        } else if (type == list.class) {
            declaredfield.set(obj, cellvalue);
        } else if (type == bigdecimal.class) {
            bigdecimal bigdecimal = bigdecimal.valueof(long.valueof(cellvalue.tostring()));
            declaredfield.set(obj, bigdecimal);
        } else {
            declaredfield.set(obj, cellvalue);
        }
    }

    /**
     * 设置哪些是当前行的第一个元素和最后一个元素 (注意:这里要求不能出现重复的列名)
     *
     * @param celltitles
     * @param classvoiexcelentity
     */
    private static void setfirstandlastfield(list<celltitlevalueentity> celltitles, classvoiexcelentity classvoiexcelentity) {
        final classvoiexcelentity[] previousclassvo = {null};
        for (int i = 0; i < celltitles.size(); i++) {
            celltitlevalueentity item = celltitles.get(i);
            string celltitlename = item.celltitlename;
            classvoiexcelentity nowclassvoentity = getclassentitybycelltitlename(celltitlename, classvoiexcelentity);
            if (nowclassvoentity != null) {
                //设置是否是第一个元素
                if (previousclassvo[0] == null) {
                    item.isexcelobjfirstfield = true;
                    previousclassvo[0] = nowclassvoentity;
                } else if (!previousclassvo[0].clazz.gettypename().equals(nowclassvoentity.clazz.gettypename())) {
                    item.isexcelobjfirstfield = true;
                    previousclassvo[0] = nowclassvoentity;

                }

                //设置是否是最后一个元素
                if (i < celltitles.size() - 1) {
                    celltitlevalueentity nextitem = celltitles.get(i + 1);
                    string nextcelltitlename = nextitem.celltitlename;
                    classvoiexcelentity nextclassvoentity = getclassentitybycelltitlename(nextcelltitlename, classvoiexcelentity);
                    if (nextclassvoentity != null) {
                        if (!nowclassvoentity.clazz.gettypename().equals(nextclassvoentity.clazz.gettypename())) {
                            item.isexcelobjlastfield = true;
                        }

                    }
                }
                if (i == celltitles.size() - 1) {
                    item.isexcelobjlastfield = true;
                }
            }

        }
    }


    /**
     * 根据列名获取 classvoiexcelentity
     *
     * @param celltitlename
     * @param classvoiexcelentity
     * @return
     */
    private static classvoiexcelentity getclassentitybycelltitlename(string celltitlename, classvoiexcelentity classvoiexcelentity) {
        list<classvofieldiexcel> fields = classvoiexcelentity.fields;
        for (classvofieldiexcel item : fields) {
            iexcel iexcel = item.iexcel;
            string name = iexcel.name();
            if (name.equals(celltitlename)) {
                return classvoiexcelentity;
            }
        }

        classvoiexcelentity sonclassvo = classvoiexcelentity.sonclassvo;
        if (sonclassvo != null) {
            return getclassentitybycelltitlename(celltitlename, sonclassvo);
        }
        return null;

    }


    /**
     * 获取当前字段所属excel映射对象
     *
     * @param celltitlename
     * @param classvoiexcelentity
     * @return
     */
    private static classvoiexcelentity getclassvoexcelentitybyexcelcelltitle(string celltitlename, classvoiexcelentity classvoiexcelentity) {
        classvoiexcelentity rsclassvoiexcelentity = null;
        list<classvofieldiexcel> fields = classvoiexcelentity.fields;
        for (classvofieldiexcel classvofieldiexcel : fields) {
            iexcel iexcel = classvofieldiexcel.iexcel;
            string name = iexcel.name();
            if (name.equals(celltitlename)) {
                rsclassvoiexcelentity = classvoiexcelentity;
                break;
            }
        }

        if (rsclassvoiexcelentity == null && classvoiexcelentity.sonclassvo != null) {
            rsclassvoiexcelentity = getclassvoexcelentitybyexcelcelltitle(celltitlename, classvoiexcelentity.sonclassvo);
        }

        return rsclassvoiexcelentity;

    }

    /**
     * 获取标题总行数
     * iexcelnames
     *
     * @param sheet0
     * @return
     */
    private static int gettitlecount(list<string> iexcelnames, sheet sheet0) {
        for (int i = 0; i < find_title_size; i++) {
            row row = sheet0.getrow(i);
            if (row != null) {
                int lastcellnum = row.getlastcellnum();
                for (int j = 0; j < lastcellnum; j++) {
                    cell cell = row.getcell(j);
                    string cellvalue = getcellvalue(cell);
                    if (strisnotblank(cellvalue) && iexcelnames.contains(cellvalue)) {
                        return i;
                    }
                }
            }
        }

        return 0;
    }


    /**
     * 获取合并行信息
     *
     * @param cell
     * @param sheet
     * @return
     */
    private static mergedrowinfo getmergedrowinfo(cell cell, sheet sheet) {
        mergedrowinfo mergedrowinfo = new mergedrowinfo();
        for (cellrangeaddress region : sheet.getmergedregions()) {
            if (region.isinrange(cell.getrowindex(), cell.getcolumnindex())) {
                mergedrowinfo.ismerge = true;
                mergedrowinfo.firstrow = region.getfirstrow();
                mergedrowinfo.lastrow = region.getlastrow();
                return mergedrowinfo;
            }
        }
        mergedrowinfo.ismerge = false;
        return mergedrowinfo;
    }


    /**
     * 检查当前行不是空的
     *
     * @param celltitles
     * @param row
     * @return
     */
    private static boolean checkrowdataisnotblank(list<celltitlevalueentity> celltitles, row row) {
        atomicinteger flag = new atomicinteger();
        for (celltitlevalueentity title : celltitles) {
            integer cellindex = title.cellindex;
            cell cell = row.getcell(cellindex);
            if (cell != null) {
                mergedrowinfo mergedrowinfo = getmergedrowinfo(cell, row.getsheet());
                if (mergedrowinfo != null && mergedrowinfo.ismerge) {
                    return true;
                }
                if (strisnotblank(getcellvalue(cell))) {
                    flag.getandincrement();
                }
            }

        }
        return flag.get() > 0;
    }

    /**
     * 获取所有小标题
     *
     * @param sheet
     * @param titlecount
     * @return
     */
    private static list<celltitlevalueentity> getcelltitles(sheet sheet, integer titlecount) {
        list<celltitlevalueentity> celltitles = new arraylist<>();
        row celltitlerow = sheet.getrow(titlecount);
        if (celltitlerow != null) {
            int lastcellnum = celltitlerow.getlastcellnum();

            for (int i = 0; i < lastcellnum; i++) {
                cell cell = celltitlerow.getcell(i);
                string cellvalue = getcellvalue(cell);
                if (strisnotblank(cellvalue)) {
                    celltitlevalueentity celltitleentity = new celltitlevalueentity();
                    celltitleentity.celltitlename = cellvalue;
                    celltitleentity.cellindex = i;
                    celltitles.add(celltitleentity);
                }
            }
        }
        return celltitles;
    }

    /**
     * 获取excel表格单元格的值
     *
     * @param cell
     * @return
     */
    private static string getcellvalue(cell cell) {
        string cellvalue = "";
        if (cell != null) {
            // 判断当前cell的type
            switch (cell.getcelltype()) {
                // 如果当前cell的type为numeric
                case numeric:
                case formula: {
                    // 判断当前的cell是否为date
                    if (hssfdateutil.iscelldateformatted(cell)) {
                        date date = cell.getdatecellvalue();
                        simpledateformat sdf = new simpledateformat(iexcel_date_default_format);
                        cellvalue = sdf.format(date);
                    }
                    // 如果是纯数字
                    else {
                        // 取得当前cell的数值
                        cellvalue = new decimalformat("0").format(cell.getnumericcellvalue());
                    }
                    break;
                }
                // 如果当前cell的type为strin
                case string:
                    // 取得当前的cell字符串
                    cellvalue = cell.getrichstringcellvalue().getstring();
                    break;
                // 默认的cell值
                default:
                    cellvalue = " ";
            }
        } else {
            cellvalue = "";
        }
        return cellvalue;
    }


    /**
     * 设置所有iexcel注解与目标对象的映射字段名和值
     *
     * @param classvoiexcelentity classvoiexcelentity.clazz必须有值
     * @param iexcelnames
     */
    private static void setallclassvoiexcelentity(classvoiexcelentity classvoiexcelentity, list<string> iexcelnames) {
        atomicboolean issonflag = new atomicboolean(false);
        class nowclazz = classvoiexcelentity.clazz;
        list<classvofieldiexcel> classvofields = new arraylist<>();
        field[] declaredfields = nowclazz.getdeclaredfields();
        arrays.stream(declaredfields).foreach(field -> {
            iexcel iexcel = field.getannotation(iexcel.class);
            if (iexcel != null && !iexcel.hiddenfield()) {
                classvofieldiexcel classvofieldiexcel = new classvofieldiexcel();
                if (iexcel.isson() && !issonflag.get()) {
                    //处理子集
                    class sonclass = getgenericclassforlist(field);
                    if (sonclass != null) {
                        classvoiexcelentity sonclassvoiexcel = new classvoiexcelentity();
                        sonclassvoiexcel.clazz = sonclass;
                        sonclassvoiexcel.parentclass = classvoiexcelentity.clazz;
                        sonclassvoiexcel.levelindex = classvoiexcelentity.levelindex + 1;
                        setallclassvoiexcelentity(sonclassvoiexcel, iexcelnames);
                        classvoiexcelentity.sonclassvo = sonclassvoiexcel;
                        issonflag.set(true);
                    }
                } else {
                    iexcelnames.add(iexcel.name());
                }
                classvofieldiexcel.classvofieldname = field.getname();
                classvofieldiexcel.iexcel = iexcel;
                classvofields.add(classvofieldiexcel);
            }

        });
        classvoiexcelentity.fields = classvofields;
    }

    /**
     * 获取list的泛型类型
     *
     * @param field
     * @return
     */
    private static class getgenericclassforlist(field field) {
        class clazz = null;
        if (field.gettype() == list.class) {
            type generictype = field.getgenerictype();
            if (generictype != null && generictype instanceof parameterizedtype) {
                parameterizedtype pt = (parameterizedtype) generictype;
                clazz = (class<?>) pt.getactualtypearguments()[0];
            }
        }
        return clazz;
    }


    /**
     * 判断是否是excel文件
     *
     * @param filename
     * @return
     */
    private static boolean isexcelfile(string filename) {
        if (!strisnotblank(filename)) {
            return false;
        }
        string filenamesuffix = getfilenamesuffix(filename);
        if (filenamesuffix.tolowercase().equals("xlsx") || filenamesuffix.tolowercase().equals("xls")) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 检测excel类型,如果filename为空,则默认为xlsx
     *
     * @param filename
     * @return
     */
    private static boolean isxlsx(string filename) {
        if (!strisnotblank(filename)) {
            return true;
        }
        string filenamesuffix = getfilenamesuffix(filename);
        if (filenamesuffix.tolowercase().equals("xlsx")) {
            return true;
        } else {
            return false;
        }

    }

    /**
     * 获取文件后缀名
     *
     * @param filename
     * @return
     */
    private static string getfilenamesuffix(string filename) {
        string[] split = filename.split("\\u002e");
        string filenamesuffix = split[split.length - 1];
        return filenamesuffix;
    }

    /**
     * 检测字符串不为空
     *
     * @param str
     * @return
     */
    private static boolean strisnotblank(string str) {
        return !(str == null || str.trim().equals(""));
    }

    /**
     * 判断list不为空
     *
     * @param list
     * @return
     */
    private static boolean listisnotempty(list list) {
        return list != null && list.size() > 0;
    }

    /**
     * 隐藏字段
     * @param clazz
     * @param columnname
     * @param target
     * @throws exception
     */
    public static void hidecolumn(class<?> clazz, string columnname, boolean target) throws exception {
        if (!strisnotblank(columnname)) {
            throw new nullpointerexception("传入的属性列名为空");
        }
        if (target == null) {
            target = true;
        }
        //获取目标对象的属性值
        field field = clazz.getdeclaredfield(columnname);
        //获取注解反射对象
        iexcel excelanion = field.getannotation(iexcel.class);
        //获取代理
        invocationhandler invocationhandler = proxy.getinvocationhandler(excelanion);
        field excelfield = invocationhandler.getclass().getdeclaredfield("membervalues");
        excelfield.setaccessible(true);
        map membervalues = (map) excelfield.get(invocationhandler);
        membervalues.put("hiddenfield", target);
    }
}

4、测试

a. 测试的实体类:订单、订单明细、追溯码

  • ordermodel
package com.ph.excel.vo;

import com.ph.excel.annotation.iexcel;

import java.util.date;
import java.util.list;

/**
 * @classname: ordermodel
 * @description: todo
 * @date: 2023/6/2 14:31
 * @author: ph9527
 * @version: 1.0
 */
public class ordermodel {

    private long id;
    @iexcel(name = "订单号",isnotblank = true)
    private string orderno;
    @iexcel(name = "订单时间", sortno = 2)
    private date ordertime;
    @iexcel(name = "购买人", sortno = 1)
    private string buyuser;

    @iexcel(isson = true)
    private list<detailmodel> details;

    public ordermodel() {
    }

    public ordermodel(long id, string orderno, date ordertime, string buyuser, integer buynum, list<detailmodel> details) {
        this.id = id;
        this.orderno = orderno;
        this.ordertime = ordertime;
        this.buyuser = buyuser;
        this.details = details;
    }

    @override
    public string tostring() {
        return "ordermodel{" +
                "id=" + id +
                ", orderno='" + orderno + '\'' +
                ", ordertime=" + ordertime +
                ", buyuser='" + buyuser + '\'' +
                ", details=" + details +
                '}';
    }

    public long getid() {
        return id;
    }

    public void setid(long id) {
        this.id = id;
    }

    public string getorderno() {
        return orderno;
    }

    public void setorderno(string orderno) {
        this.orderno = orderno;
    }

    public date getordertime() {
        return ordertime;
    }

    public void setordertime(date ordertime) {
        this.ordertime = ordertime;
    }

    public string getbuyuser() {
        return buyuser;
    }

    public void setbuyuser(string buyuser) {
        this.buyuser = buyuser;
    }

    public list<detailmodel> getdetails() {
        return details;
    }

    public void setdetails(list<detailmodel> details) {
        this.details = details;
    }
}

  • detailmodel:
package com.ph.excel.vo;

import com.ph.excel.annotation.iexcel;

import java.util.date;
import java.util.list;

/**
 * @classname: detailmodel
 * @description: todo
 * @date: 2023/6/2 14:31
 * @author: ph9527
 * @version: 1.0
 */
public class detailmodel {
    private long id;
    private long orderid;
    @iexcel(name = "商品名")
    private string goodname;
    @iexcel(name = "商品码", isnotblank = true, sortno = 2)
    private string goodcode;
    @iexcel(name = "购买数量", sortno = 1)
    private integer buynum;
    @iexcel(isson = true)
    private list<codemodel> codes;

    @override
    public string tostring() {
        return "detailmodel{" +
                "id=" + id +
                ", orderid=" + orderid +
                ", goodname='" + goodname + '\'' +
                ", goodcode='" + goodcode + '\'' +
                ", buynum=" + buynum +
                ", codes=" + codes +
                '}';
    }

    public detailmodel() {
    }


    public detailmodel(long id, long orderid, string goodname, string goodcode, integer buynum, list<codemodel> codes) {
        this.id = id;
        this.orderid = orderid;
        this.goodname = goodname;
        this.goodcode = goodcode;
        this.buynum = buynum;
        this.codes = codes;
    }

    public long getid() {
        return id;
    }

    public void setid(long id) {
        this.id = id;
    }

    public long getorderid() {
        return orderid;
    }

    public void setorderid(long orderid) {
        this.orderid = orderid;
    }

    public string getgoodname() {
        return goodname;
    }

    public void setgoodname(string goodname) {
        this.goodname = goodname;
    }

    public string getgoodcode() {
        return goodcode;
    }

    public void setgoodcode(string goodcode) {
        this.goodcode = goodcode;
    }

    public integer getbuynum() {
        return buynum;
    }

    public void setbuynum(integer buynum) {
        this.buynum = buynum;
    }

    public list<codemodel> getcodes() {
        return codes;
    }

    public void setcodes(list<codemodel> codes) {
        this.codes = codes;
    }
}

  • codemodel :
package com.ph.excel.vo;

import com.ph.excel.annotation.iexcel;

/**
 * @classname: codemodel
 * @description: todo
 * @date: 2023/6/2 14:31
 * @author: ph9527
 * @version: 1.0
 */
public class codemodel {

    private  long id;
    private long detailid;
    @iexcel(name = "追溯码",isnotblank = true)
    private string code;

    @override
    public string tostring() {
        return "codemodel{" +
                "id=" + id +
                ", detailid=" + detailid +
                ", code='" + code + '\'' +
                '}';
    }

    public codemodel() {
    }

    public codemodel(long id, long detailid, string code) {
        this.id = id;
        this.detailid = detailid;
        this.code = code;
    }

    public long getid() {
        return id;
    }

    public void setid(long id) {
        this.id = id;
    }

    public long getdetailid() {
        return detailid;
    }

    public void setdetailid(long detailid) {
        this.detailid = detailid;
    }

    public string getcode() {
        return code;
    }

    public void setcode(string code) {
        this.code = code;
    }
}

b :测试读取excel

读取用到的excel为:

c :测试读取的代码

    /**
     * 读取excel测试
     *
     * @return
     */

    @getmapping("/read")
    public jsonobject readexcel() throws filenotfoundexception {
        jsonobject rs = new jsonobject();
        file file = new file("d:\\ph\\desktop\\test.xlsx");
        fileinputstream inputstream = new fileinputstream(file);
        //读取数据
        list<ordermodel> orders = iexcelutils.readexcel(inputstream, file.getname(), ordermodel.class);
        //获取因必填项没填写,未读取的数据信息
        list<iexcelutils.blankrowinfo> errrowinfos = iexcelutils.geterrrowinfo();

        rs.put("读取的数据orders", orders);
        rs.put("错误的数据errrowinfo", errrowinfos);

        return rs;
    }

d :读取excel的结果:

e:测试导出excel

我导出测试的数据直接读取的exel,下面是读取的excel图

f : 导出测试代码:

 /**
     * 导出测试
     * @param response
     * @throws exception
     */
    @getmapping("/export")
    public void export(httpservletresponse response) throws exception {
        //创建测试数据
        list<ordermodel> data = createexportdata();
        //导出excel
        iexcelutils.exportexcel("订单", "订单信息", response, data, ordermodel.class);
    }

g:导出结果:

因为对订单和明细排序了,所以"购买人"在excel第一列,"订单时间"在excel第二列

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com