前言
EasyExcel的知识点记录及使用;
提供自己学习
一、EasyExcel是什么?
1、概述:
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
2、案例分析
2.1 导入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
<exclusions>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
</exclusions>
</dependency>
2.2 读excel数据到内存中
2.2.1 代码一
public AjaxResult importData(MultipartFile file) throws Exception {
//配置excel分析监听器
ExcelListener excelListener = new ExcelListener(tbClueService);
//读取excel表格数据
EasyExcel.read(file.getInputStream(), TbClueExcelVo.class, excelListener).sheet().doRead();
return AjaxResult.success(excelListener.getResult());
}
分析
(1)格式:
- 配置excel分析监听器
ExcelListener excelListener = new ExcelListener(tbClueService);
因为监听器不是单例的,每次读取一条数据就会创建一个监听器对象,所有不能交给spring管理,
所以一般会提供监听器(ExcelListener )的有参构造方法,由此传入需要使用的service层的接口,
该接口的实现类为单例,被spring管理,只能通过此方法传入。
- 读取 excel表格数据
// 在读的时候只需要new ExcelListener 监听器传入就行了
EasyExcel.read(file.getInputStream(), TbClueExcelVo.class, new ExcelListener())
// 需要读取批注 默认不读取
.extraRead(CellExtraTypeEnum.COMMENT)
// 需要读取超链接 默认不读取
.extraRead(CellExtraTypeEnum.HYPERLINK)
// 需要读取合并单元格信息 默认不读取
.extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
这个框架底层使用了建造者模式,每次读取一条数据,也就将一条数据封装到一个对象中(并且每次创
建一个excel分析监听器对象和数据对象)
(2)excel监听器代码
package com.huike.clues.utils.easyExcel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.huike.clues.domain.dto.ImportResultDTO;
import com.huike.clues.domain.vo.TbClueExcelVo;
import com.huike.clues.service.ITbClueService;
/**
* EasyExcel监听器,用于解析数据并执行操作
*/
public class ExcelListener extends AnalysisEventListener<TbClueExcelVo> {
/**
* 利用构造方法获取对应的service
*/
public ITbClueService clueService;
private ImportResultDTO resultDTO;
//每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>();
/**
* 提供带参构造方法,在这里需要通过构造方法的方式获取对应的service层
* 谁调用这个监听器谁提供需要的service
* 原因:(ExcelListener这个类不能交给spring管理,因为每次读取一条数据都需要new
* ExcelListener这个对象和数据对象)
* @param clueService
*/
public ExcelListener(ITbClueService clueService) {
this.clueService = clueService;
this.resultDTO = new ImportResultDTO();
}
/**
* 每解析一行数据都要执行一次
* 每条都执行一次插入操作
* @param data
* @param context
*/
@Override
public void invoke(TbClueExcelVo data, AnalysisContext context) {
//对于每一条数据的处理
list.add(data);
// 在这里可以做一些其他的操作 就考自己去拓展了
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 当所有数据都解析完成后会执行
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
// 当然也可以有很多其他操作 比如有些需要触发其他的 可以在这里调用
saveData();
}
// 读取条额外信息:批注、超链接、合并单元格信息等
@Override
public void extra(CellExtra extra, AnalysisContext context) {
LOGGER.info("读取到了一条额外信息:{}", JSON.toJSONString(extra));
switch (extra.getType()) {
case COMMENT:
LOGGER.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),
extra.getText());
break;
case HYPERLINK:
if ("Sheet1!A1".equals(extra.getText())) {
LOGGER.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
extra.getColumnIndex(), extra.getText());
} else if ("Sheet2!A1".equals(extra.getText())) {
LOGGER.info(
"额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
+ "内容是:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex(), extra.getText());
} else {
Assert.fail("Unknown hyperlink!");
}
break;
case MERGE:
LOGGER.info(
"额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex());
break;
default:
}
}
//在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
@Override
public void onException(Exception exception, AnalysisContext context) {
// 如果是某一个单元格的转换异常 能获取到具体行号
// 如果要获取头的信息 配合invokeHeadMap使用
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex());
}
}
/**
* 返回结果集对象
* @return
*/
public ImportResultDTO getResult(){
return resultDTO;
}
}
分析监听器AnalysisEventListener< T>
AnalysisEventListener< T>继承了 ReadListener ,我们一般使用它的父接口
public interface ReadListener<T> extends Listener {
//在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。
//如果这里不抛出异常则 继续读取下一行。
void onException(Exception var1, AnalysisContext var2) throws Exception;
// 调用invokeHeadMap来获取表头数据
void invokeHead(Map<Integer, CellData> var1, AnalysisContext var2);
// 一行行读取表格内容(每一条数据解析都会调用)
void invoke(T var1, AnalysisContext var2);
//读取条额外信息:批注、超链接、合并单元格信息等
void extra(CellExtra var1, AnalysisContext var2);
// 当数据全部解析完后,此方法会执行
void doAfterAllAnalysed(AnalysisContext var1);
//验证是否还有数据
boolean hasNext(AnalysisContext var1);
}
2.3 将数据写入excel中
(1)创建每条数据对应的数据对象
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}
(2)上代码
/**
* 最简单的写
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 直接写即可
*/
@Test
public void simpleWrite() {
// 写法1
String fileName = TestFileUtil.getPath() + "simpleWrite" +
System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板
//然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
// 写法2
fileName = TestFileUtil.getPath() + "simpleWrite" +
System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(data(), writeSheet);
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
以下是poi导入导出excel的代码(工具类)
package org.common.util;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFDataFormat;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.foreveross.common.exception.UdpBootException;
import org.foreveross.common.param.TemplateExportParamsExtend;
import org.framework.poi.excel.annotation.Excel;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @description: poi util
*/
@Slf4j
public class PoiUtil {
private final static String EXCEL2003 = "xls";
private final static String EXCEL2007 = "xlsx";
/**
* @description: 根据word模版生成word文件
* @param: [url(模版文件类路径), fileName(要传回给浏览器的文件名称), params]
* @return: void
* @version: 1.0
*/
public static void exportWordByTemplate(String url, String fileName, Map params) throws Exception {
HttpServletResponse response = getResponse(MediaType.APPLICATION_OCTET_STREAM_VALUE, fileName);
OutputStream outputStream = response.getOutputStream();
ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
InputStream resourceAsStream = defaultClassLoader.getResourceAsStream(url);
ParseWord07Extend parseWord07Extend = new ParseWord07Extend();
XWPFDocument xwpfDocument = parseWord07Extend.parseWord(resourceAsStream, params);
xwpfDocument.write(outputStream);
outputStream.flush();
}
/**
* @description: 根据word模版生成word文件 并返回流
* @param: [url(模版文件类路径), fileName(要传回给浏览器的文件名称), params]
* @return: void
* @version: 1.0
*/
public static OutputStream createWordByTemplateReturnOutputStream(String url, Map params) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
InputStream resourceAsStream = defaultClassLoader.getResourceAsStream(url);
Asserts.notNull(resourceAsStream,"未找到模板文件:"+url);
ParseWord07Extend parseWord07Extend = new ParseWord07Extend();
XWPFDocument xwpfDocument = parseWord07Extend.parseWord(resourceAsStream, params);
xwpfDocument.write(outputStream);
return outputStream;
}
/**
* @description: 文件下载
* @param: [url(模版文件类路径), fileName(要传回给浏览器的文件名称), params]
* @return: void
* @version: 1.0
*/
public static void exportFile(String url, String fileName) throws Exception {
log.info("附件转换成流:{},{}",url,fileName);
HttpServletResponse response = getResponse(MediaType.APPLICATION_OCTET_STREAM_VALUE, fileName);
OutputStream outputStream = response.getOutputStream();
URL urlObject = new URL(url);
//生产环境ssl解决
HttpURLConnection conn = (HttpURLConnection) urlObject.openConnection();
if (conn instanceof HttpsURLConnection) {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
((HttpsURLConnection) conn).setSSLSocketFactory(sc.getSocketFactory());
((HttpsURLConnection) conn).setHostnameVerifier(new TrustAnyHostnameVerifier());
}
conn.connect();
InputStream inputStream = conn.getInputStream();
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
outputStream.write(bs, 0, len);
}
outputStream.flush();
}
/**
* @description: 根据模版导出excel
* @param: [url(模版地址填写类路径), fileName(要返回的文件名)
* , entitys(数据), paramMap(参数), pojo(数据类型)]
* @return: void
* @version: 1.0
*/
public static void exportExcelByTemplate(String url, String fileName, List<Object> entitys,Map<String,Object> paramMap,Class pojo) throws Exception {
HttpServletResponse response = getResponse(MediaType.APPLICATION_OCTET_STREAM_VALUE, fileName);
ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
InputStream resourceAsStream = defaultClassLoader.getResourceAsStream(url);
TemplateExportParamsExtend templateExportParams = new TemplateExportParamsExtend();
templateExportParams.setTemplateInputStream(resourceAsStream);
templateExportParams.setHeadingRows(2);
ExcelExportOfTemplateExtensUtil excelExportOfTemplateUtil = new ExcelExportOfTemplateExtensUtil();
Workbook workbook = excelExportOfTemplateUtil.createExcleByTemplate(templateExportParams, pojo, entitys, paramMap);
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
}
/**
* @description: 根据模版导出excel
* @param: [url(模版地址填写类路径), fileName(要返回的文件名)
* , entitys(数据), paramMap(参数), pojo(数据类型)]
* @return: void
* @version: 1.0
*/
public static void exportExcelByTemplateExtends(String url, String fileName, List<Object> entitys,Map<String,Object> paramMap,
Class pojo,TemplateExportParamsExtend templateExportParams) throws Exception {
HttpServletResponse response = getResponse(MediaType.APPLICATION_OCTET_STREAM_VALUE, fileName);
ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
InputStream resourceAsStream = defaultClassLoader.getResourceAsStream(url);
templateExportParams.setTemplateInputStream(resourceAsStream);
ExcelExportOfTemplateExtensUtil excelExportOfTemplateUtil = new ExcelExportOfTemplateExtensUtil();
Workbook workbook = excelExportOfTemplateUtil.createExcleByTemplate(templateExportParams, pojo, entitys, paramMap);
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
}
/**
* 导出excel
* @param list 数据集合
* @param cls 导出表头
*/
public static <T> void exportExcel(OutputStream outputStream ,List<T> list, Class<T> cls,List<String> ignoreFields) {
//获取表头
Field[] fields = cls.getDeclaredFields();
List<Field> fieldList = Arrays.stream(fields)
.filter(field -> {
if(!CollectionUtils.isEmpty(ignoreFields) && ignoreFields.contains(field.getName())){
return false;
}
//获取标记@Excel注解的字段
Excel annotation = field.getAnnotation(Excel.class);
if (annotation != null) {
field.setAccessible(true);
return true;
}
return false;
}).collect(Collectors.toList());
//创建excel
Workbook wb = new XSSFWorkbook();
//创建sheet
Sheet sheet = wb.createSheet("Sheet1");
AtomicInteger ai = new AtomicInteger();
{
Row row = sheet.createRow(ai.getAndIncrement());
AtomicInteger aj = new AtomicInteger();
//写入
fieldList.forEach(field -> {
Excel annotation = field.getAnnotation(Excel.class);
String columnName = "";
if (annotation != null) {
columnName = annotation.name();
}
Cell cell = row.createCell(aj.getAndIncrement());
//设置样式
CellStyle cellStyle = wb.createCellStyle();
//内容居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cell.setCellStyle(cellStyle);
cell.setCellValue(columnName);
});
}
if (!list.isEmpty()){
list.forEach(t->{
Row row1 = sheet.createRow(ai.getAndIncrement());
AtomicInteger aj = new AtomicInteger();
fieldList.forEach(field -> {
Class<?> type = field.getType();
Object value = "";
try {
value = field.get(t);
} catch (Exception e) {
e.printStackTrace();
}
Cell cell = row1.createCell(aj.getAndIncrement());
if (value != null) {
cell.setCellValue(value.toString());
}
});
});
}
try {
wb.write(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @description: 根据邀请函模版生成PDF文件
* @param: [url, params]
* @return: java.io.InputStream
* @version: 1.0
*/
public static OutputStream createPDFByTemplate(String url,Map params) throws Exception{
ClassPathResource classPathResource = new ClassPathResource(url);
InputStream fiKeyFile = classPathResource.getInputStream();
//
PdfReader reader = new PdfReader(fiKeyFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
/* 将要生成的目标PDF文件名称 */
PdfStamper ps = new PdfStamper(reader, bos);
PdfContentByte under = ps.getUnderContent(1);
/* 使用中文字体 */
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();
fontList.add(bf);
/* 取出报表模板中的所有字段 */
AcroFields fields = ps.getAcroFields();
fields.setSubstitutionFonts(fontList);
fillData(fields,params);
/* 必须要调用这个,否则文档不会生成的 */
ps.setFormFlattening(true);
ps.close();
// 转换流
bos.close();
return bos;
}
/**
* @description: 模版填充
* @param: [fields, data]
* @return: void
* @version: 1.0
*/
public static void fillData(AcroFields fields, Map<String, String> data)
throws IOException, DocumentException {
for (String key : data.keySet()) {
String value = data.get(key);
fields.setField(key, value); // 为字段赋值,注意字段名称是区分大小写的
}
}
/**
* @description: 转换流
* @param: [out]
* @return: java.io.ByteArrayInputStream
* @version: 1.0
*/
public static ByteArrayInputStream parse(OutputStream out) throws Exception {
ByteArrayOutputStream baos = null;
baos = (ByteArrayOutputStream) out;
ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
return swapStream;
}
/**
* 上传excel文件转化实体类
* @param file
* @param cls
* @return
* @throws Exception
*/
public static <T> List<T> readExcel(MultipartFile file, Class<T> cls) throws Exception {
String fileName = file.getOriginalFilename();
if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
throw new UdpBootException("上传文件格式不正确:" + fileName) ;
}
InputStream is = file.getInputStream();
return readExcel(is, cls, fileName);
}
/**
* 导出excel
* @param response HttpServletResponse
* @param list 数据集合
* @param cls 导出表头
* @param name 文件名
*/
public static <T> void exportExcel(HttpServletResponse response, List<T> list, Class<T> cls, String name){
//获取表头
Field[] fields = cls.getDeclaredFields();
List<Field> fieldList = Arrays.stream(fields)
.filter(field -> {
//获取标记@Excel注解的字段
Excel annotation = field.getAnnotation(Excel.class);
if (annotation != null) {
field.setAccessible(true);
return true;
}
return false;
}).collect(Collectors.toList());
//创建excel
Workbook wb = new XSSFWorkbook();
//创建sheet
Sheet sheet = wb.createSheet("Sheet1");
AtomicInteger ai = new AtomicInteger();
{
Row row = sheet.createRow(ai.getAndIncrement());
AtomicInteger aj = new AtomicInteger();
//写入
fieldList.forEach(field -> {
Excel annotation = field.getAnnotation(Excel.class);
String columnName = "";
if (annotation != null) {
columnName = annotation.name();
}
Cell cell = row.createCell(aj.getAndIncrement());
//设置样式
CellStyle cellStyle = wb.createCellStyle();
//内容居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cell.setCellStyle(cellStyle);
cell.setCellValue(columnName);
});
}
if (!list.isEmpty()){
//时间样式
CellStyle cellStyle = wb.createCellStyle();
XSSFDataFormat format = (XSSFDataFormat) wb.createDataFormat();
cellStyle.setDataFormat(format.getFormat("yyyy/MM/dd"));
list.forEach(t->{
Row row1 = sheet.createRow(ai.getAndIncrement());
AtomicInteger aj = new AtomicInteger();
fieldList.forEach(field -> {
Class<?> type = field.getType();
Object value = "";
try {
value = field.get(t);
} catch (Exception e) {
e.printStackTrace();
}
Cell cell = row1.createCell(aj.getAndIncrement());
if (value != null) {
if (type == Date.class){
cell.setCellStyle(cellStyle);
cell.setCellValue((Date) value);
}else {
cell.setCellValue(value.toString());
}
}
});
});
}
String excelName = name +".xlsx";
buildExcelDocument(excelName,wb,response);
}
private static HttpServletResponse getResponse(String contentType,String fileName) throws UnsupportedEncodingException {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
HttpServletResponse response = servletRequestAttributes.getResponse();
response.setContentType(contentType);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
return response;
}
private static final String WORD_CONTENT_TYPE = "application/msword";
private static final String EXCEL_CONTENT_TYPE = "application/excel";
/**
* 浏览器下载excel
* @param fileName
* @param wb
* @param response
*/
private static void buildExcelDocument(String fileName, Workbook wb, HttpServletResponse response){
try {
response.reset();
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
response.flushBuffer();
wb.write(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* excel文件流转化实体类
* @param is
* @param cls
* @param fileName
* @return
*/
private static <T> List<T> readExcel(InputStream is, Class<T> cls, String fileName) {
List<T> dataList = new ArrayList<>();
Workbook workbook = null;
try {
if (fileName.endsWith(EXCEL2007)) {
workbook = new XSSFWorkbook(is);
}
if (fileName.endsWith(EXCEL2003)) {
workbook = new HSSFWorkbook(is);
}
if (workbook != null) {
Map<String, List<Field>> classMap = new HashMap<>();
List<Field> fields = Stream.of(cls.getDeclaredFields()).collect(Collectors.toList());
fields.forEach(
field -> {
Excel annotation = field.getAnnotation(Excel.class);
//获取实体字段
if (annotation != null) {
String columnsName = annotation.name();
if (StringUtils.isBlank(columnsName)) {
return;
}
if (!classMap.containsKey(columnsName)) {
classMap.put(columnsName, new ArrayList<>());
}
field.setAccessible(true);
classMap.get(columnsName).add(field);
}
}
);
Map<Integer, List<Field>> reflectionMap = new HashMap<>(16);
//默认读取第一个sheet
Sheet sheet = workbook.getSheetAt(0);
boolean firstRow = true;
for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
//提取Excel表头
if (firstRow) {
for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell);
if (classMap.containsKey(cellValue)) {
reflectionMap.put(j, classMap.get(cellValue));
}
}
firstRow = false;
} else {
if (row == null) {
continue;
}
//判断是否为空白行
Boolean allBlank = PoiUtil.isEmptyRow(row, classMap.size());
if (allBlank) {
continue;
}
T t = cls.newInstance();
for (int j = 0; j < classMap.size(); j++) {
if (reflectionMap.containsKey(j)) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell);
if (StringUtils.isNotBlank(cellValue)) {
allBlank = false;
}
List<Field> fieldList = reflectionMap.get(j);
for (Field x : fieldList) {
Excel annotation = x.getAnnotation(Excel.class);
String columnName = annotation.name();
try {
handleField(t, cellValue, x);
} catch (Exception e) {
log.error(String.format("reflect field:%s value:%s exception!", columnName, cellValue), e);
throw new Exception(String.format("字段:%s 转换异常 转化值为%s,位于第%s行%s列", columnName,cellValue, i + 1, j + 1));
}
}
}
}
dataList.add(t);
}
}
}
} catch (Exception e) {
log.error(String.format("parse excel exception!"), e);
throw new UdpBootException(e.getMessage());
}
return dataList;
}
/**
* 读取cell的内容
* @param cell
* @return
*/
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
if (HSSFDateUtil.isCellDateFormatted(cell)) {
return HSSFDateUtil.getJavaDate(cell.getNumericCellValue()).toString();
} else {
return new BigDecimal(cell.getNumericCellValue()).toString();
}
} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
return StringUtils.trimToEmpty(cell.getStringCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
return StringUtils.trimToEmpty(cell.getCellFormula());
} else if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
return "";
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
return String.valueOf(cell.getBooleanCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
return "ERROR";
} else {
return cell.toString().trim();
}
}
/**
* 判断是否为空白行
* @param row
* @param num
* @return
*/
private static Boolean isEmptyRow(Row row, int num) {
Boolean re = true;
for (int j = 0; j < num; j++) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell);
if (StringUtils.isNotBlank(cellValue)) {
re = false;
break;
}
}
return re;
}
/**
* 写入数据到实例中
* @param t
* @param value
* @param field
* @param <T>
* @throws Exception
*/
private static <T> void handleField(T t, String value, Field field) throws Exception {
Class<?> type = field.getType();
if (type == null || type == void.class || StringUtils.isBlank(value)) {
return;
}
if (type == Object.class) {
field.set(t, value);
//数字类型
} else if (type.getSuperclass() == null || type.getSuperclass() == Number.class) {
if (type == int.class || type == Integer.class) {
field.set(t, NumberUtils.toInt(value));
} else if (type == long.class || type == Long.class) {
field.set(t, NumberUtils.toLong(value));
} else if (type == byte.class || type == Byte.class) {
field.set(t, NumberUtils.toByte(value));
} else if (type == short.class || type == Short.class) {
field.set(t, NumberUtils.toShort(value));
} else if (type == double.class || type == Double.class) {
field.set(t, NumberUtils.toDouble(value));
} else if (type == float.class || type == Float.class) {
field.set(t, NumberUtils.toFloat(value));
} else if (type == char.class || type == Character.class) {
field.set(t, CharUtils.toChar(value));
} else if (type == boolean.class) {
field.set(t, BooleanUtils.toBoolean(value));
} else if (type == BigDecimal.class) {
field.set(t, new BigDecimal(value));
}
} else if (type == Boolean.class) {
field.set(t, BooleanUtils.toBoolean(value));
} else if (type == Date.class) {
//
Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
Pattern compile = Pattern.compile("\\d{4}/\\d{2}/\\d{2}");
Pattern newest = Pattern.compile("\\d{4}\\d{2}\\d{2} \\d{2}:\\d{2}:\\d{2}");
Matcher matcher = pattern.matcher(value);
if( matcher.matches() ){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
field.set(t, sdf.parse(value));
} else if (compile.matcher(value).matches()) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
field.set(t, sdf.parse(value));
} else if (newest.matcher(value).matches()) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
field.set(t, sdf.parse(value));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.US);
field.set(t, sdf.parse(value));
}
} else if (type == String.class) {
field.set(t, value);
} else {
Constructor<?> constructor = type.getConstructor(String.class);
field.set(t, constructor.newInstance(value));
}
}
public static InputStream exportFileReturnInputStream(String url, String fileName) throws Exception {
log.info("附件转换成流:{},{}", url, fileName);
URL urlObject = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlObject.openConnection();
if (conn instanceof HttpsURLConnection) {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom());
((HttpsURLConnection) conn).setSSLSocketFactory(sc.getSocketFactory());
((HttpsURLConnection) conn).setHostnameVerifier(new TrustAnyHostnameVerifier());
}
conn.connect();
return conn.getInputStream();
}
}