Excel导出

  • 定义数据模型

参考财付通的批量提现Excel的格式,定义模型如下

    private int recordId; //提现id
private String cname; //提现人名称
private String cbank; //提现银行的code
private String cnum; //提现卡号
private int money; //提现金额
private int type = 1; //类别
private String comment = "现金提现"; //备注
  • 定义接口IExcelExport
package cn.daimaniu.blog.poi;

import java.util.List;

public interface IExcelExport<T> {
/**
* 获取Excel的Header
*
* @return
*/
String[] getHeader(); /**
* 返回Excel的header大小
*
* @return
*/
int getHeaderSize(); /**
* 导出的标题
*
* @return
*/
String getTitle(); /**
* 是否包含 特殊的Field的处理
*
* @param filedName
* @return
*/
boolean containSpecialField(String filedName); /**
* 获取 特殊的Field的处理后的值
*
* @param filedName
* @return
*/
String getSpecialFieldValue(String filedName); /**
* 获取数据源
*
* @return
*/
List<T> getPoiList(); /**
* 设置数据源
*/
void setPoiList(List<T> data);
}

接口主要定义了model的set和get,生成文件名称,excel第一行的标题定义

  • 实现接口 RecordExport
package cn.daimaniu.blog.poi.impl;

import cn.daimaniu.blog.poi.IExcelExport;
import cn.daimaniu.blog.poi.model.RecordPoi;
import org.apache.commons.lang.StringUtils; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; public class RecordExport implements IExcelExport<RecordPoi> {
List<RecordPoi> poiList = new ArrayList<>();
private String title;
String[] headers = {"序号", "收款人姓名", "银行名称", "银行卡号", "付款金额", "到账方式", "备注"}; public String[] getHeader() {
return headers;
} public int getHeaderSize() {
return headers.length;
} public String getTitle() {
if (StringUtils.isEmpty(title)) {
return formatDate(new Date(), "yyyy-MM-dd_HH-mm-ss") + "-提现记录.xls";
} else {
return title;
}
} private String formatDate(Date date, String format) {
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
return dateFormat.format(date);
} public boolean containSpecialField(String filedName) {
return false;
} public String getSpecialFieldValue(String filedName) {
return null;
} public List<RecordPoi> getPoiList() {
return this.poiList;
} public void setPoiList(List<RecordPoi> data) {
this.poiList = data;
}
}
  • ExcelUtil工具类
    public static <T> void export(IExcelExport<T> excelExport, OutputStream out, String pattern) {
//读取配置
String[] headers = excelExport.getHeader();
Collection<T> dataset = excelExport.getPoiList();
if (dataset == null || dataset.isEmpty()) {
//空数据 直接退出
return;
}
// 声明一个工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
// 生成一个表格
HSSFSheet sheet = workbook.createSheet(excelExport.getTitle());
// 设置表格默认列宽度为15个字节
sheet.setDefaultColumnWidth(15);
// 生成一个样式
HSSFCellStyle style = workbook.createCellStyle();
// 设置这些样式
style.setFillForegroundColor(HSSFColor.WHITE.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 生成一个字体
HSSFFont font = workbook.createFont();
font.setColor(HSSFColor.BLACK.index);
font.setFontHeightInPoints((short) 12);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
style.setFont(font);
// 生成并设置另一个样式
HSSFCellStyle style2 = workbook.createCellStyle();
style2.setFillForegroundColor(HSSFColor.WHITE.index);
style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 生成另一个字体
HSSFFont font2 = workbook.createFont();
font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
// 把字体应用到当前的样式
style2.setFont(font2);
// 声明一个画图的顶级管理器
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
// 产生表格标题行
HSSFRow row = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
} // 遍历集合数据,产生数据行
Iterator<T> it = dataset.iterator();
int index = 0;
while (it.hasNext()) {
index++;
row = sheet.createRow(index);
T t = it.next();
// 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
Field[] fields = t.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style2);
Field field = fields[i];
String fieldName = field.getName();
String getMethodName = "get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
try {
Class tCls = t.getClass();
Method getMethod = tCls.getMethod(getMethodName,
new Class[]{});
Object value = getMethod.invoke(t, new Object[]{});
// 判断值的类型后进行强制类型转换
String textValue = null;
if (excelExport.containSpecialField(fieldName)) {
textValue = excelExport.getSpecialFieldValue(fieldName);
} else if (value instanceof Date) {
Date date = (Date) value;
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
textValue = sdf.format(date);
} else if (value instanceof Long) {
Date date = new Date((Long) value);
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
textValue = sdf.format(date);
} else if (value instanceof byte[]) {
// 有图片时,设置行高为60px;
row.setHeightInPoints(60);
// 设置图片所在列宽度为80px,注意这里单位的一个换算
sheet.setColumnWidth(i, (short) (35.7 * 80));
// sheet.autoSizeColumn(i);
byte[] bsValue = (byte[]) value;
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,
1023, 255, (short) 6, index, (short) 6, index);
anchor.setAnchorType(2);
patriarch.createPicture(anchor, workbook.addPicture(
bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
// 其它数据类型都当作字符串简单处理
if (value == null) {
textValue = "";
} else {
textValue = value.toString();
}
}
// 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
if (textValue != null) {
Pattern p = Pattern.compile("^//d+(//.//d+)?$");
Matcher matcher = p.matcher(textValue);
if (matcher.matches()) {
// 是数字当作double处理
cell.setCellValue(Double.parseDouble(textValue));
} else {
HSSFRichTextString richString = new HSSFRichTextString(
textValue);
HSSFFont font3 = workbook.createFont();
font3.setColor(HSSFColor.BLACK.index);
richString.applyFont(font3);
cell.setCellValue(richString);
}
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
// 清理资源
}
}
}
try {
workbook.write(out);
} catch (IOException e) {
e.printStackTrace();
}
}

