平常项目中经常会需要导出excel
如果需要导出的列很多的话,可能要花费很长的时间
本文章通过jxl和poi实现根据数据库表字段及其注释动态生成excel模板,并导出表数据导excel
其实也可以只用jxl,具体可以根据本文稍作修改
【maven依赖】
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-core</artifactId>
<version>1.0.3</version>
</dependency>
首先通过sql查询出表的字段和注释,之后使用poi(也可以使用jxl)根据字段和注释创建excel,注释作为列标题,字段名可作为参数,用于最后导出数据
<select id="selectTableColumn" parameterType="java.util.Map" resultType="java.util.Map">
show full columns from ${tableName};
</select>
查询结果

编辑
【controller】根据之前的sql查询出来一个map,然后通过POIUtil.createTemp()方法生成excel模板文件(方法在后面有)
然后将表数据查出来,本文中的方法gastrointestinalStromalService.selectList(params)根据id集合查询所需要导出的数据,这个替换成自己的查询语句就行,比如select * from tablename。
之后将查询出来的数据放入map中,并传入jxl的 transformer.transformXLS();方法。
@RequestMapping("/excel")
public void exportExcel(HttpServletResponse response, String ids) {
FileInputStream fis = null;
ServletOutputStream out = null;
try {
Map<String, Object> params = new HashMap<>();
//设置数据库表名
params.put("tableName", "gastrointestinal_stromal");
String fileName = UUID.randomUUID() + ".xlsx";
String path = filePath + "export" + File.separator + fileName;
//根据数据库表生成excel模板
POIUtil.createTemp(path, baseTableService.selectTableColumn(params));
//根据id查询要导出的数据
params.put("ids", ids.split(","));
List<Map<String, Object>> formDatas = gastrointestinalStromalService.selectList(params);
//添加导出参数
Map<String, Object> cMap = new HashMap();
cMap.put("vms", formDatas);
//响应流设置
String currntTime = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
response.reset();
response.setContentType("application" + File.separator + "vnd.ms-excel"); //下载文版类型
String exportFileName = "导出" + currntTime;
response.addHeader("Content-Disposition", "attachment;filename=" + new String(exportFileName.getBytes("gb2312"), "ISO8859-1") + ".xlsx");
//生成的临时导出文件
File destFile = File.createTempFile(filePath + "export" + File.separator + UUID.randomUUID(), ".xlsx");
// 开始转换。利用 transformer 转到Excel
XLSTransformer transformer = new XLSTransformer();
// 参数:srcFilePath:模板源文件 cMap:需要导出的数据 destFile.getAbsolutePath():下载的目标文件
transformer.transformXLS(path, cMap, destFile.getAbsolutePath());
//写入响应流
fis = new FileInputStream(destFile);
out = response.getOutputStream();
byte[] bytes = new byte[512];
int i = 0;
while ((i = fis.read(bytes)) != -1) {
out.write(bytes, 0, i);
}
//删除临时文件
new File(path).delete();
destFile.delete();
} catch (Exception e) {
logger.error("{}导出表单excel异常:{}", Constans.ERRO_LOG, e);
} finally {
//释放资源
try {
out.close();
} catch (IOException e) {
logger.error("{}导出表单excel异常:{}", Constans.ERRO_LOG, e);
}
try {
fis.close();
} catch (IOException e) {
logger.error("{}导出表单excel异常:{}", Constans.ERRO_LOG, e);
}
}
}
部分循环使用JDK8的新特性, AtomicInteger用于计数,线程安全,在foreach循环中不能使用a++进行计数
将comment字放到excel第一行中,并过滤掉没注释的字段
"<jx:forEach items = \"${vms}\" var=\"data\">"是excel模板的表达式,放到第二行,意思是遍历我们传入的vms参数,后面可以使用data.的方式获取数据
将字段名拼接成表达式 "${data."+stringObjectMap.get("Field")+"}"。放到第三行
最后对循环进行闭合"</jx:forEach>"。放最后一行
public static String createTemp(String path,List<Map<String,Object>> maps) throws IOException {
// 1. 创建一个工作薄
XSSFWorkbook workbook = new XSSFWorkbook();
// 创建一个目录和文件名
FileOutputStream out = new FileOutputStream(new File(path));
// 2. 创建一个工作表
XSSFSheet spreadsheet = workbook.createSheet("Sheet1");
// 单元格样式
XSSFCellStyle style5 = workbook.createCellStyle();
style5.setAlignment(HorizontalAlignment.CENTER);
style5.setBorderBottom(BorderStyle.THICK);
style5.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style5.setBorderLeft(BorderStyle.THICK);
style5.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style5.setBorderRight(BorderStyle.THICK);
style5.setRightBorderColor(IndexedColors.BLACK.getIndex());
style5.setBorderTop(BorderStyle.THICK);
style5.setTopBorderColor(IndexedColors.BLACK.getIndex());
// 3. 创建一行
XSSFRow row = spreadsheet.createRow(0);
XSSFRow row2 = spreadsheet.createRow(2);
AtomicInteger cellid = new AtomicInteger(-1);
AtomicInteger cellid2 = new AtomicInteger();
maps.forEach(stringObjectMap -> {
String comment = stringObjectMap.get("Comment") + "";
if(StringUtils.isNotEmpty(comment)) {
spreadsheet.setColumnWidth(cellid.getAndIncrement(), comment.getBytes().length*2*256);
Cell cell = row.createCell(cellid.intValue());
// 设置单元格的值
cell.setCellValue(comment);
// 设置单元格样式
cell.setCellStyle(style5);
Cell cell2 = row2.createCell(cellid2.getAndIncrement());
cell2.setCellValue("${data."+stringObjectMap.get("Field")+"}");
}
});
XSSFCellStyle style6 = workbook.createCellStyle();
style6.setAlignment(HorizontalAlignment.CENTER);
XSSFRow row1 = spreadsheet.createRow(1);
Cell cell = row1.createCell(0);
cell.setCellValue("<jx:forEach items = \"${vms}\" var=\"data\">");
cell.setCellStyle(style6);
CellRangeAddress region = new CellRangeAddress(1, 1, 0, cellid.intValue());
spreadsheet.addMergedRegion(region);
XSSFRow row3 = spreadsheet.createRow(3);
Cell cell3 = row3.createCell(0);
cell3.setCellValue("</jx:forEach>");
// 输出
workbook.write(out);
out.close();
return path;
}
生成出来的excel模板

编辑
之后按照controller中的方法将数据传入生成出来的excel模板,即可导出表数据
导出效果图

编辑
转载请注明出处
浙公网安备 33010602011771号