AJAX文件下载
JQuery的ajax函数的返回类型只有xml、text、json、html等类型,没有“流”类型,所以我们要实现ajax下载,不能够使用相应的ajax函数进行文件下载。但可以用js生成一个form,用这个form提交参数,并返回“流”类型的数据。在实现过程中,页面也没有进行刷新。
注意此示例采用STRUTS2实现,没有采用Struts2内置的文件下载方法。
JS代码如下:
<script type="text/javascript"> function aClick () { $.ajax({ type : "POST",//提交方式 url : "${pageContext.request.contextPath}/ajaxTest.action",//路径 data : { id: 1,name:"testtt" },//数据,这里使用的是Json格式进行传输 success : function(result) {//返回数据根据结果进行相应的处理 var form=$("<form>");//定义一个form表单 form.attr("style","display:none"); form.attr("target",""); form.attr("method","post"); form.attr("action","downloadTest.action"); var input1=$("<input>"); input1.attr("type","hidden"); input1.attr("name","exportData"); input1.attr("value",(new Date()).getMilliseconds()); $("body").append(form);//将表单放置在web中 form.append(input1); form.submit();//表单提交 } }); } </script>
下图有两个超链接,第一个是通过AJAX调用下载ACTION的,第二个直接就是超链接调用ACTION 。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <Meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src='full/jquery.min.js'></script> <title>Insert title here</title> <script type="text/javascript"> function aClick () { $.ajax({ type : "POST","ajaxTest.action"); var input1=$("<input>"); input1.attr("type",(new Date()).getMilliseconds()); $("body").append(form);//将表单放置在web中 form.append(input1); form.submit();//表单提交 } }); } </script> </head> <body> <br /> <h2>点击下载</h2> <a href="javascript:void(0)" onclick="aClick()">文件下载</a> <a href="ajaxTest.action?fileName=FCN301-Ver.1.1費用申請書.xls">文件下载(超链接)</a> </body> </html>
ACTION类如下:(此ACTION类中也有一个下载的方法,都是共通的)
/** * com.ppl.action.excelDol.java * @author 作者 : pplsunny * @version 创建时间:2017年4月8日 下午8:26:39 * 类说明 */ package com.ppl.action; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.ppl.test.WorkbookDemo; /** * XXXX */ public class excelDol extends ActionSupport { public String execute() throws Exception { String filePath="G:/POI_JAVA/FCN301-Ver.1.1費用申請書.xls"; //下载到客户端 HttpServletResponse response = ServletActionContext.getResponse(); //download(filePath,response); WorkbookDemo.readTempleteExcel(filePath,response); //1 获取表单数据 HttpServletRequest request = ServletActionContext.getRequest(); String id = request.getParameter("id"); String name = request.getParameter("name"); System.out.println(id+"--"+name); return NONE; } private void download(String path,HttpServletResponse response) { try { // path是指欲下载的文件的路径。 File file = new File(path); // 取得文件名。 String filename = file.getName(); String strName = new String(filename.getBytes("UTF-8"),"ISO-8859-1"); // 以流的形式下载文件。 InputStream fis = new BufferedInputStream(new FileInputStream(path)); byte[] buffer = new byte[fis.available()]; fis.read(buffer); fis.close(); // 清空response response.reset(); // 设置response的Header response.addHeader("Content-Disposition","attachment;filename=" + new String(filename.getBytes("UTF-8"),"ISO-8859-1")); response.addHeader("Content-Length","" + file.length()); OutputStream toClient = new BufferedOutputStream( response.getOutputStream()); response.setContentType("application/vnd.ms-excel;charset=gb2312"); toClient.write(buffer); toClient.flush(); toClient.close(); } catch (IOException ex) { ex.printStackTrace(); } } }
EXCEL文件操作类
package com.ppl.test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.util.WorkbookUtil; public class WorkbookDemo { /** * 创建工作簿 * @throws IOException */ public static void createWorkBook() throws IOException { /** * 工作薄: WorkBook是操作Excel的入口,Excel的文档对象,HSSFWorkbook(2003版本 ),XSSFWorkbook(2007版本)实现了该接口。 * HSSF对应xls格式,XSSF对应xlsx格式 * ------------------------------------------------------------------ * Workbook wb = new XSSFWorkbook(); * FileOutputStream fileOut = new FileOutputStream("workbook.xlsx"); * wb.write(fileOut); * fileOut.close(); * ------------------------------------------------------------------ */ final Workbook HSSFwb = new HSSFWorkbook(); /** * Sheet是在org.apache.poi.ss.usermodel包的接口,它是创建具有特定名称的高或低级别的电子表格的所有类的超接口。 * 页:Sheet表示工作薄的分页。HSSFSheet, XSSFChartSheet,XSSFDialogsheet,XSSFSheet实现了该接口。 * 索引以0开始,以workbook.getNumberOfSheets()-1结束 */ final String safeName = WorkbookUtil.createSafeSheetName("first sheet"); final Sheet sheet = HSSFwb.createSheet(safeName); //sheet.autoSizeColumn(6,true); /** * 获取工作簿数量 */ final int sheetCount = HSSFwb.getNumberOfSheets(); System.out.println("sheetCount: " + sheetCount); /** * Row:表示页中的一行。HSSFRow,XSSFRow实现了该接口。 * Row的索引以0开始(getFirstRowNum),以getLastRowNum结束 */ final Row row = sheet.createRow((short) 0); /** * 得到的是最后一个不为空的行索引,真实行号是【getLastRowNum()+1】 */ final int rowNumReal = sheet.getLastRowNum(); /** * Cell:行中的一个单元格。HSSFCell,XSSFCell实现了该接口。 * Cell的索引以0开始(getFirstCellNum),以getLastCellNum结束,*/ final Cell cell = row.createCell(0); /** * 获取当前行中不为空的单元格数 */ final int cellNumReal = row.getPhysicalNumberOfCells(); /** * 空单元格返回对应的单元格类型 */ Cell cell2 = row.getCell(3,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); cell2 = row.getCell(4,Row.MissingCellPolicy.RETURN_BLANK_AS_NULL); cell2 = row.getCell(5,Row.MissingCellPolicy.RETURN_NULL_AND_BLANK); //设置单元格的数据 cell.setCellValue(1); // Or do it on one line. row.createCell(1).setCellValue(1.2); row.createCell(2).setCellValue("This is a string 速度反馈链接"); row.createCell(3).setCellValue(true); //----------------------单元格赋值示例START------------------------------------------ /** * 创建第十行 */ final Row rowTEN = sheet.createRow((short) 9); // 填充日期类型的数据---未设置Cell Style rowTEN.createCell(1).setCellValue(new Date()); // 另一种创建日期的方法 rowTEN.createCell(2).setCellValue(Calendar.getInstance()); /** * 在第十行的单元格上创建单元格 */ final Cell cellOther = rowTEN.createCell(5); cellOther.setCellValue(new Date()); /** * 获取HSSF的辅助类 */ final CreationHelper createHelper = HSSFwb.getCreationHelper(); final CellStyle cellStyle = HSSFwb.createCellStyle(); // 填充日期类型的数据---已设置Cell Style final String timeFormat = "yyyy-MM-dd hh:mm:ss"; cellStyle.setDataFormat(createHelper.createDataFormat().getFormat(timeFormat)); final Cell cell7 = rowTEN.createCell(6); cell7.setCellValue(new Date()); cell7.setCellStyle(cellStyle); /** * 设置单元格宽度自适应,对中文支持不好 */ sheet.autoSizeColumn((short) 6); //----------------------单元格赋值示例END------------------------------------------ /** * 创建一个文件 命名为workbook.xls,默认创建到当前工程的根目录下 */ final FileOutputStream fileOut = new FileOutputStream("workbook2.xls"); /** * 把上面创建的工作簿输出到文件中 */ HSSFwb.write(fileOut); /** * 关闭输出流 */ fileOut.close(); HSSFwb.close(); } /** * 使用POI读入excel工作簿文件 * @throws Exception */ public static void readWorkBook() throws Exception { /** * 从文件流读取Excel */ final InputStream inp = new FileInputStream("workbook1.xls"); /** * 根据上述创建的输入流 创建工作簿对象 */ final Workbook wb = WorkbookFactory.create(inp); /** * 页Sheet是从0开始索引的 */ final Sheet sheet = wb.getSheetAt(0); /** * 按名引用excel工作表 * Sheet sheetByName = wb.getSheet("NAME"); */ /** * 获取工作簿的行数 */ final int rowNumReal = sheet.getLastRowNum(); System.out.println("----------------------"); System.out.println("rowNumReal-->" + rowNumReal); System.out.println("----------------------"); final int cellNumReal = sheet.getRow(rowNumReal).getPhysicalNumberOfCells(); System.out.println("cellNumReal-->" + cellNumReal); //利用foreach循环 遍历sheet中的所有行 int rowNum=0; /** * 直接采用这种循环空行和空列是不会读取的, * 即当行有空行或者一行中有空单元格是,循环会跳过去 */ for (final Row row : sheet) { rowNum++; //遍历row中的所有方格 for (final Cell cell : row) { final String valueT = getCellContentAsString(cell); System.out.println(cell.toString() + " ---> " + valueT); } //每一个行输出之后换行 System.out.println(); } System.out.println("----------------------"); loopRowAndCell(sheet); System.out.println("rowNum-->"+rowNum); //关闭输入流 inp.close(); } /** * 遍历一个工作簿中的行和列 * 不包含空行和空列(无需对空行和空列做处理) * @param sheet * @throws Exception */ public static void loopRealRowAndCell(final Sheet sheet) throws Exception { /** * 遍历行 */ int rowno = 0; for (final Iterator itemRow = sheet.rowIterator(); itemRow.hasNext();) { final Row row = (Row) itemRow.next(); rowno++; System.out.println("----------rowno----------" + rowno); /** * 遍历列 */ for (final Iterator itemCell = row.cellIterator(); itemCell.hasNext();) { final Cell cell = (Cell) itemCell.next(); /** * 获取单元格格式类型 * POI 3.15 beta 3. Use CellType.ERROR instead. */ String cellValue = ""; switch (cell.getCellTypeEnum()) { case STRING:// 字符串 cellValue = cell.getRichStringCellValue().getString().trim(); break; case NUMERIC:// 数字 //如果为时间格式的内容 if (HSSFDateUtil.isCellDateFormatted(cell)) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); cellValue = sdf.format(HSSFDateUtil.getJavaDate(cell.getNumericCellValue())).toString(); break; } else { /** * 解决科学计数法的问题 */ final Double d = cell.getNumericCellValue(); final DecimalFormat dformat = new DecimalFormat("#.##"); cellValue = dformat.format(d); } break; case BOOLEAN:// Boolean cellValue = String.valueOf(cell.getBooleanCellValue()).trim(); break; case FORMULA:// 公式 /** * 解决公式的取值问题 */ try { /** * 公式计算结果是纯数字 */ cellValue = String.valueOf(cell.getNumericCellValue()); } catch (final IllegalStateException e) { /** * 公式计算结果是不是纯数字 */ cellValue = String.valueOf(cell.getRichStringCellValue()); } /** * 这句获取的是计算公式 */ //cellValue = cell.getCellFormula() + ""; break; case BLANK: // 空值 cellValue = "BLANG"; break; case ERROR: // 故障 cellValue = "N/A"; break; default://未知类型 cellValue = "ERROR"; } System.out.println(" cellValue---> " + cellValue); } } } /** * 遍历一个工作簿中的行和列 * 包含空行和空列(传统遍历,需要对空行和空列进行处理) * @param sheet * @throws Exception */ public static void loopRowAndCell(final Sheet sheet) throws Exception { /** * 得到的是最后一个不为空的行索引,真实行号是【getLastRowNum()+1】 */ final int rowNumReal = sheet.getLastRowNum(); /** * 遍历行 */ for (int rowIndex = 0; rowIndex <= rowNumReal; rowIndex++) { /** * 获取当前行 */ final Row row = sheet.getRow(rowIndex); /** * 空行处理 */ if (null == row) { System.out.println(" BLANG ROW " + rowIndex); continue; } /** * 取得当前行的列数 */ final int cellCount = row.getLastCellNum(); /** * 遍历列 */ for (int cellIndex = 0; cellIndex < cellCount; cellIndex++) { /** * 获取当前列,如果当前列不存在(为空)则返回一个单元格类型为空的单元格 */ final Cell cell = row.getCell(cellIndex,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); /** * 空列处理 */ if (null == cell) { System.out.println(" BLANG CELL " + cellIndex); continue; } /** * 获取单元格格式类型 * POI 3.15 beta 3. Use CellType.ERROR instead. */ String cellValue = ""; switch (cell.getCellTypeEnum()) { case STRING:// 字符串 cellValue = cell.getRichStringCellValue().getString().trim(); break; case NUMERIC:// 数字 //如果为时间格式的内容 if (HSSFDateUtil.isCellDateFormatted(cell)) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); cellValue = sdf.format(HSSFDateUtil.getJavaDate(cell.getNumericCellValue())).toString(); break; } else { /** * 解决科学计数法的问题 */ final Double d = cell.getNumericCellValue(); final DecimalFormat dformat = new DecimalFormat("#.##"); cellValue = dformat.format(d); } break; case BOOLEAN:// Boolean cellValue = String.valueOf(cell.getBooleanCellValue()).trim(); break; case FORMULA:// 公式 /** * 解决公式的取值问题 */ try { /** * 公式计算结果是纯数字 */ cellValue = String.valueOf(cell.getNumericCellValue()); } catch (final IllegalStateException e) { /** * 公式计算结果是不是纯数字 */ cellValue = String.valueOf(cell.getRichStringCellValue()); } /** * 这句获取的是计算公式 */ //cellValue = cell.getCellFormula() + ""; break; case BLANK: // 空值 cellValue = "BLANG"; break; case ERROR: // 故障 cellValue = "N/A"; break; default://未知类型 cellValue = "ERROR"; } System.out.println(" cellValue---> " + cellValue); } } } /** * *解析一个单元格得到数据 * @param cell * @return */ private static String getCellContentAsString(final Cell cell) { if (null == cell) { return ""; } /** * 获取单元格格式类型 * POI 3.15 beta 3. Use CellType.ERROR instead. */ String cellValue = ""; switch (cell.getCellTypeEnum()) { case STRING:// 字符串 cellValue = cell.getRichStringCellValue().getString().trim(); break; case NUMERIC:// 数字 //如果为时间格式的内容 if (HSSFDateUtil.isCellDateFormatted(cell)) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); cellValue = sdf.format(HSSFDateUtil.getJavaDate(cell.getNumericCellValue())).toString(); break; } else { /** * 解决科学计数法的问题 */ final Double d = cell.getNumericCellValue(); final DecimalFormat dformat = new DecimalFormat("#.##"); cellValue = dformat.format(d); } break; case BOOLEAN:// Boolean cellValue = String.valueOf(cell.getBooleanCellValue()).trim(); break; case FORMULA:// 公式 /** * 解决公式的取值问题 */ try { /** * 公式计算结果是纯数字 */ cellValue = String.valueOf(cell.getNumericCellValue()); } catch (final IllegalStateException e) { /** * 公式计算结果是不是纯数字 */ cellValue = String.valueOf(cell.getRichStringCellValue()); } /** * 这句获取的是计算公式 */ //cellValue = cell.getCellFormula() + ""; break; case BLANK: // 空值 cellValue = "BLANG"; break; case ERROR: // 故障 cellValue = "N/A"; break; default://未知类型 cellValue = ""; } return cellValue; } /** * * 读取已有Excel作为模板进行数据操作 * @param filePAth 模板路径 * @return -1:filePAth error; * @throws IOException * @throws FileNotFoundException */ public static int readTempleteExcel(final String filePAth,HttpServletResponse response) throws FileNotFoundException,IOException { if ((filePAth == null) || filePAth.trim().isEmpty()) { return -1; } /** * 先读取模板 ,使用POIFSFileSystem对象构造的新HSSFWorkbook对象。 */ final POIFSFileSystem POIfs = new POIFSFileSystem(new FileInputStream(filePAth)); /** * 基于模板创建workbook */ final HSSFWorkbook workbook = new HSSFWorkbook(POIfs); /** * 如果模板存在多页的话可以分别取到 */ final HSSFSheet sheet_1st = workbook.getSheetAt(0); //////////////////////------------------------ // 第一页,第一行 final HSSFRow row = sheet_1st.getRow(0); // 取第一个单元格 final HSSFCell cell = row.getCell(0); // 获取单元格字符串值 final String cellValue = cell.getStringCellValue(); System.out.println(cellValue); //final String path = "G:/POI_JAVA/demo.xls"; // 输出Excel HttpServletResponse newresponse=response; try { ByteArrayOutputStream os = new ByteArrayOutputStream(); workbook.write(os);// HSSFWorkbook写入流 byte[] content = os.toByteArray(); InputStream is = new ByteArrayInputStream(content); //文件名字符编码转换 //String strName = new String(filename.getBytes("UTF-8"),"ISO-8859-1"); // 设置请求 // 设置response参数,可以打开下载页面 newresponse.reset(); newresponse.setContentType("application/octet-stream"); newresponse.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode("aa.xls","UTF-8")); OutputStream outputStream = newresponse.getOutputStream();// 打开流 BufferedInputStream bis = null; BufferedOutputStream bos = null; bis = new BufferedInputStream(is); bos = new BufferedOutputStream(outputStream); byte[] buff = new byte[2048]; int bytesRead; // Simple read/write loop. while (-1 != (bytesRead = bis.read(buff,buff.length))) { bos.write(buff,bytesRead); } if (bis != null){ bis.close(); } if (bos != null){ bos.close(); } outputStream.flush();// 刷新流 outputStream.close();// 关闭流 workbook.close(); } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return 0; } }
==================