导出类,传入IExcelExport接口(泛型),允许使用不同Model的Export实现,实现不同数据源的导出。

export方法 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值,通过excelExport.containSpecialField 判断是否需要 自定义字段的特殊处理。其它的Style Font的设置可参考官方文档。

  • 执行数据测试

mvn test -Dtest=ExcelTest#TestExcel

测试将执行一个模拟数据的导出功能,并将导出的Excel重新解析 并打印出来。

导出效果:

 
cnbj-excel-export@2x.png

Excel导入

  • 定义接口IExcelConsumer
public interface IExcelConsumer {
/**
* 消费excel sheet
*
* @param sheet
*/
void consume(Sheet sheet);
}
  • 实现消费接口RecordComsumer
package cn.daimaniu.blog.poi.impl.consumer;

import cn.daimaniu.blog.poi.IExcelConsumer;
import cn.daimaniu.blog.poi.model.RecordPoi;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet; import java.util.ArrayList;
import java.util.List; public class RecordComsumer implements IExcelConsumer {
@Override
public void consume(Sheet sheet) {
List<RecordPoi> recordPois = new ArrayList<>();
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
if (i % 500 == 0) {
//在这里 处理 提取出来的数据
// recordPoiMapper.batchInsert(recordPois);
System.out.println("Excel解析出 size:" + recordPois.size() + "recordPois:" + recordPois.toString());
recordPois = null;
recordPois = new ArrayList<>();
}
Row row = sheet.getRow(i);
RecordPoi recordPoi = new RecordPoi(); recordPoi.setRecordId(Integer.parseInt(row.getCell(0).getStringCellValue()));
recordPoi.setCname(row.getCell(1).getStringCellValue());
recordPoi.setCbank(row.getCell(2).getStringCellValue());
recordPoi.setCnum(row.getCell(3).getStringCellValue());
recordPoi.setMoney(Integer.parseInt(row.getCell(4).getStringCellValue()));
recordPoi.setType(Integer.parseInt(row.getCell(5).getStringCellValue()));
recordPoi.setComment(row.getCell(6).getStringCellValue()); recordPois.add(recordPoi);
}
if (recordPois != null && recordPois.size() > 0) {
//在这里 处理 500除余,提取出来的数据
// recordPoiMapper.batchInsert(recordPois);
System.out.println("Excel解析出 size:" + recordPois.size() + "recordPois:" + recordPois.toString());
recordPois = null;
}
}
}

消费类只要依次读取Excel Row的Column数据,重写到Model对象中即可。

Notice:在Excel导入过程中,一定要注意数据的有效性判断,比如Null,数据格式判断(Text,String,numeric,Date的区别...)

