问题描述:需要完成这样一个功能:一后台生成excle,前台点击按钮直接可以下载。
要完成这个功能分两步:
一.将需要写入的数据写入到缓存中
二.将缓存中的文件使用流写到httpServletResponse中。这样通过设置 httpServletResponse的Header可以直接返回一个excle类型的文件。
首先进行第一步:写入数据,这里是使用POI的接口:
CourseClass courseClass = courseClassService.selectById(classId);
Course course = courseService.selectById(courseClass.getCourseId());
List<UserStageMsg> userStageMsgList = getClassStageTestMsg(classId, paperId);
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("sheet1");
HSSFRow row = sheet.createRow((int) 0);
HSSFCellStyle style = wb.createCellStyle();
HSSFCell cell = row.createCell(0);
cell.setCellValue("序号");
cell.setCellStyle(style);
cell = row.createCell(1);
cell.setCellValue("姓名");
cell.setCellStyle(style);
cell = row.createCell(2);
cell.setCellValue("学号");
cell.setCellStyle(style);
cell = row.createCell(3);
cell.setCellValue("分数");
cell.setCellStyle(style);
cell = row.createCell(4);
cell.setCellValue("提交状态");
cell.setCellStyle(style);
if (userStageMsgList.size() > 0) {
for (int i = 0; i < userStageMsgList.size(); i++) {
row = sheet.createRow((int) i + 1);
row.createCell(0).setCellValue(i+1);
row.createCell(1).setCellValue(userStageMsgList.get(i).getRealname());
row.createCell(2).setCellValue(userStageMsgList.get(i).getStaffNum());
if (userStageMsgList.get(i).getStage_Score() != null)
row.createCell(3).setCellValue(userStageMsgList.get(i).getStage_Score());
else
row.createCell(3).setCellValue(0);
if ("1".equals(userStageMsgList.get(i).getStatus()))
row.createCell(4).setCellValue("已提交");
else
row.createCell(4).setCellValue("未提交");
}
}
这段代码想要完成的工作就是把一个班级中所有学生的阶段测试分数和提交状态写入到一个excle文件中。标题所遇到的问题也不时出现在这一段代码内。具体的用法很简单,网上有很多,自己写这块出问题的概率很小。我这整个函数就是网上拷贝修改的。
String fileName = new String(new StringBuilder().append(courseClass.getClassName()).append("阶段测试详情")
.append(".xls").toString().getBytes("UTF-8"));
ServletOutputStream os = null;
try {
os = httpServletResponse.getOutputStream();
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName,"UTF-8") );
httpServletResponse.setContentType("application/vnd.ms-excel;charset=utf-8");
wb.write(os);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (wb != null ){
wb.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
throw new ApiException(e.getStackTrace().toString());
}
}
这些代码才是导致问题出现或者说解决问题的关键所在。这几行代码以后很多需要注意的地方(这段是对的)。
1.先把问题聚焦到文件内容的乱码,在历时两个小时的百度以及各种不同方案的修改之后,我突然发现这样一篇博客。大致内容就是使用接口测试工具postman、swagger等测试这种功能的接口时,不一定是代码本身出现了问题,而也有可能时测试工具的问题。看完以后我试了postman(本来用的swagger),发现果然都是乱码。是以下这个样子:
然后打开了是这个样子:
以及这个样子:
于是我直接把URL敲在了浏览器中,此时奇迹发生了。我下载到了一个文件,“.xls”,是的你没有看错,只有后缀名没有文件名,下载完了给他一个名字,然后打开,果然,没有再出现乱码。所以文件内容乱码很有可能是测试工具的锅。
2.现在还有一个问题就是没有文件名的问题,为了解决这个问题,我仔细阅读了代码:
......
ServletOutputStream os = null;
......
我发现这个输出流是OutputStream 类型的,对比了百度上其他代码,我发现有的使用ServletOutputStream 作为输出流。更换了以后,文件名出现了,但还是:
但是文件内容依旧没毛病。
3.现在还有最后一个问题就是文件名乱码的问题。
httpServletResponse.setHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName,"UTF-8") );
将被注释的一行改成以下这行,文件名就不再乱码了。