整体思路
客户在页面点击“导出Excel”链接-->>进入Java逻辑处理代码-->>复制Excel模版文件-->>向这个复制过的模版文件中写入List数据-->>把数据写入完成的Excel文件下载到客户端
适用场景
数据格式固定、需要把List数据导出到Excel文件的情况下
具体代码
1.页面链接
// 添加“导出Excel”链接
$("div#paddingDiv").append(
" <a href='exportStatisticsData.sp?dateStart="
+ $("#dateStartId").val() + "&dateEnd="
+ $("#dateEndId").val() + "&selectOrgan="
+ $("#selectOrgan").val() + "''>导出查询结果到Excel</a>");
2.SpringMVC的ModelAndView
<!-- 工作量报表,导出Excel的Action跳转 -->
<bean name="/exportStatisticsData.sp" class="com.peak.acc.action.ExportStatisticsAction">
<property name="commonDao">
<ref bean="commonDao" />
</property>
</bean>
try {
// 接下来,取出数据,进行页面显示
list = commonDao.getObjectListByArguments("queryStatisticsT", null);
// 将数据库查询出来的列表集,转成页面展示需要的格式,单独放在一个方法里
listShowInPage = exchangeToShowList(list, organString);
/**
* 最后展示到页面上的列表元素数量
*/
int rows = listShowInPage.size();
// 模版文件对象(模版在项目中有)
File templateFirst = null;
if (rows <= 2) {// 如果只有少于等于两行数据,就使用模版2
templateFirst = new File(request.getRealPath("/")
+ "upload/acc/template/Acc任务数量统计模版2.xls");
} else {// 否则,使用模版1
templateFirst = new File(request.getRealPath("/")
+ "upload/acc/template/Acc任务数量统计模版1.xls");
}
// 使用模版,生成Excel文件的目标路径
targetPath = "D:/acc_rm/Excel/createWhatYouWant/";
// 拷贝模版,生成一个新的文件,用于写入统计数据,使用UUID生成唯一文件名
String newFileName = targetPath + UUID.randomUUID().toString()
+ ".xls";
File newTargetFile = new File(targetPath);
// 若目录不存在,就创建一个
if (!newTargetFile.exists()) {
newTargetFile.mkdirs();
}
// 创建目标Excel文件,.xls格式的
newTargetFile = new File(newFileName);
// 调用静态方法copyFile()复制模版文件 到目标文件
AccFileUtil.copyFile(templateFirst, newTargetFile);
log.info("任务统计的写入文件准备就绪");
// 把数据,写入到目标文件
createTheTargetExcel(rows, newTargetFile);
// 附件名称
String filename = "会计标准化任务统计报表 " + startDate + " -- " + endDate
+ " " + organString + ".xls";
// 设置response的编码方式
response.setContentType("application/x-msdownload");
// 写明要下载的文件的大小
response.setContentLength((int) newTargetFile.length());
// 设置下载附件的文件名
response.setHeader("Content-Disposition", "attachment;filename="
+ new String(filename.getBytes("GBK"), "iso-8859-1"));
// 读出文件到i/o流
FileInputStream fis = new FileInputStream(newTargetFile);
byte[] b = new byte[1024];// 相当于我们的缓存
int k = 0;// 该值用于计算当前实际下载了多少字节
// 从response对象中得到输出流,准备下载
OutputStream myout = response.getOutputStream();
// 开始循环下载
while (-1 != (k = fis.read(b, 0, b.length))) {
// 将b中的数据写到客户端的内存
myout.write(b, 0, k);
}
// 将写入到客户端的内存的数据,刷新到磁盘
myout.flush();
myout.close();
} catch (Exception e) {
log
.info("ExportExcel ------------------任务数量统计查询转换出现错误--------------------------:"
+ e.getMessage());
e.printStackTrace();
} finally {
// 清空列表所占有的内存
clearAllList();
// 最后,检查一下目录下的文件个数,大于100的话,就进行清空
deleteDirFiles(targetPath, 100);
}
// 展示,这里无需返回视图
return null;
public static void copyFile(File sourceFile, File targetFile)
throws IOException {
BufferedInputStream bufIS = null;
BufferedOutputStream bufOS = null;
try {
// 带缓冲的输入流
bufIS = new BufferedInputStream(new FileInputStream(sourceFile));
// 带缓冲的输出流
bufOS = new BufferedOutputStream(new FileOutputStream(targetFile));
// 缓冲数组
byte[] bytes = new byte[1024 * 5];
// 位置记录
int len = 0;
while ((len = bufIS.read(bytes)) != -1) {
// 把读入的数据流写入到输出流冲
bufOS.write(bytes, 0, len);
}
// 强制写入到输出流
bufOS.flush();
} catch (FileNotFoundException e) {
log.info("复制文件时找不到文件:" + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
log.info("复制文件时出现IO错误:" + e.getMessage());
e.printStackTrace();
} finally {
// 重要:记得关闭流
if (bufIS != null) {
bufIS.close();
}
if (bufOS != null) {
bufOS.close();
}
}
}
/**
* 向目标Excel文件写入数据
*
* @param rows
* 需要写多少行Excel
* @param newTargetFile
* 目标文件
* @throws IOException
*/
private void createTheTargetExcel(int rows, File newTargetFile)
throws IOException {
FileOutputStream localFile = null;
try {
// 获取到拷贝过后的Excel模版文件
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(
newTargetFile));
// 根据Excel文件,获取到 工作簿
HSSFWorkbook workbook = new HSSFWorkbook(fs);
// 获取到第一页工作表
HSSFSheet sheet = workbook.getSheetAt(0);
// 定义行
HSSFRow row;
// 列表中的把数据写入到Excel里面,从第四行开始(前三行是标题)
for (int i = 0; i < rows; i++) {
StatisticsShowE aline = (StatisticsShowE) listShowInPage.get(i);
row = sheet.getRow(i + 3); // 获取第(i+3)行,前三行是标题
// 单元格的位置,从0开始
short tempCellCounter = 0;
// 解决中文乱码问题(Excel文件内容里面的乱码)
row.getCell(tempCellCounter).setEncoding(
HSSFWorkbook.ENCODING_UTF_16);
row.getCell(tempCellCounter).setCellValue(aline.getJgm());
tempCellCounter++;
// 每日
row.getCell(tempCellCounter).setCellValue(
aline.getMrrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMrrw().getWwcCount());
tempCellCounter++;
// 日终
row.getCell(tempCellCounter).setCellValue(
aline.getRzrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getRzrw().getWwcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getRzrw().getCbCount());
tempCellCounter++;
// 每周
row.getCell(tempCellCounter).setCellValue(
aline.getMzrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMzrw().getWwcCount());
tempCellCounter++;
// 每旬
row.getCell(tempCellCounter).setCellValue(
aline.getMxrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMxrw().getWwcCount());
tempCellCounter++;
// 每月
row.getCell(tempCellCounter).setCellValue(
aline.getMyrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMyrw().getWwcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMyrw().getCbCount());
tempCellCounter++;
// 每季
row.getCell(tempCellCounter).setCellValue(
aline.getMjrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMjrw().getWwcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMjrw().getCbCount());
tempCellCounter++;
// 半年
row.getCell(tempCellCounter).setCellValue(
aline.getBnrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getBnrw().getWwcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getBnrw().getCbCount());
tempCellCounter++;
// 每年
row.getCell(tempCellCounter).setCellValue(
aline.getMnrw().getWcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMnrw().getWwcCount());
tempCellCounter++;
row.getCell(tempCellCounter).setCellValue(
aline.getMnrw().getCbCount());
tempCellCounter++;
}
// 新建一输出文件流
localFile = new FileOutputStream(newTargetFile);
// 把数据写入到相应的Excel 工作簿
workbook.write(localFile);
localFile.flush();
localFile.close();
} catch (FileNotFoundException e) {
log.info("向Excel文件写入数据时出现异常:" + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
log.info("向Excel文件写入数据时出现异常:" + e.getMessage());
e.printStackTrace();
} finally {
if (localFile == null) {
// 操作结束,关闭文件
localFile.close();
}
}
}
/**
* 当指定的目录下,文件个数超过一定数量时,进行清空
*
* @param path
* @param targetNum
*/
private void deleteDirFiles(String path, int targetNum) {
File dirPath = new File(path);
if (dirPath.exists()) {// 如果找到了这个目录
File[] excelFiles = dirPath.listFiles();
// 当该目录下的文件个数大于指定参数时
if (excelFiles.length > targetNum) {
for (int i = 0; i < excelFiles.length; i++) {
File tempFile = excelFiles[i];
// 日志记录删除的文件的名称
log.info(tempFile.getName() + " 已经删除");
if (tempFile.isFile()) {// 如果是文件,就进行删除
tempFile.delete();
}
}
}
}
}
注:使用的Excel解析框架是POI,此处仅提供实现思路和部分实现代码
导出效果:
最后导出的Excel文件:
模版文件: