背景
app导出excel,读取excel,可能不常见,但是你得会。
环境
win10,11
jdk8+
as4+
引入
本次实战中,使用到了三方库 net.sourceforge.jexcelapi
详细的引入如下(gradle):
implementation group: 'net.sourceforge.jexcelapi', name: 'jxl', version: '2.6.12'
文末将会放出全部代码
开发
这里已经引入了jxl的三方库,该库可以实现excel的读写操作。
这里,主要实现的是,导出数据生成excel表,读取execl表的数据。
首先我们要有一个概念,就是excel表内部构造,是现有一个sheet,再有具体的内容!!!
所以,在生成excel表后,第一步,就是创建一个sheet,然后再在这个sheet里面进行数据操作!
其实细心一点就会发现,格式是通用的,如下图:
第一行,一般情况下,都是属性的描述,然后第二行,就是数据的填充,诸如此类。
那么,是不是可以设计一个通用的数据格式,就行数据的通用读写?
博主这里选择的,是一个List<HashMap<String,String>>这样的数据格式,List是对于某个sheet中的所有数据,而HashMap中的key,就是属性,value就是对应的属性值。在填充内容第一行时,做一下特殊处理,就可以把属性写入了,后续只需要index对齐,即可填充全部数据。
上面的思路,是比较通用的,注意一下数组越界的情况即可!
好了,梳理了内容填充的思路,还有一个sheet创建,其实也是大同小异的,进行循环创建即可!
上核心代码
首先,先有sheet再有内容,第一步,就是创建sheet,代码如下:
可以看到,有个api就是createSheet,这个方法,就是创建一个表的意思。
创建完表了,那么,就要利用这个WritableSheet对象,进行表数据的写入了。
代码如下:
这里的逻辑,就是先插入第一行属性数据,后续再插入内容数据,for循环操作,当然有review空间,这里只是基于功能快速实现写的逻辑,实测可以使用!!!
通过上述的写sheet,写内容,那么,就会把全部的数据写到excel表了?其实还有几个坑,只有做过才会发现!
(1)Workbook的write()调用时机问题
如果同一个Workbook多次调用该方法,实测发现,第一次以后,就不会再写入了,直观现象就是,写入的部分逻辑失效,然后代码调用WorkBook.Close方法,会报错。
(2)写入数据时,格式的设置问题
示例代码如下:
sheet.addCell(new Label(col, positionCounter, headInfo.get(col), wcf));
其中wcf就是单元格的格式,测试发现,如果不设置单元格格式,写入会没有内容
以上,就是导出excel的一些流程和注意的坑,下面再说说,读取excel的一些逻辑
其实如果你实现了导出,同样的,是不是导入数据,也是按照导出数据时候的数据处理,就可以了?没错,这里直接上核心代码:
try {
is = new FileInputStream(path);
workbook = Workbook.getWorkbook(is);
//读取excel有多少个表
Sheet[] sheets = workbook.getSheets();
if (sheets == null || sheets.length == 0) {
return new ArrayList<>();
}
//单个单元格
Cell cell;
List<ExcelInfoBean> result = new ArrayList<>();
List<String> headList = new ArrayList<>();
for (int s = 0; s < sheets.length; s++) {
Sheet sheetCache = sheets[s];
String sheetName = sheetCache.getName();
//获取所有单元格里面的数据
ExcelInfoBean exportBean = new ExcelInfoBean(sheetName, new ArrayList<>());
int cols = sheetCache.getColumns();
int rows = sheetCache.getRows();
//逐行获取
List<HashMap<String, String>> contentList = new ArrayList<>();
for (int r = 0; r < rows; r++) {
HashMap<String, String> contentHashMap = new HashMap<>();
for (int c = 0; c < cols; c++) {
cell = sheetCache.getCell(c, r);
String content = cell.getContents();
if (r == 0) {
//头部数据
headList.add(content);
} else {
//非头部数据
contentHashMap.put(headList.get(c), content);
}
}
if (r != 0) {
contentList.add(contentHashMap);
}
}
exportBean.setData(contentList);
result.add(exportBean);
}
return result;
}
本质上,就是获取这个WorkBook,所有表sheet的数量,然后变量sheets,再从sheet中,读取行,列的数据,再写入到你的内存数据中,就可以了!
下面是所有相关的代码:
ExcelInfoBean.class
public class ExcelInfoBean implements Serializable {
//sheet名字--与数据对象名字一致
private String sheetTitle;
//key属性名,value属性值--excel头,excel值
private List<HashMap<String, String>> data = new ArrayList<>();
public ExcelInfoBean(@NonNull String sheetTitle, List<HashMap<String, String>> data) {
this.sheetTitle = sheetTitle;
this.data = data;
}
public String getSheetTitle() {
return sheetTitle;
}
public void setSheetTitle(String sheetTitle) {
this.sheetTitle = sheetTitle;
}
public List<HashMap<String, String>> getData() {
return data;
}
public void setData(List<HashMap<String, String>> data) {
this.data = data;
}
}
ExcelUtils.class
public class ExcelUtils implements Serializable {
private static final WritableCellFormat wcf;
static {
WritableFont wf = new WritableFont(WritableFont.createFont("宋体"), 12,
WritableFont.NO_BOLD, false);
wcf = new WritableCellFormat(wf);
try {
wcf.setAlignment(jxl.format.Alignment.CENTRE);// 左右居中
wcf.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);// 上下居中
// wcf.setBorder(Border.ALL, BorderLineStyle.THIN); // 设置边框
// wcf.setWrap(true); // 是否换行;
} catch (WriteException e) {
e.printStackTrace();
}
}
private static class SingleHolder implements Serializable {
public final static ExcelUtils mInstance = new ExcelUtils();
}
public static ExcelUtils getInstance() {
return SingleHolder.mInstance;
}
/**
* 生成excel
*
* @param beans 一个对象,对应一个表格
* @param fileAllPath 文件全路径--如/ddd/dd/
*/
public boolean exportData(String fileAllPath, String fileName, ExcelInfoBean... beans) {
if (beans == null || beans.length == 0) {
return true;
}
//数据处理
OutputStream os = null;
WritableWorkbook wwb = null;
try {
File file = new File(fileAllPath);
if (!file.exists()) {
file.mkdirs();
}
os = new FileOutputStream(file.getAbsoluteFile() + File.separator + fileName);
wwb = Workbook.createWorkbook(os);
for (int i = 0; i < beans.length; i++) {
ExcelInfoBean cacheInfo = beans[i];
//开始处理数据
String sheetName = cacheInfo.getSheetTitle();
//建立表
WritableSheet sheet = wwb.createSheet(sheetName, i);
List<HashMap<String, String>> contentList = cacheInfo.getData();
if (contentList != null && !contentList.isEmpty()) {
//写入数据
//第一行为属性头
List<String> headInfo = new ArrayList<>();
HashMap<String, String> headMap = contentList.get(0);
for (Map.Entry<String, String> mapCache : headMap.entrySet()) {
headInfo.add(mapCache.getKey());
}
int positionCounter = 0;
if (!headInfo.isEmpty()) {
for (int col = 0; col < headInfo.size(); col++) {
sheet.addCell(new Label(col, positionCounter, headInfo.get(col), wcf));
}
//写入表头
positionCounter += 1;
}
//写入内容
for (int c = 0; c < contentList.size(); c++) {
HashMap<String, String> contentMap = contentList.get(c);
if (contentMap != null && !contentMap.isEmpty()) {
for (int col = 0; col < headInfo.size(); col++) {
String headInfoCache = headInfo.get(col);
//通过表头,获取数据
String contentValue = contentMap.get(headInfoCache);
//写入到对应的位置
sheet.addCell(new Label(col, positionCounter, contentValue, wcf));
}
positionCounter += 1;
}
}
}
}
//至此写入
wwb.write();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (wwb != null) {
try {
wwb.close();
} catch (IOException | WriteException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
* 读取excel
*/
public List<ExcelInfoBean> importData(@NonNull String path) {
File file = new File(path);
if (!file.exists()) {
return new ArrayList<>();
}
//读取excel
InputStream is = null;
Workbook workbook = null;
try {
is = new FileInputStream(path);
workbook = Workbook.getWorkbook(is);
//读取excel有多少个表
Sheet[] sheets = workbook.getSheets();
if (sheets == null || sheets.length == 0) {
return new ArrayList<>();
}
//单个单元格
Cell cell;
List<ExcelInfoBean> result = new ArrayList<>();
List<String> headList = new ArrayList<>();
for (int s = 0; s < sheets.length; s++) {
Sheet sheetCache = sheets[s];
String sheetName = sheetCache.getName();
//获取所有单元格里面的数据
ExcelInfoBean exportBean = new ExcelInfoBean(sheetName, new ArrayList<>());
int cols = sheetCache.getColumns();
int rows = sheetCache.getRows();
//逐行获取
List<HashMap<String, String>> contentList = new ArrayList<>();
for (int r = 0; r < rows; r++) {
HashMap<String, String> contentHashMap = new HashMap<>();
for (int c = 0; c < cols; c++) {
cell = sheetCache.getCell(c, r);
String content = cell.getContents();
if (r == 0) {
//头部数据
headList.add(content);
} else {
//非头部数据
contentHashMap.put(headList.get(c), content);
}
}
if (r != 0) {
contentList.add(contentHashMap);
}
}
exportBean.setData(contentList);
result.add(exportBean);
}
return result;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (workbook != null) {
try {
workbook.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return new ArrayList<>();
}
}
that's all----------------------------------------------------------------------------------------------