跟據客戶的要求,須要開發一套包括圖形的報表,還須要導出WORDapp
圖表須要這樣:ide
這樣:工具
這樣:ui
還有這樣:this
接下來是實現思路:spa
以往用的最多的就是JFreechart,手上也有實現各類圖形的資源,可是領導說用它作的圖形太醜了, 因此沒什麼卵用。3d
FusionCharts到是漂亮,可是沒有辦法實現上述圖表,客戶也不能接受替代方案,一樣沒什麼卵用excel
而後就是百度ECharts,漂亮、功能強大、靈活性強(JS/HTML5實現,能夠隨意更改源碼), 可是有些功能不支待IE8, 仍是沒什麼卵用code
想了不少方法,最後又回到了原點,客戶要生成Office, 就讓Office給咱們作,雖然Java對操做圖表尚未什麼好的方法,可是jacob是能夠操做宏,咱們經過宏實現全部圖表功能。orm
一、 製做Excel圖表模板
製做圖表看起來簡單,可是作起來至關的慢,好在客戶提供一些相似圖表,我作了一些調整就能夠了 膜拜。。。。。
還有就是網上一堆的製做圖表的教程,就不記錄了。
二、 經過POI填充數據到Excel
1 /** 2 * 經過填充excel 生成圖表 3 * @param list 圖標數據 4 * @param inFile 模板文件 5 * @param outFile 輸出文件 6 * @return 7 * @throws Exception 8 */ 9 public static void createChart(List<Map> list, String inFile,String outFile) { 10 if(list == null) list = new ArrayList(); 11 12 System.out.println("圖表個數" + list.size()); 13 System.out.println("源文件路徑" + inFile); 14 System.out.println("圖表個數" + outFile); 15 16 try { 17 // 讀取模板 18 FileInputStream is = new FileInputStream(inFile); 19 HSSFWorkbook wbs = new HSSFWorkbook(is); 20 21 int sheetIndex; 22 HSSFSheet sheet; //sheet 23 int rowIndex; 24 HSSFRow row; //行 25 int cellIndex; 26 HSSFCell cell; //列 27 String value; 28 float fvalue; 29 String valStr = "^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$"; 30 31 List<Integer> sheetList = new ArrayList(); 32 for(Map tempMap:list) { 33 // 讀取工做表(data) 34 sheetIndex = Integer.parseInt(tempMap.get("SHEETINDEX") + ""); 35 sheet = wbs.getSheetAt(sheetIndex-1); 36 sheetList.add(sheetIndex); 37 38 /* 39 int i = 0; 40 List<HSSFPictureData> pictures = wbs.getAllPictures(); 41 for (HSSFPictureData picData : pictures) { 42 String ext = picData.suggestFileExtension(); 43 byte[] data = picData.getData(); 44 System.out.println(data.length); 45 46 47 //savePic(row, picData); 48 /* 49 String ext = picData.suggestFileExtension(); 50 51 byte[] data = picData.getData(); 52 if (ext.equals("jpeg")) { 53 FileOutputStream out = new FileOutputStream( 54 "D:\\Users\\Fancy1_Fan\\桌面\\work\\pict" + i + ".jpg"); 55 out.write(data); 56 out.close(); 57 } 58 if (ext.equals("png")) { 59 FileOutputStream out = new FileOutputStream( 60 "D:\\Users\\Fancy1_Fan\\桌面\\work\\pict" + i + ".png"); 61 out.write(data); 62 out.close(); 63 }*//* 64 i++; 65 }*/ 66 67 //添加行 68 rowIndex = Integer.parseInt(tempMap.get("ROWINDEX") + ""); 69 row = sheet.getRow(rowIndex-1); 70 if(row == null) row = sheet.createRow(rowIndex-1); 71 72 //列 73 cellIndex = Integer.parseInt(tempMap.get("CELLINDEX") + ""); 74 cell = row.getCell(cellIndex-1); 75 76 value = tempMap.get("DATAINFO") + ""; 77 if(value.matches(valStr)) { 78 fvalue = Float.parseFloat(value); 79 80 cell.setCellValue(fvalue); 81 } else { 82 cell.setCellValue(value); 83 } 84 //cell.setCellValue(tempMap.get("DATAINFO") + ""); //數據列 85 } 86 for(int temp:sheetList) { 87 sheet = wbs.getSheetAt(temp-1); 88 sheet.setForceFormulaRecalculation(true); 89 } 90 91 // 輸出文件 92 FileOutputStream os = new FileOutputStream(outFile); 93 wbs.write(os); 94 is.close(); 95 os.close(); 96 } catch (Exception e) { 97 e.printStackTrace(); 98 } 99 }
三、 生成宏
個人基本思路是把全部生成的圖片復至到一個指定Sheet, 而後Java代碼只要到這個Sheet裏獲取圖形
Sheets("QPLJYFJWXSQK").Select ActiveSheet.ChartObjects("圖表 1").Activate ActiveChart.PlotArea.Select ActiveChart.ChartArea.Copy Sheets("CHART").Select Range("A41").Select ActiveSheet.Pictures.Paste.Select ActiveCell.FormulaR1C1 = "QPLJYFJWXSQK"
Sheets("QGJYFJLXSQK").Select Range("J13:S20").Select ' 複製位圖 Selection.CopyPicture Appearance:=xlScreen, Format:=xlBitmap Sheets("CHART").Select Range("AA1").Select '粘貼爲圖片(問題:複製的位圖自動添加邊框線,經過裁減的方式刪除邊框線) ActiveSheet.Paste Selection.ShapeRange.PictureFormat.Crop.PictureOffsetX = -1 Selection.ShapeRange.PictureFormat.Crop.PictureOffsetY = -1 Selection.Copy Range("A1").Select ActiveSheet.Pictures.Paste.Select ActiveCell.FormulaR1C1 = "QGJYFJLXSQK"
只要會VBA 基本語法,其它的若是不會,能夠經過錄制宏獲得
四、 調用宏
先提供工具類
1 package com.wiseda.fc.utils; 2 3 import com.jacob.activeX.ActiveXComponent; 4 import com.jacob.com.ComThread; 5 import com.jacob.com.Dispatch; 6 import com.jacob.com.Variant; 7 8 public class JacobExcelUtils { 9 private static ActiveXComponent xl = null; //Excel對象(防止打開多個) 10 private static Dispatch workbooks = null; //工做簿對象 11 private Dispatch workbook = null; //具體工做簿 12 private Dispatch sheets = null;// 得到sheets集合對象 13 private Dispatch currentSheet = null;// 當前sheet 14 15 public ActiveXComponent getXl() { 16 return xl; 17 } 18 19 public Dispatch getWorkbooks() { 20 return workbooks; 21 } 22 23 public Dispatch getWorkbook() { 24 return workbook; 25 } 26 27 /** 28 * 打開excel文件 29 * @param filepath 文件路徑名稱 30 * @param visible 是否顯示打開 31 * @param readonly 是否只讀方式打開 32 */ 33 public void OpenExcel(String filepath, boolean visible, boolean readonly) { 34 try { 35 initComponents(); //清空原始變量 36 ComThread.InitSTA(); 37 if(xl==null) 38 xl = new ActiveXComponent("Excel.Application"); //Excel對象 39 xl.setProperty("Visible", new Variant(visible));//設置是否顯示打開excel 40 if(workbooks==null) 41 workbooks = xl.getProperty("Workbooks").toDispatch(); //工做簿對象 42 workbook = Dispatch.invoke( //打開具體工做簿 43 workbooks, 44 "Open", 45 Dispatch.Method, 46 new Object[] { filepath, new Variant(false), 47 new Variant(readonly) },// 是否以只讀方式打開 48 new int[1]).toDispatch(); 49 } catch (Exception e) { 50 e.printStackTrace(); 51 releaseSource(); 52 } 53 } 54 55 /** 56 * 工做簿另存爲 57 * @param filePath 另存爲的路徑 58 */ 59 public void SaveAs(String filePath){ 60 Dispatch.invoke(workbook, "SaveAs", Dispatch.Method, 61 new Object[] { filePath, 62 new Variant(44) }, new int[1]); 63 } 64 65 /** 66 * 關閉excel文檔 67 * @param f 含義不明 (關閉是否保存?默認false) 68 */ 69 public void CloseExcel(boolean f,boolean quitXl) { 70 try { 71 Dispatch.call(workbook, "Save"); 72 Dispatch.call(workbook, "Close", new Variant(f)); 73 } catch (Exception e) { 74 e.printStackTrace(); 75 } finally { 76 if(quitXl){ 77 releaseSource(); 78 } 79 } 80 } 81 82 /** 83 * 釋放資源 84 */ 85 public static void releaseSource(){ 86 if(xl!=null){ 87 xl.invoke("Quit", new Variant[] {}); 88 xl = null; 89 } 90 workbooks = null; 91 ComThread.Release(); 92 System.gc(); 93 } 94 95 /** 96 * 添加新的工做表(sheet),(添加後爲默認爲當前激活的工做表) 97 */ 98 public Dispatch addSheet() { 99 return Dispatch.get(Dispatch.get(workbook, "sheets").toDispatch(), "add").toDispatch(); 100 } 101 102 /** 103 * 修改當前工做表的名字 104 * @param newName 105 */ 106 public void modifyCurrentSheetName(String newName) { 107 Dispatch.put(getCurrentSheet(), "name", newName); 108 } 109 110 /** 111 * 獲得當前工做表的名字 112 * @return 113 */ 114 public String getCurrentSheetName() { 115 return Dispatch.get(getCurrentSheet(), "name").toString(); 116 } 117 118 /** 119 * 獲得工做薄的名字 120 * @return 121 */ 122 public String getWorkbookName() { 123 if(workbook==null) 124 return null; 125 return Dispatch.get(workbook, "name").toString(); 126 } 127 128 /** 129 * 獲得sheets的集合對象 130 * @return 131 */ 132 public Dispatch getSheets() { 133 if(sheets==null) 134 sheets = Dispatch.get(workbook, "sheets").toDispatch(); 135 return sheets; 136 } 137 138 /** 139 * 獲得當前sheet 140 * @return 141 */ 142 public Dispatch getCurrentSheet() { 143 currentSheet = Dispatch.get(workbook, "ActiveSheet").toDispatch(); 144 return currentSheet; 145 } 146 147 /** 148 * 經過工做表名字獲得工做表 149 * @param name sheetName 150 * @return 151 */ 152 public Dispatch getSheetByName(String name) { 153 return Dispatch.invoke(getSheets(), "Item", Dispatch.Get, new Object[]{name}, new int[1]).toDispatch(); 154 } 155 156 /** 157 * 經過工做表索引獲得工做表(第一個工做簿index爲1) 158 * @param index 159 * @return sheet對象 160 */ 161 public Dispatch getSheetByIndex(Integer index) { 162 return Dispatch.invoke(getSheets(), "Item", Dispatch.Get, new Object[]{index}, new int[1]).toDispatch(); 163 } 164 165 /** 166 * 獲得sheet的總數 167 * @return 168 */ 169 public int getSheetCount() { 170 int count = Dispatch.get(getSheets(), "count").toInt(); 171 return count; 172 } 173 174 /** 175 * 調用excel宏 176 * @param macroName 宏名 177 */ 178 public void callMacro(String macroName){ 179 Dispatch.call(xl, "Run",new Variant(macroName)); 180 } 181 182 /** 183 * 單元格寫入值 184 * @param sheet 被操做的sheet 185 * @param position 單元格位置,如:C1 186 * @param type 值的屬性 如:value 187 * @param value 188 */ 189 public void setValue(Dispatch sheet, String position, String type, Object value) { 190 191 Dispatch cell = Dispatch.invoke(sheet, "Range", 192 Dispatch.Get, new Object[] { position }, new int[1]) 193 .toDispatch(); 194 Dispatch.put(cell, type, value); 195 } 196 197 /** 198 * 單元格讀取值 199 * @param position 單元格位置,如: C1 200 * @param sheet 201 * @return 202 */ 203 public Variant getValue(String position, Dispatch sheet) { 204 Dispatch cell = Dispatch.invoke(sheet, "Range", Dispatch.Get, 205 new Object[] { position }, new int[1]).toDispatch(); 206 Variant value = Dispatch.get(cell, "Value"); 207 return value; 208 } 209 210 private void initComponents(){ 211 workbook = null; 212 currentSheet = null; 213 sheets = null; 214 } 215 }
調用宏代碼
1 public void excelPictureGrab() throws Exception { 2 this.targetFile = new File(targetFilePath); 3 4 //複製文件 5 FileUtils.copyFile(xlsFile, targetFile); 6 7 logger.info("文件復至完成"); 8 9 //生成帶圖形的 excel 10 JacobExcelUtils tool = new JacobExcelUtils(); 11 try { 12 tool.OpenExcel(targetFilePath, false, false); 13 14 logger.info("打開Excel"); 15 16 //執行宏 複製爲圖片 17 tool.callMacro("copyImg"); 18 19 logger.info("處理宏完成"); 20 } catch (Exception e) { 21 throw new Exception("執行宏出錯," + e.getMessage()); 22 // TODO: handle exception 23 } finally { 24 // 關閉流 25 tool.CloseExcel(false, true); 26 } 27 }
五、 獲取圖表
1 //獲取圖片字節流 2 public static String getPic(String fileUrl,String backupUrl) throws Exception { 3 StringBuffer results = new StringBuffer(); 4 5 File tfdir = new File(backupUrl); 6 if (!tfdir.exists()) tfdir.mkdirs(); 7 8 InputStream inp = new FileInputStream(fileUrl); 9 HSSFWorkbook workbook = (HSSFWorkbook) WorkbookFactory.create(inp); 10 11 List<HSSFPictureData> pictures = workbook.getAllPictures(); 12 HSSFSheet sheet = (HSSFSheet) workbook.getSheetAt(0); //全部圖片都存在第一頁 13 14 int i = 0; 15 for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) { 16 HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); 17 18 if (shape instanceof HSSFPicture) { 19 HSSFPicture pic = (HSSFPicture) shape; 20 int pictureIndex = pic.getPictureIndex()-1; 21 22 //圖片名稱 23 int row = anchor.getRow1(); 24 25 System.out.println(anchor.getCol1()); 26 27 HSSFCell picCell = sheet.getRow(row).getCell(anchor.getCol1()); 28 29 String picName = ""; 30 if(picCell != null) { 31 picName = picCell.getStringCellValue(); 32 } 33 34 35 logger.info(i + "--->row." + anchor.getRow1() + ":cell." + anchor.getCol1() + ":pictureIndex." + pictureIndex); 36 37 HSSFPictureData picData = pictures.get(pictureIndex); 38 39 //備份並返回 圖片 40 if(picName != null && !"".equals(picName)) { 41 String result = BackupPic(picName, picData,backupUrl); 42 results.append(result); 43 results.append(","); 44 } 45 } 46 i++; 47 } 48 49 return results.toString(); 50 } 51 52 //備份圖片 53 private static String BackupPic(String picName,PictureData pic,String backupUrl) throws Exception { 54 String result = ""; 55 56 String pngImgUrl,jpgImgUrl; 57 String ext = pic.suggestFileExtension(); 58 byte[] data = pic.getData(); 59 if (ext.equals("png")) { 60 61 pngImgUrl = backupUrl + picName + "." + ext; 62 FileOutputStream out = new FileOutputStream( 63 pngImgUrl); 64 out.write(data); 65 out.close(); 66 67 //轉爲 jpg 68 jpgImgUrl = backupUrl + picName + ".jpg"; 69 ConvertPngToJpg(pngImgUrl,jpgImgUrl); 70 71 result = picName + ":" + DatatypeConverter.printBase64Binary(data); 72 } 73 74 return result; 75 } 76 77 //壓縮圖片 把PND圖片轉JPG 78 private static void ConvertPngToJpg(String pngImgUrl,String jpgImgUrl) { 79 BufferedImage bufferedImage; 80 try { 81 82 //read image file 83 bufferedImage = ImageIO.read(new File(pngImgUrl)); 84 85 // create a blank, RGB, same width and height, and a white background 86 BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(), 87 bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB); 88 newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null); 89 90 // write to jpeg file 91 ImageIO.write(newBufferedImage, "jpg", new File(jpgImgUrl)); 92 93 } catch (IOException e) { 94 95 e.printStackTrace(); 96 97 } 98 }