1.官网
2.excel样式
3.代码
@slf4j public class dynamicimportlistener implements readlistener<map<integer, string>> { /** * 从哪一行开始读数据 */ private final int headrownumber; /** * 公司信息列 */ private final int companyinfonumber; /** * 数据列 */ private final int headnumber; private final map<integer, map<integer, string>> rawrowsmap = new hashmap<>(); private final list<cellextra> extramergeinfolist = new arraylist<>(); private final map<integer, string> headermap = new linkedhashmap<>(); private final navigablemap<integer, string> companyinfomap = new treemap<>(); public dynamicimportlistener(int headrownumber, int companyinfonumber, int headnumber) { this.headrownumber = headrownumber; this.companyinfonumber = companyinfonumber; this.headnumber = headnumber; } @override public void invoke(map<integer, string> rowmap, analysiscontext context) { int rowindex = context.readrowholder().getrowindex(); if (rowindex == companyinfonumber) { string company = rowmap.get(0); if (strutil.isnotblank(company)) { companyinfomap.put(rowindex, company.trim()); } } else if (rowindex == headnumber) { for (map.entry<integer, string> e : rowmap.entryset()) { string v = e.getvalue(); if (strutil.isnotblank(v)) { headermap.put(e.getkey(), v.trim()); } } }else { rawrowsmap.put(rowindex, rowmap); } } @override public void extra(cellextra extra, analysiscontext context) { if (extra.gettype() == cellextratypeenum.merge && extra.getfirstrowindex() >= headrownumber - 1) { extramergeinfolist.add(extra); } } @override public void doafterallanalysed(analysiscontext context) { log.info("读取完毕:数据总行 {},表头列 {},合并单元格 {} 条", rawrowsmap.size(), headermap.size(), extramergeinfolist.size()); } /** * 获取首条公司信息 */ public string getcompanyinfo() { return companyinfomap.isempty() ? null : companyinfomap.firstentry().getvalue(); } /** * 获取所有合并单元格元数据 */ public list<cellextra> getmergedregions() { return collections.unmodifiablelist(extramergeinfolist); } /** * 回填合并单元格数据 */ public void fillmergedcells() { if (extramergeinfolist.isempty()) return; for (cellextra extra : extramergeinfolist) { int r1 = extra.getfirstrowindex(); int r2 = extra.getlastrowindex(); int c1 = extra.getfirstcolumnindex(); string init = rawrowsmap.get(r1).get(c1); for (int rr = r1; rr <= r2; rr++) { map<integer, string> row = rawrowsmap.get(rr); if (row == null) continue; for (int cc = c1; cc <= extra.getlastcolumnindex(); cc++) { row.put(cc, init); } } } } /** * 构建 vo 列表,固定字段 + extrafields */ public <t> list<t> buildvolist(class<t> voclass) { list<t> result = new arraylist<>(); int headeridx = headnumber; int maxrow = rawrowsmap.keyset().stream().max(integer::compareto).orelse(headeridx); for (int idx = headeridx + 1; idx <= maxrow; idx++) { map<integer, string> rowmap = rawrowsmap.get(idx); if (rowmap == null) continue; try { t vo = voclass.getdeclaredconstructor().newinstance(); // 填充列 for (map.entry<integer, string> head : headermap.entryset()) { string headername = head.getvalue(); string cellval = rowmap.get(head.getkey()); string value = (cellval == null) ? "" : cellval.trim(); boolean matched = false; for (field f : voclass.getdeclaredfields()) { excelproperty prop = f.getannotation(excelproperty.class); if (prop != null && arrays.aslist(prop.value()).contains(headername)) { f.setaccessible(true); f.set(vo, converttype(f.gettype(), value)); matched = true; break; } } if (!matched) { method m = voclass.getmethod("getextrafields"); @suppresswarnings("unchecked") map<string, string> extra = (map<string, string>) m.invoke(vo); extra.put(headername, value); } } result.add(vo); } catch (exception e) { log.error("行 {} 构建 vo 失败: {}", idx + 1, e.getmessage()); } } return result; } /** * @param targettype 目标类型 * @param text 文本 * @return java.lang.object * @description 数据类型转换 * @author zhaohuaqing * @date 2025/6/26 11:42 */ private object converttype(class<?> targettype, string text) { if (text == null) { return null; } string trimmed = text.trim(); // 字符串 if (targettype == string.class) { return trimmed; } // 原生数字类型 if (targettype == integer.class || targettype == int.class) { return integer.valueof(trimmed); } if (targettype == long.class || targettype == long.class) { return long.valueof(trimmed); } if (targettype == double.class || targettype == double.class) { return double.valueof(trimmed); } if (targettype == float.class || targettype == float.class) { return float.valueof(trimmed); } if (targettype == short.class || targettype == short.class) { return short.valueof(trimmed); } if (targettype == byte.class || targettype == byte.class) { return byte.valueof(trimmed); } // bigdecimal if (targettype == bigdecimal.class) { return new bigdecimal(trimmed); } // 布尔 if (targettype == boolean.class || targettype == boolean.class) { // 支持 "true"/"false",也支持 "1"/"0" if ("1".equals(trimmed) || "0".equals(trimmed)) { return "1".equals(trimmed); } return boolean.valueof(trimmed); } // java 8 日期时间 if (targettype == localdate.class) { // 默认 iso 格式,或自定义 return localdate.parse(trimmed, datetimeformatter.iso_local_date); } if (targettype == localtime.class) { return localtime.parse(trimmed, datetimeformatter.iso_local_time); } if (targettype == localdatetime.class) { return localdatetime.parse(trimmed, datetimeformatter.ofpattern("yyyy-mm-dd hh:mm:ss")); } if (targettype == offsetdatetime.class) { return offsetdatetime.parse(trimmed, datetimeformatter.iso_offset_date_time); } if (targettype == zoneddatetime.class) { return zoneddatetime.parse(trimmed, datetimeformatter.iso_zoned_date_time); } // 旧版 java.util.date if (targettype == java.util.date.class) { try { // 你可以根据 excel 导出格式,调整 simpledateformat return new simpledateformat("yyyy-mm-dd hh:mm:ss").parse(trimmed); } catch (parseexception e) { throw new runtimeexception("日期解析失败: " + trimmed, e); } } return trimmed; } }
如何使用
@data @builder @allargsconstructor @noargsconstructor @accessors(chain = false) // 设置 chain = false,避免excel导入有问题 public class sopextractmdsavo { @excelproperty(value = "一级xxx") private string firstlevel; @excelproperty(value = "二级xxx") private string secondlevel; @excelproperty(value = "三级xxx") private string thirdlevel; @excelproperty(value = "xxx") private string formula; @excelproperty(value = "xxx") private string factor; @excelproperty(value = "xxx") private string referencevalue; @excelproperty(value = "xxx") private string element; @excelproperty(value = "xxx") private string scheme; @excelproperty(value = "超链接1") private string hyperlink1; @excelproperty(value = "超链接2") private string hyperlink2; @excelproperty(value = "超链接3") private string hyperlink3; /** * 动态列:所有未在 vo 明确定义的列 */ private map<string, string> extrafields = new linkedhashmap<>(); /** * 管控方案ids */ private string controlplanids; /** * 输出物ids */ private string outputmaterialids; /** * @return 非空的 hyperlink 列表 */ public list<string> nonblankhyperlinks() { list<string> list = new arraylist<>(10); if (strutil.isnotblank(hyperlink1)) list.add(hyperlink1); if (strutil.isnotblank(hyperlink2)) list.add(hyperlink2); if (strutil.isnotblank(hyperlink3)) list.add(hyperlink3); return list; } }
inputstream inputstream = file.getinputstream(); int headrownumber = 0; // 表头在 excel 的第 2 行(从 1 开始计) dynamicimportlistener listener = new dynamicimportlistener(headrownumber, 0, 1); // 1) 读数据、收集表头 & 合并单元格 & 公司信息 easyexcel.read(inputstream, listener) .extraread(cellextratypeenum.merge) .sheet("test") .headrownumber(headrownumber) .doread(); // 2) 外部拿公司信息 string company = listener.getcompanyinfo(); // 3) 回填合并单元格 listener.fillmergedcells(); // 4) 构建 vo 列表(包含固定字段 + extrafields) list<sopextractmdsavo> rows = listener.buildvolist(sopextractmdsavo.class);
到此这篇关于java easyexcel实现导入多sheet的excel的文章就介绍到这了,更多相关java easyexcel导入excel内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论