前言:
不知道小伙伴们有没有遇见过“要识别excel里的插件对象”的需求。一般情况来说,在软件项目开发的过程中这种需求一般不常见,因为在excel里面的内容完全可以通过线上来提交,比如使用form表单等形式来进行数据录入。但是在线下处理一些材料、数据等可能会遇到这样的问题。
我的这个需求就是线下遇到的,也并不是软件项目开发中的需求(附带讲:项目中的这种功能完全没有必要存在,因为实现这种需求的方式太有针对性了,还并不能保证它的正确性。总之,这种功能完全就是出力不讨好的典型)
问题描述:
问题背景是这样的,我们要做一个数据分析模型,然后甲方需要提供分析数据,将一个个excel数据表转化为一个一条条记录的记录表好用作模型分析。最后就是提供给我们的数据表是含带插件对象的excel表,因为之前没有读取过excel的插件对象,让我以为这种插件对象完全读取不了。后经查看文章发现有一种方式是可以读取的,可以依靠这种方式实现数据读取。
注:在这里要感谢一下前辈的这篇文章“在Java中的Apache POI读取Excel的复选框值(Reading Excel checkbox values in Java Apache POI)”
下面给出实现经过和方式:
我们先来看下复选框或单选框长得什么样:
我们要做的就是要识别excel中,选择的是男或女、是或否。
目前只能通过代码实现对选择框的选中判断,返回true或false,以此来做识别判断
所需jar包:
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
识别代码如下:
package com.yzw.exceldemo.excel;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
/**
* @author yzw
*/
public class ExcelObject {
private static final String Workbook = "Workbook";
public static void readCheckbox(String path) {
FileInputStream file = null;
InputStream istream = null;
try {
file = new FileInputStream(new File(path));
POIFSFileSystem poifs = new POIFSFileSystem(file);
istream = poifs.createDocumentInputStream(Workbook);
HSSFRequest req = new HSSFRequest();
req.addListenerForAllRecords(new EventExample());
HSSFEventFactory factory = new HSSFEventFactory();
factory.processEvents(req, istream);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if (file != null)
file.close();
if (istream != null)
istream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
/**
* 写个main方法来做一个测试
* @param args
*/
public static void main(String[] args) {
System.out.println("ReadExcelFile");
//此处为我使用的一个线程用来存储每次复选框的识别列表(目前不需要)
ObjectList.setCurrentFlag(new ArrayList());
System.out.println("ReadCheckbox");
readCheckbox("C:\\Users\\Administrator\\Desktop\\复选框测试.xls");
}
}
然后,我们还需要写一个类来实现HSSFListener类,并重写processRecord方法,代码如下:
package com.yzw.exceldemo.excel;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SubRecord;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author yzw
*/
public class EventExample implements HSSFListener {
private final static Pattern P = Pattern.compile("\\[sid=0x000A.+?\\[0(\\d),");
@Override
public void processRecord(Record record) {
switch (record.getSid()) {
case ObjRecord.sid:
ObjRecord objRec = (ObjRecord) record;
List<SubRecord> subRecords = objRec.getSubRecords();
for (SubRecord subRecord : subRecords) {
if (!(subRecord instanceof CommonObjectDataSubRecord)) {
Matcher m = P.matcher(subRecord.toString());
if (m.find()) {
String checkBit = m.group(1);
if (checkBit.length() == 1) {
boolean checked = "1".equals(checkBit);
ObjectList.getCurrentFlag().add(checked);
System.out.println(ObjectList.getCurrentFlag().size()+"--------"+checked+"-----------"+checkBit);
}
}
}
}
break;
default:
break;
}
}
}
然后运行上面的main方法做一个测试,打印测试结果:
然后我们变动一下单选框,如下:
再次运行main方法,打印结果:
基于此,我们可以得出对应关系如下:
1----对应----男(true)
2----对应----女(true)
3----对应----是(true)
4----对应----否(true)
注意:我们在使用这种方式时,一定要注意对应关系,尤其是复选框或单选框较多时。
接下来我来贴出ObjectList类的实现,其实还是有很多方法来实现存储当前的识别列表集合:
package com.yzw.exceldemo.excel;
import java.util.List;
/**
* @author yzw
* 使用一个线程对当前的数据进行一个存储
*/
public class ObjectList {
private static ThreadLocal currentUser = new ThreadLocal();
public static void setCurrentFlag(List t) {
currentUser.set(t);
}
public static List getCurrentFlag() {
return (List) currentUser.get();
}
public static void removeCurrentFlag() {
currentUser.remove();
}
}
注意:在当前使用完后,一定要记得清除List的数据。
当前方式只支持xls格式的excel,如需要将xlsx文件转为xls文件的则可以参照 使用宏将xlsx格式文件批量转为xls格式文件 这篇文章
关于excel的读取和写入这里就不进行展示了,网上一大堆。
好了,小伙伴们!只要能获取到识别结果,那么接下来的实现方式就不需要在展示了吧。