简单OA项目笔记(5):生成、上载excel格式的动态表格(POI)
简单OA项目笔记(5):生成、下载excel格式的动态表格(POI)
vnd.ms-excel:文件类型是tomcat提供的
"contentDisposition">filename="AllUsers.xls":配置下载全都是附件形式,文件名以配置为准
"inputName">downloadFile:需要具体action中的get“downloadFile”
把动态表格生成excel用的库叫POI,从数据库提取出数据之后,利用POI可以产生一个stream。
大体步骤:
步骤一:从数据库读信息
步骤二:数据组装成excel
步骤三:用InputStream发回浏览器
数据流:
1.struts.xml中action配置
result:是“stream”vnd.ms-excel:文件类型是tomcat提供的
"contentDisposition">filename="AllUsers.xls":配置下载全都是附件形式,文件名以配置为准
"inputName">downloadFile:需要具体action中的get“downloadFile”
<action name="generateExcel" class="generateExcelAction"> <result name="success" type="stream"><!-- result是“stream”--> <param name="contentType">application/vnd.ms-excel</param> <!--文件类型是tomcat提供的--> <param name="contentDisposition">attachment;filename="AllUsers.xls"</param> <!--配置下载全都是附件形式,文件名以配置为准--> <param name="inputName">downloadFile</param> <!--需要具体action中的get“downloadFile”--> </result> </action>
2.GenerateExcelAction
这个getter和上边"inputName">downloadFile 一致
public InputStream getDownloadFile() { return this.service.getInputStream(); }
3.UserServiceImpl
这里边是生成excel的核心代码,组装好之后,要把生成的excel转换成InputStream类型还给action。action根据下载配置,把文件用附件的形式发给客户端,完成下载。
生成excel的过程是
1.创建sheet
2.由sheet创建:行
3.表头:short表示0号格
设置中文
4.迭代创建表格:
5.把表格写进 ByteArrayOutputStream 对象,再转换成InputStream 对象返还给action
public InputStream getInputStream() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet("sheet1"); HSSFRow row = sheet.createRow(0); HSSFCell cell = row.createCell((short) 0); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("序号"); cell = row.createCell((short) 1); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("姓"); cell = row.createCell((short) 2); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("名"); cell = row.createCell((short) 3); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("年龄"); List<User> list = this.findAll(); for (int i = 0; i < list.size(); ++i) { User user = list.get(i); row = sheet.createRow(i + 1); cell = row.createCell((short) 0); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(i + 1); cell = row.createCell((short) 1); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(user.getFirstname()); cell = row.createCell((short) 2); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(user.getLastname()); cell = row.createCell((short) 3); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(user.getAge()); } ByteArrayOutputStream os = new ByteArrayOutputStream(); try { wb.write(os); } catch (IOException e) { e.printStackTrace(); } byte[] content = os.toByteArray(); InputStream is = new ByteArrayInputStream(content); return is; }
4.用另一种思路:产生临时文件
上边产生excel的的方式没有用到临时文件,直接在内存里就都完成了。还有一种方法是利用临时文件保存excel表信息。
这种方法比较麻烦,首先是下载的文件名不能重复,否则多线程情况下就该互相覆盖掉了
String fileName = RandomStringUtils.randomAlphanumeric(10); fileName = new StringBuffer(fileName).append(".xls").toString(); final File file = new File(fileName); try { OutputStream os = new FileOutputStream(file); wb.write(os); os.close(); } catch (Exception e) { e.printStackTrace(); } InputStream is = null; try { is = new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } new Thread(new Runnable() { public void run() { try { Thread.sleep(15000); } catch (InterruptedException e) { e.printStackTrace(); } file.delete();//删除临时文件 } }).start(); return is;
而且产生的随机文件名的临时文件,还要自己估摸一个时间延迟删除:
new Thread(new Runnable() { public void run() { try { Thread.sleep(15000); } catch (InterruptedException e) { e.printStackTrace(); } file.delete();//删除临时文件 } }).start();
如果没删掉还有靠其他方法比如servlet启动时删除:
public void init() throws ServletException { File file = new File("."); File[] subFiles = file.listFiles(new FileFilter() { public boolean accept(File pathname) { if(pathname.getName().endsWith("xls")) { return true; } return false; } } ); for(File f : subFiles) { f.delete(); } }
这个比较恶心,目前来看还是用第一种说的 在内存里 ByteArrayOutputStream 完成吧,内存很紧张的时候可能才会用临时文件吧。