后台导入导出Excel的更多相关文章

  1. Vue结合后台导入导出Excel问题详解后续

    接前几天写的一篇博客  https://www.cnblogs.com/ttjm/p/11307462.html 在ie浏览器测试发现打不开,经调查问题如下 1 如果在本地开发调试,请求接口报错如下 ...

  2. Vue结合后台导入导出Excel问题详解

    话不多说,直接上前端代码 axios({ method: 'post', url: 'http://localhost:19090/exportUser',//这个是请求的地址 params: {// ...

  3. thinkphp导入导出excel表单数据

    在PHP项目经常要导入导出Excel表单. 先去下载PHPExcel类库文件,放到相应位置. 我在thinkphp框架中的位置为ThinkPHP/Library/Org/Util/ 导入 在页面上传e ...

  4. php中导入导出excel的原理

    在php中我们要经常导入导出excel文件,方便后台管理.那么php导入和导出excel的原理到底是什么呢?excel分为两大版本excel2007(后缀.xlsx).excel2003(后缀.xls ...

  5. .NET导入导出Excel

    若是开发后台系统,ASP.NET MVC中总是涉及了很多导入导出Excel的问题,有的时候处理起来比较烦 如果能使用以下代码解决,就完美了 public class ReportModel { [Ex ...

  6. NPOI导入导出Excel

    .net mvc利用NPOI导入导出excel 注意:如何导出的提交方式ajax导出是失效的! 解决方案是:js处理l两个表单的提交  代码:  第一步. 在页面里面加入2个隐藏的iframe, 如下 ...

  7. ASP.NET Core使用EPPlus导入导出Excel

    开发过程中,经常会遇到导入导出数据的需求,本篇博客介绍在.NET Core中如何使用EPPlus组件导入导出Excel EPPlus: EPPlus是使用Open Office XML格式(xlsx) ...

  8. Vue框架下实现导入导出Excel、导出PDF

    项目需求:开发一套基于Vue框架的工程档案管理系统,用于工程项目资料的填写.编辑和归档,经调研需支持如下功能: Excel报表的导入.导出 PDF文件的导出 打印表格 经过技术选型,项目组一致决定通过 ...

  9. uniapp导入导出Excel

    众所周知,uniapp作为跨端利器,有诸多限制,其中之一便是vue页面不支持传统网页的dom.bom.blob等对象. 所以,百度上那些所谓的导入导出excel的方法,大部分都用不了,比如xlsx那个 ...

随机推荐

  1. Python中的WebSocket

    一.Websockets介绍 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信 ...

  2. CF715E Complete the Permutations(第一类斯特林数)

    题目 CF715E Complete the Permutations 做法 先考虑无\(0\)排列的最小花费,其实就是沿着置换交换,花费:\(n-\)环个数,所以我们主要是要求出规定环的个数 考虑连 ...

  3. XAMPP安装指南

    首先下载一个安装包 按照默认选项,依次安装: 去掉不必要的选项: 选择安装路径: 显示下图说明已经成功安装完成了. 打开XAMPP,启动Apache服务: 如果显示Apache服务无法启动,有如下错误 ...

  4. sql 加密解密函数

    if object_ID ( 'fn_ACITEncryption' ) is not null      drop function fn_ACITEncryption  go    create  ...

  5. spring security使用哈希加密的密码

    之前我们都是使用MD5 Md5PasswordEncoder 或者SHA ShaPasswordEncoder 的哈希算法进行密码加密,在spring security中依然使用只要指定使用自定义加密 ...

  6. Matlab绘图基础——图形绘制的插值  以及 图像大小的重采样

    使用说明:图形绘制时的插值 interp1   %1-D data interpolation interpft  %使用fft算法插值     %将原数据x转换到频率域,再逆转换回来更密集的数据采样 ...

  7. LeetCode——Sum of Two Integers

    LeetCode--Sum of Two Integers Question Calculate the sum of two integers a and b, but you are not al ...

  8. flume-ng源码阅读memory-channel(原创)

    org.apache.flume.channel.MemoryChannel类是Flume-NG的memory-channel. private LinkedBlockingDeque<Even ...

  9. 第一章 Burp Suite 安装和环境配置

    Burp Suite是一个集成化的渗透测试工具,它集合了多种渗透测试组件,使我们自动化地或手工地能更好的完成对web应用的渗透测试和攻击.在渗透测试中,我们使用Burp Suite将使得测试工作变得更 ...

  10. SPOJ - LCS2

    后缀自动机板子题 https://vjudge.net/problem/28017/origin 找多串的最长公共子串 //#pragma comment(linker, "/stack:2 ...