Excel 导出数据库数据开发中很常见,也有一些封装好,快速使用的框架.例如easyExcel,easyPOI.所谓快速实现导出,都需要创建实体类,使用注解与数据库字段形成映射.但是一些数据库表字段不确定的数据表要实现导出,怎么快速实现(数据表不确定,没办法创建实体类.easyExcel,easyPOI没研究太深,个人感觉实现不了,有知道如何实现的欢迎交流).@传送门,门后有精彩
提供一个接口,实现数据库表数据导出生成Excel,并上传文件服务器AmazonS3,返回前端一个文件地址.
java中使用poi实现自定义excel文件的下载
Java中3种OutputStream转InputStream的方法
SpringBoot 2.1.2.RELEASE
JDK 1.8
Maven 3.5.0
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
<scope>compile</scope>
</dependency>
<!--S3依赖-->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.347</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.7.4</version>
</dependency>
ExportExcelUtil 和 ExportExcelXSSFUtil
package com.fang.industry.service.common.utils;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
/**
* @author: [email protected]
* @createDate: 2021/5/24 09:44
*/
public class ExportExcelXSSFUtil {
private XSSFWorkbook wb = null;
private XSSFSheet sheet = null;
public ExportExcelXSSFUtil(XSSFWorkbook wb, XSSFSheet sheet) {
this.wb = wb;
this.sheet = sheet;
}
/**
* 合并单元格后给合并后的单元格加边框
*
* @param region
* @param cs
*/
public void setRegionStyle(CellRangeAddress region, XSSFCellStyle cs) {
int toprowNum = region.getFirstRow();
for (int i = toprowNum; i <= region.getLastRow(); i++) {
XSSFRow row = sheet.getRow(i);
for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
XSSFCell cell = row.getCell(j);// XSSFCellUtil.getCell(row,
// (short) j);
cell.setCellStyle(cs);
}
}
}
/**
* 设置表头的单元格样式
*
* @return
*/
public XSSFCellStyle getHeadStyle() {
// 创建单元格样式
XSSFCellStyle cellStyle = wb.createCellStyle();
// 设置单元格的背景颜色为白色
cellStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(255,255,255)));
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 设置单元格水平居中对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER);
// 设置单元格垂直居中对齐
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 创建单元格内容显示不下时自动换行
cellStyle.setWrapText(true);
// 设置单元格字体样式
XSSFFont font = wb.createFont();
// 设置字体加粗
font.setBold(true);
font.setFontName("宋体");
font.setFontHeight((short) 500);
cellStyle.setFont(font);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
return cellStyle;
}
/**
* 设置表体的单元格样式
*
* @return
*/
public XSSFCellStyle getBodyStyle() {
// 创建单元格样式
XSSFCellStyle cellStyle = wb.createCellStyle();
// 设置单元格居中对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER);
// 设置单元格垂直居中对齐
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 创建单元格内容显示不下时自动换行
cellStyle.setWrapText(true);
// 设置单元格字体样式
XSSFFont font = wb.createFont();
// 设置字体
font.setFontName("宋体");
font.setFontHeight((short) 200);
cellStyle.setFont(font);
// 设置单元格边框为细线条
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
return cellStyle;
}
/**
* 设置表体的单元格样式
*
* @return
*/
public XSSFCellStyle getBodyStyleWithoutBorder() {
// 创建单元格样式
XSSFCellStyle cellStyle = wb.createCellStyle();
// 设置单元格居中对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER);
// 设置单元格垂直居中对齐
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 创建单元格内容显示不下时自动换行
cellStyle.setWrapText(true);
// 设置单元格字体样式
XSSFFont font = wb.createFont();
// 设置字体
font.setFontName("宋体");
font.setFontHeight((short) 200);
cellStyle.setFont(font);
return cellStyle;
}
}
package com.fang.industry.service.common.utils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import javax.servlet.ServletOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @author: [email protected]
* @createDate: 2021/5/24 09:44
*/
public class ExportExcelUtil {
/**
* 导出多标题的EXCEL
* @param titles
* @param list
* @param outputStream
*/
public static void ExportMultiHeadExcel(String[] titles, ArrayList<List<Object>> list, ServletOutputStream outputStream) {
// 创建一个workbook 对应一个excel应用文件
Workbook workBook = new XSSFWorkbook();
// 在workbook中添加一个sheet,对应Excel文件中的sheet
//Sheet名称,可以自定义中文名称
XSSFSheet sheet = (XSSFSheet) workBook.createSheet("Sheet1");
ExportExcelXSSFUtil exportUtil = new ExportExcelXSSFUtil((XSSFWorkbook) workBook, sheet);
XSSFCellStyle bodyStyle = exportUtil.getBodyStyle();
// 构建表头
XSSFRow headRow = sheet.createRow(0);
XSSFCell cell = null;
// 输出标题
for (int i = 0; i < titles.length; i++) {
//设置列宽
sheet.setColumnWidth(i, 4000);
//自动列宽
// sheet.autoSizeColumn(i,true);
cell = headRow.createCell(i);
cell.setCellStyle(bodyStyle);
cell.setCellValue(titles[i]);
}
// 构建表体数据
for (int j = 0; j < list.size(); j++) {
XSSFRow bodyRow = sheet.createRow(j + 1);
List<Object> rowList = list.get(j);
for (int k = 0; k < rowList.size(); k++) {
//设置列宽自适应
// sheet.autoSizeColumn(k,true);
cell = bodyRow.createCell(k);
cell.setCellStyle(bodyStyle);
cell.setCellValue(rowList.get(k)+"");
}
}
try {
workBook.write(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 导出单标题的EXCEL
* @param title
* @param list
* @param outputStream
*/
public static void ExportSingleHeadExcel(String title, ArrayList<List<Object>> list, ServletOutputStream outputStream) {
// 创建一个workbook 对应一个excel应用文件
Workbook workBook = new XSSFWorkbook();
// 在workbook中添加一个sheet,对应Excel文件中的sheet
//Sheet名称,可以自定义中文名称
XSSFSheet sheet = (XSSFSheet) workBook.createSheet("Sheet1");
ExportExcelXSSFUtil exportUtil = new ExportExcelXSSFUtil((XSSFWorkbook) workBook, sheet);
XSSFCellStyle headStyle = exportUtil.getHeadStyle();
XSSFCellStyle bodyStyle = exportUtil.getBodyStyle();
//构建表头
XSSFRow headRow = sheet.createRow(0);
XSSFCell cell = null;
//输出标题
//设置列宽
for (int i = 0; i < list.get(0).size(); i++) {
sheet.setColumnWidth(i, 4000);
}
//创建(0,0)单元格
cell = headRow.createCell(0);
cell.setCellStyle(headStyle);
cell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(
0,//第一行(基于0)
0,//最后一行(从0开始)
0,//第一列(基于0)
list.get(0).size()-1 //最后一列(基于0)
));
for (int j = 0; j < list.size(); j++) {
XSSFRow bodyRow = sheet.createRow(j + 1);
List<Object> rowList = list.get(j);
for (int k = 0; k < rowList.size(); k++) {
//设置列宽自适应
sheet.autoSizeColumn(k,true);
cell = bodyRow.createCell(k);
cell.setCellStyle(bodyStyle);
cell.setCellValue(rowList.get(k)+"");
}
}
try {
workBook.write(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 导出单标题的EXCEL
* @param title
* @param excelData
* @param outputStream
*/
public static void ExportSingleHeadExcel(String title, String[][] excelData, ServletOutputStream outputStream) {
// 创建一个workbook 对应一个excel应用文件
Workbook workBook = new XSSFWorkbook();
// 在workbook中添加一个sheet,对应Excel文件中的sheet
//Sheet名称,可以自定义中文名称
XSSFSheet sheet = (XSSFSheet) workBook.createSheet("Sheet1");
ExportExcelXSSFUtil exportUtil = new ExportExcelXSSFUtil((XSSFWorkbook) workBook, sheet);
XSSFCellStyle headStyle = exportUtil.getHeadStyle();
XSSFCellStyle bodyStyle = exportUtil.getBodyStyle();
//构建表头
XSSFRow headRow = sheet.createRow(0);
headRow.setHeight((short)600);
XSSFCell cell = null;
//设置列宽
for (int i = 0; i < excelData[0].length; i++) {
sheet.setColumnWidth(i, 4000);
}
//创建(0,0)单元格
cell = headRow.createCell(0);
cell.setCellStyle(headStyle);
cell.setCellValue(title);
//合并单元格
sheet.addMergedRegion(new CellRangeAddress(
0,//第一行(基于0)
0,//最后一行(从0开始)
0,//第一列(基于0)
excelData[0].length-1 //最后一列(基于0)
));
for (int j = 1; j < excelData.length; j++) {
XSSFRow bodyRow = sheet.createRow(j);
for (int k = 0; k < excelData[j].length; k++) {
cell = bodyRow.createCell(k);
cell.setCellStyle(bodyStyle);
cell.setCellValue(excelData[j][k]+"");
}
}
try {
workBook.write(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 导出无标题的EXCEL
* @param list
* @param outputStream
*/
public static OutputStream ExportSingleHeadExcel(ArrayList<List<Object>> list, ByteArrayOutputStream outputStream) {
// 创建一个workbook 对应一个excel应用文件
Workbook workBook = new XSSFWorkbook();
// 在workbook中添加一个sheet,对应Excel文件中的sheet
//Sheet名称,可以自定义中文名称
XSSFSheet sheet = (XSSFSheet) workBook.createSheet("Sheet1");
//构建表头
XSSFRow headRow = sheet.createRow(0);
XSSFCell cell = null;
//输出标题
//设置列宽
for (int i = 0; i < list.get(0).size(); i++) {
sheet.setColumnWidth(i, 4000);
}
cell = headRow.createCell(0);
List<Object> objects = list.get(0);
for (int p = 0; p < objects.size(); p++) {
cell = headRow.createCell(p);
cell.setCellValue(objects.get(p)+"");
}
for (int j = 1; j < list.size(); j++) {
XSSFRow bodyRow = sheet.createRow(j);
List<Object> rowList = list.get(j);
for (int k = 0; k < rowList.size(); k++) {
cell = bodyRow.createCell(k);
cell.setCellValue(rowList.get(k)+"");
}
}
try {
workBook.write(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return outputStream;
}
/**
* 导出无标题的EXCEL
* @param list
* @param outputStream
*/
public static OutputStream ExportSingleHeadExcelAddStyle(ArrayList<List<Object>> list, ByteArrayOutputStream outputStream) {
// 创建一个workbook 对应一个excel应用文件
Workbook workBook = new XSSFWorkbook();
// 在workbook中添加一个sheet,对应Excel文件中的sheet
//Sheet名称,可以自定义中文名称
XSSFSheet sheet = (XSSFSheet) workBook.createSheet("Sheet1");
ExportExcelXSSFUtil exportUtil = new ExportExcelXSSFUtil((XSSFWorkbook) workBook, sheet);
XSSFCellStyle headStyle = exportUtil.getHeadStyle();
XSSFCellStyle bodyStyle = exportUtil.getBodyStyle();
//构建表头
XSSFRow headRow = sheet.createRow(0);
XSSFCell cell = null;
//输出标题
//设置列宽
for (int i = 0; i < list.get(0).size(); i++) {
sheet.setColumnWidth(i, 4000);
}
cell = headRow.createCell(0);
cell.setCellStyle(headStyle);
List<Object> objects = list.get(0);
for (int p = 0; p < objects.size(); p++) {
sheet.autoSizeColumn(p,true);
cell = headRow.createCell(p);
cell.setCellStyle(headStyle);
cell.setCellValue(objects.get(p)+"");
}
for (int j = 1; j < list.size(); j++) {
XSSFRow bodyRow = sheet.createRow(j);
List<Object> rowList = list.get(j);
for (int k = 0; k < rowList.size(); k++) {
//设置列宽自适应
sheet.autoSizeColumn(k,true);
cell = bodyRow.createCell(k);
cell.setCellStyle(bodyStyle);
cell.setCellValue(rowList.get(k)+"");
}
}
try {
workBook.write(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return outputStream;
}
}
可以根据自己的需求改进这两个工具类
注:ExportExcelUtil中前几个方法对单元格,excel的样式做了美化.在数据量多的情况下,会影响导出效率(5000条数据需要差不多1分钟多钟),如果在不要求单元格样式的情况下,可以不做优化,类似下图中的方法
@Override
public DtoResponse<DataExcelDto> downloadData(DataIdBo bo) {
DtoResponse<DataExcelDto> result=new DtoResponse<DataExcelDto>();
if(bo.getTenantId()==null){
return result.failure(ApiExceptionEnum.PARAM_IS_BLANK.code(),
"tenantId不能为空");
}
if (bo.getTenantId().toString().length() != TableUtil.TENANT_ID_SIZE) {
return result.failure(ApiExceptionEnum.PARAM_IS_INVALID.code(),
"tenantId错误");
}
if(bo.getAppId()==null){
return result.failure(ApiExceptionEnum.PARAM_IS_BLANK.code(),
"AppId不能为空");
}
if(bo.getId()==null){
return result.failure(ApiExceptionEnum.PARAM_IS_BLANK.code(),
"Id不能为空");
}
try {
DataExcel dataExcel = appDataService.getDataExcelDetails(bo);
if (dataExcel==null){
return null;
}
/**
*Excel中的数据(表头+表体)
*
* dataExcelDetails中的每个list都是Excel中的每一行
* dataExcelDetails中第一个为表头list
* 第2个开始,每个list对应每行数据
*/
ArrayList<List<Object>> dataExcelDetails = dataExcel.getDataBody();
/**
*流转换
*/
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ExportExcelUtil.ExportSingleHeadExcel(dataExcelDetails, byteArrayOutputStream);
ByteArrayInputStream swapStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
StringBuilder keyName = new StringBuilder();
keyName.append(fileUrlPrefix);
keyName.append(UUID.randomUUID().toString()).append(".xlsx");
S3Utils.uploadStreamToS3(swapStream, keyName.toString());
DataExcelDto dto = new DataExcelDto();
dto.setDataName(dataExcel.getDataName());
dto.setDataUrl(keyName.toString());
return result.success(dto);
}catch (Exception e){
return result.failure(0,"下载异常");
}
}
Excel导出是将Workbook写进输出流(outputStream)中,文件上传是需要输入流.所以需要将流进行转换.大致方式为3种
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ExportExcelUtil.ExportSingleHeadExcel(dataExcelDetails, byteArrayOutputStream);
ByteArrayInputStream swapStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
不可以直接使用,要加自己的配置
package com.fang.industry.service.common.utils;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class S3Utils {
/**
* 【你的 access_key】
*/
private static final String AWS_ACCESS_KEY = "";
/**
* 【你的 aws_secret_key】
*/
private static final String AWS_SECRET_KEY = "";
/**
* 【你 bucket 的名字】 # 首先需要保证 s3 上已经存在该存储桶
*/
private static final String bucketName = "";
/**
*
*/
private static final String ENDPOINT = "";
private static AmazonS3 s3Client;
//静态块:初始化S3的连接对象s3Client! 需要3个参数:AWS_ACCESS_KEY,AWS_SECRET_KEY,AWS_REGION
static {
AWSCredentials awsCredentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
//注意:因为是本地方式,访问相应的S3文件系统,所以signingRegion可以默认为空。
s3Client = AmazonS3ClientBuilder.standard().enablePathStyleAccess()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(ENDPOINT, ""))
.build();
//测试是否连接上去S3
// System.out.println("||| 【list all buckets:】: " + s3Client.listBuckets() + "\n");
}
// public static void main(String[] args) throws IOException {
// String inputPath = "E:/地图.xlsx";
// String outputPath = "E:/地图do.xlsx";
//
// uploadStreamToS3(new FileInputStream(inputPath), "apass/test/asd2.xlsx");
// downloadFromS3("apass/test/asd.xlsx",outputPath);
// }
/**
* 上传本地文件到AWS S3
*
* @param tempFile
* @param keyName
* @throws IOException
*/
public static void uploadToS3WithPublicRead(File tempFile, String keyName) throws IOException {
if (tempFile.exists() && tempFile.isFile()) {
try {
PutObjectRequest request = new PutObjectRequest(bucketName, keyName, tempFile);
s3Client.putObject(request);
s3Client.setObjectAcl(bucketName, keyName, CannedAccessControlList.PublicRead);
} catch (AmazonServiceException ase) {
ase.printStackTrace();
} catch (AmazonClientException ace) {
ace.printStackTrace();
}
}
}
public static void uploadDirToS3WithPublicRead(File dir, String keyName) throws IOException {
if (dir.exists() && dir.isDirectory()) {
File[] files = dir.listFiles();
for (File f : files) {
StringBuffer key = new StringBuffer(keyName);
key.append("/").append(f.getName());
if (f.isDirectory()) {
uploadDirToS3WithPublicRead(f, key.toString());
} else {
uploadToS3WithPublicRead(f, key.toString());
}
}
}
}
/**
* 下载相应的S3数据到本地文件系统
*
* @param key
* @param targetFilePath
*/
public static void downloadFromS3(String key, String targetFilePath) {
S3Object object = s3Client.getObject(new GetObjectRequest(bucketName, key));
if (object != null) {
InputStream input = null;
FileOutputStream fileOutputStream = null;
byte[] data = null;
try {
//获取文件流
input = object.getObjectContent();
data = new byte[input.available()];
int len = 0;
fileOutputStream = new FileOutputStream(targetFilePath);
while ((len = input.read(data)) != -1) {
fileOutputStream.write(data, 0, len);
}
} catch (IOException e) {
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
}
}
if (input != null) {
try {
input.close();
} catch (IOException e) {
}
}
}
}
}
/**
* 上传文件流到AWS S3
*
* @param inputStream
* @param keyName
* @throws IOException
*/
public static void uploadStreamToS3(InputStream inputStream, String keyName) throws IOException {
try {
PutObjectRequest request = new PutObjectRequest(bucketName, keyName, inputStream,null);
s3Client.putObject(request);
s3Client.setObjectAcl(bucketName, keyName, CannedAccessControlList.PublicRead);
} catch (AmazonServiceException ase) {
ase.printStackTrace();
} catch (AmazonClientException ace) {
ace.printStackTrace();
}finally {
inputStream.close();
}
}
/**
* 获取文件流
*
* @param key
*/
public static InputStream downloadStreamFromS3(String key) {
S3Object object = s3Client.getObject(new GetObjectRequest(bucketName, key));
if (object != null) {
return object.getObjectContent();
}else{
return null;
}
}
}