最近在工做中遇到的一個問題,要將html標籤裏的Table跟echarts生成報表導出到excel裏面,沒有搞過各類谷歌!-_-,還好解決了,就分享一下此次踩坑的經驗了.html
所使用的jar包:前端
commons-codec-1.9.jar commons-lang3-3.3.2.jar jsoup-1.8.3.jar poi-3.9.jar slf4j-api-1.7.7.jar slf4j-simple-1.7.7.jar table-to-xls-0.0.1-RELEASE.jar//這個能夠在oscchina的git上找到的謝謝大神的代碼了
首先說一說實現的思路:java
前端用jquery獲取Table標籤的內容跟echarts報表的圖片的base64----->2.ajax的post傳輸數據到後臺----->3將獲取到的數據分別處理,表格生成excel再將base64還原成圖片插入到生成的excel裏面jquery
具體實現:git
第一步:ajax
首先說明一下echarts在生成圖表以前都要先初始化一個東西因此base64能夠根據這個來獲取json
var showCharts=[];//這是個全局變量用來接收每一個chart對象的 //在每一個chart初始化的時候將初始化的對象放進數組 var myChart = echarts.init(document.getElementById(tagid)); showCharts.push(myChart);
第二步:經過頁面上的一個按鈕觸發一個函數(click事件)
api
function export2Excel(tableId){ var tableContext =$("#"+tableId).html(); var datas={} if(tableContext.length>37){//這裏爲何判斷長度大於37由於表格動態生成的默認長度就有36!!:) tableContext="<table>"+tableContext+"</table>"; datas.tableContext=tableContext; } if(showCharts.length!=0){ var imgUrls = []; for(var x =0; x<showCharts.length;x++){ imgUrls.push(showCharts[x].getDataURL("png")); } datas.imgUrls=imgUrls; } if(datas.tableContext){ $.ajax({ url:url,//發送到後臺處理這些數據的控制器地址(這個只是負責發送數據到後臺) type: "POST", dataType: "json", data: $.param(datas,true),//發送數組這樣的數據格式必用這個東西否則極可能出問題 success: function (result) { if(parseInt(result.status)==0){ location.href=url+fileName//用來處理下載請求的控制器地址跟下載的文件名,爲啥要有這一步呢由於ajax不支持下載的瀏覽器是彈不出那個保存文件的框的(有沒有草泥馬) } }, failure: function (err) { alert("ajax產生了錯誤!"); } }); }else{ alert("必須有表格或者圖表才能下載"); }
第三步:後臺處理數組
//這個控制器是用來預處理ajax的post請求提交過來的數據的 @RequestMapping(value = "preExportToExcel",method=RequestMethod.POST) @ResponseBody public AjaxData<Map<String,String>> preExportToExcel(String tableContext, String[] imgUrls,HttpServletRequest req,HttpServletResponse rep) throws Exception { AjaxData<Map<String,String>> ajax = new AjaxData<Map<String,String>>(); tableContext=HtmlUtils.htmlUnescape(tableContext); String filePath=req.getSession().getServletContext().getRealPath("/")+"temp"; filePath = filePath.replace("\\","/")+"/"; HtmlTableToExcel html = new HtmlTableToExcel(imgUrls, filePath, tableContext);//這個對象會將傳遞過來的數據生成excel String xlsFileName = html.mergePicAndExcel(); Map<String,String> map = new HashMap<String,String>(); map.put("xlsFileName", xlsFileName); ajax.setData(map); return ajax; } //這個控制器纔是真正的下載控制器對應ajax裏面的location.href那句代碼 //採用servlet這種方式下載的緣由就是能夠在下載完成的時候能夠將文件刪掉 @RequestMapping(value = "exportToExcel",method=RequestMethod.GET) @ResponseBody public void exportToExcel(String xlsFileName, HttpServletResponse rep) throws Exception { OutputStream out = null; try { rep.reset(); rep.setContentType("application/vnd.ms-excel"); rep.setHeader("Content-Disposition","attachment; filename=" + xlsFileName.substring(xlsFileName.lastIndexOf("/") + 1)); out = rep.getOutputStream(); System.out.println(xlsFileName); out.write(FileUtils.readFileToByteArray(new File(xlsFileName))); out.flush(); File file = new File(xlsFileName.substring(0,xlsFileName.lastIndexOf("/"))); File[] files= file.listFiles(); for (File file2 : files) { FileUtils.deleteFile(file2.getAbsolutePath()); } } catch (IOException e) { throw new RuntimeException(e.getMessage() + "文件下載失敗"); } finally { if (out != null) { try { out.close(); } catch (IOException e) { throw new RuntimeException(e.getMessage() + "文件下載失敗"); } } } }
所用類的代碼:瀏覽器
值得注意的是圖片的後綴名必須是.png結尾的額否則透明背景的圖片插入到excel裏面是要變成黑乎乎的
/** * 將圖片的base64碼解密並還原圖片(只支持支持格式"png","jpg",支持多張圖片) * */ public class Base64ToImage { /** * Logger for this class */ private static final Logger logger = Logger.getLogger(Base64ToImage.class); /** * 枚舉類用來選擇模式 * */ public static enum PictureType { //png的圖片類型 TYPE_PNG,TYPE_JPG; } /** * * @param imgUrls 多張圖片的base64碼組 * @param filePath 保存文件的路徑 * @param type 生成文件的模式 * @return 返回生成的圖片的名字 */ public static List<String> base64ToPicture(String[] imgUrls,String filePath,Base64ToImage.PictureType type){ String suffix=""; //判斷傳入的圖片類型 if(type==PictureType.TYPE_PNG) suffix=suffix+".png"; if(type==PictureType.TYPE_JPG) suffix=suffix+".jpg"; //判斷空值以及0值 if(imgUrls.length==0||imgUrls==null||StringUtils.isBlank(filePath)){ return null; } List<String> fileNameList= new ArrayList<String>(); for (String imgUrl : imgUrls) { String fileName = UUID.randomUUID().toString(); String realFileName=filePath+fileName; if(isCreatePic(imgUrl, realFileName,suffix)) fileNameList.add(fileName+suffix); logger.info(fileName); } return fileNameList; } /** * * @param imgsURl 圖片的base64碼 * @param fileName 圖片名稱 * @return 是否生成圖片成功 */ private static boolean isCreatePic(String imgsURl, String fileName,String suffix){ BASE64Decoder decoder = new BASE64Decoder(); boolean flag = true; OutputStream out=null; try { String[] url = imgsURl.split(","); String u = url[1]; // Base64解碼 byte[] buffer = new BASE64Decoder().decodeBuffer(u); // 生成圖片 out= new FileOutputStream(new File(fileName + suffix)); out.write(buffer); out.flush(); } catch (Exception e) { flag = false; }finally{ try { if(out!=null)out.close(); } catch (IOException e) { flag=false; } } return flag; } } // 將頁面上的html 表格導出(支持頁面上的報表圖片導出,只支持單表的導出,只支持png格式圖片插入) public class HtmlTableToExcel { private static final Logger logger = Logger.getLogger(HtmlTableToExcel.class); //圖片的base64碼 private String[] imgUrls; //存放生成文件的路徑 private String filePath; //生成的文件名字 // private String fileName=UUID.randomUUID().toString(); private String tableContext; public HtmlTableToExcel(String[] imgUrls,String filePath, String tableContext) { this.imgUrls = imgUrls; this.tableContext = tableContext; this.filePath=filePath; } public String createExcel(){ FileOutputStream fout=null; try { String xlsFileName =this.filePath+UUID.randomUUID().toString()+".xls"; fout = new FileOutputStream(xlsFileName); TableToXls.process(tableContext, fout); return xlsFileName; } catch (FileNotFoundException e) { e.printStackTrace(); }finally{ try { if(fout!=null)fout.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } public String mergePicAndExcel(){ String xlsFileName=createExcel(); if(imgUrls!=null){ List<String>fileNames = Base64ToImage.base64ToPicture(this.imgUrls, this.filePath, PictureType.TYPE_PNG); for(int x = 0;x < fileNames.size();x++){ drawPiceToExcel(xlsFileName, this.filePath+fileNames.get(x),x); } } return xlsFileName; } private void drawPiceToExcel(String xlsFileName,String picFileName,int position){ FileOutputStream fileOut = null; BufferedImage bufferImg = null; FileInputStream in = null; Workbook wb = null; try { // 先把讀進來的圖片放到一個ByteArrayOutputStream中,以便產生ByteArray ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); bufferImg = ImageIO.read(new File(picFileName)); ImageIO.write(bufferImg, "png", byteArrayOut); // 打開一個工做薄 in = new FileInputStream(xlsFileName); POIFSFileSystem fs = new POIFSFileSystem(in); wb = new HSSFWorkbook(fs); HSSFSheet sheet = (HSSFSheet) wb.getSheetAt(0); HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 100, (short) 0, sheet.getLastRowNum()+5*position+27*position, (short) (sheet.getRow(0).getPhysicalNumberOfCells()+8), sheet.getLastRowNum()+5*position+27*(position+1)); // 插入圖片 patriarch.createPicture(anchor,wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG)); fileOut = new FileOutputStream(xlsFileName); // 寫入excel文件 wb.write(fileOut); fileOut.close(); } catch (IOException io) { throw new RuntimeException(io.getMessage()+"讀取文件出問題"); } finally { if (fileOut != null) { try { fileOut.close(); } catch (IOException e) { e.printStackTrace(); } } } } }