今天接到項目中的一個功能,要實現excel的導入,導出功能。這個看起來思路比較清楚,但是做起了就遇到了不少問題。
不過核心的問題,大家也不會遇到了。每個項目前台頁面,以及數據填充方式都不一樣,不過大多都是以json數據填充的。在導入excel填充json數據到頁面時,真的讓我差點吐血了。在做這個導入導出的時候,那一個禮拜都是黑暗的。
好了,廢話不多說了,我今天就給大家展示這個兩個功能的核心點,excel生成json數據和json數據生成excel文件。
一:從上傳文件到服務器,后台java解析,返回excel的json數據到前台。我自己從新做了一個簡單的測試項目,需要演示項目的(struts2),下面評論出來,謝謝大家支持。
1.excel生成json數據,用於導入excel文件到頁面中。
2.可以使用jxl,或者poi去實現這個,我兩種方式都采用了,下面是jar包(標記的jar是核心excel轉json數據的,包括jxl和poi,其它jar是項目的)
3.還是和上傳文件一樣,使用ajax,formdata對象將文件傳輸到后台,此時生成的是二進制文件,需要在服務器上生成所要的文件。
4.調用方法將上傳的文件轉化為json數據,使用poi要注意了,03版和07版使用的對象不一樣,代碼中有說明。
4.將得到的json數據返回前台。
5.下面是效果圖,最后面就附上源碼。
這是后台java處理代碼。
package com.pan.files.action; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; 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.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSON; import org.apache.commons.io.FileUtils; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFDataFormat; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.struts2.ServletActionContext; /*import org.springframework.web.multipart.MultipartFile;*/ public class ImportExcel { private File files; //上傳的文件路徑 private String filesFileName; //文件名 public File getFiles() { return files; } public void setFiles(File files) { this.files = files; } public String getFilesFileName() { return filesFileName; } public void setFilesFileName(String filesFileName) { this.filesFileName = filesFileName; } /* 這個是jxl方式 dir:文件地址 */ /*public static String excelToJson(File dir ) throws BiffException, IOException { jxl.Workbook wb =jxl.Workbook.getWorkbook(dir); // 從文件流中獲取Excel工作區對象(WorkBook) jxl.Sheet sheet = wb.getSheet(0); // 從工作區中取得頁(Sheet) jxl.Cell[] header = sheet.getRow(0); String json1 = ""; String[] arry = new String[sheet.getRows()]; for (int i = 1; i < sheet.getRows(); i++) { // 循環打印Excel表中的內容 Map hashMap = new HashMap(); ArrayList List = new ArrayList(); for (int j = 0; j < sheet.getColumns(); j++) { jxl.Cell cell = sheet.getCell(j, i); List.add(cell.getContents()); } // 這個json字符串就是我們想要的,實際應用中可以直接返回該字符串 // String json = JSONObject.toJSONString(hashMap); // String json = JSONObject.toJSONString(List); String json = com.alibaba.fastjson.JSONArray.toJSONString(List); json1 += json+","; } return "["+ json1.substring(0,json1.length()-1)+"]excel"; } */ public void targetFile() throws Exception { //根據服務器的文件保存地址和原文件名創建目錄文件全路徑 String dirs= ServletActionContext.getServletContext() .getRealPath("/image"); if (files != null){ File savedir = new File(dirs) ; if (! savedir.exists()) { savedir.mkdirs() ; } } //將上傳到服務器上的二進制文件寫成實際文件 File savefile = new File(dirs, filesFileName); FileUtils.copyFile(files, savefile) ; // String paremt = excelToJson(savefile); LinkedHashMap<String, String> sjson = excelTojson(savefile); HttpServletResponse response = ServletActionContext.getResponse(); response.setHeader("Content-type", "text/html;charset=UTF-8"); //這句話的意思,是告訴servlet用UTF-8轉碼,而不是用默認的ISO8859 response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); // copy(this.files, di); out.println(sjson); } public static LinkedHashMap<String,String> excelTojson(File file) throws IOException, Exception { // 返回的map LinkedHashMap<String,String> excelMap = new LinkedHashMap<>(); // Excel列的樣式,主要是為了解決Excel數字科學計數的問題 CellStyle cellStyle; // 根據Excel構成的對象 Workbook wb; // 如果是2007及以上版本,則使用想要的Workbook以及CellStyle if(file.getName().endsWith("xlsx")){ //07及07以后版本 wb = new XSSFWorkbook(new FileInputStream(file)); XSSFDataFormat dataFormat = (XSSFDataFormat) wb.createDataFormat(); cellStyle = wb.createCellStyle(); // 設置Excel列的樣式為文本 cellStyle.setDataFormat(dataFormat.getFormat("@")); }else{ //03版本 POIFSFileSystem fs = new POIFSFileSystem(file); wb = new HSSFWorkbook(fs); HSSFDataFormat dataFormat = (HSSFDataFormat) wb.createDataFormat(); cellStyle = wb.createCellStyle(); // 設置Excel列的樣式為文本 cellStyle.setDataFormat(dataFormat.getFormat("@")); } // sheet表個數 int sheetsCounts = wb.getNumberOfSheets(); // 遍歷每一個sheet for (int i = 0; i < sheetsCounts; i++) { Sheet sheet = wb.getSheetAt(i); // 一個sheet表對於一個List List list = new LinkedList(); // 將第一行的列值作為正個json的key String[] cellNames; // 取第一行列的值作為key Row fisrtRow = sheet.getRow(0); // 如果第一行就為空,則是空sheet表,該表跳過 if(null == fisrtRow){ continue; } // 得到第一行有多少列 int curCellNum = fisrtRow.getLastCellNum(); // 根據第一行的列數來生成列頭數組 cellNames = new String[curCellNum]; // 單獨處理第一行,取出第一行的每個列值放在數組中,就得到了整張表的JSON的key for (int m = 0; m < curCellNum; m++) { Cell cell = fisrtRow.getCell(m); // 設置該列的樣式是字符串 cell.setCellStyle(cellStyle); cell.setCellType(Cell.CELL_TYPE_STRING); // 取得該列的字符串值 cellNames[m] = cell.getStringCellValue(); } for (String s : cellNames) { } // 從第二行起遍歷每一行 int rowNum = sheet.getLastRowNum(); System.out.println("總共有 " + rowNum + " 行"); for (int j = 1; j <= rowNum; j++) { // 一行數據對於一個Map LinkedHashMap rowMap = new LinkedHashMap(); // 取得某一行 Row row = sheet.getRow(j); int cellNum = row.getLastCellNum(); // 遍歷每一列 for (int k = 0; k < cellNum; k++) { Cell cell = row.getCell(k); cell.setCellStyle(cellStyle); cell.setCellType(Cell.CELL_TYPE_STRING); // 保存該單元格的數據到該行中 rowMap.put(cellNames[k],cell.getStringCellValue()); } // 保存該行的數據到該表的List中 list.add(rowMap); } // 將該sheet表的表名為key,List轉為json后的字符串為Value進行存儲 excelMap.put(sheet.getSheetName(),JSON.toJSONString(list,false)); } wb.close(); return excelMap; } public static void main(String [] args) throws FileNotFoundException{ // createJson(); } }
這是前台js文件:
$(function () { $("#confirm").on("click",function(){ var files = $("input").eq(0).val(); if(files==""){ alert("請先上傳文件"); } }); $("#cancel").on("click",function(){ // webform.close(); }); $("#fileUpload").change(function(){ var val = $(this).val(); var fileName = val.split("\\")[val.split("\\").length-1]; if (val.indexOf("xls") != -1 || val.indexOf("xlsx") != -1) { $("input").eq(0).val(fileName); $('#formFile').ajaxSubmit({ url:'excel_targetFile.action', type:'POST', // data:{scmd:''}, 需要傳什么參數自己配置 success:function(data){ $("#confirm").on("click",function(){ alert("導入成功"); }); $("#cancel").on("click",function(){ alert("取消導入"); }); }, error:function(xhr){ alert("上傳出錯"); } }); } else { alert("請選擇正確的文件格式!"); //清空上傳路徑 $(this).val(""); return false; } }); })
這是jsp頁面代碼:
<%@ 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"> <title>Insert title here</title> <script src="./js/jquery-1.9.1.min.js" type="text/javascript"></script> <script src="./js/jquery.form.js" type="text/javascript"></script> <script src="./js/excelJs.js" type="text/javascript"></script> <style type="text/css"> .file { position: relative; display: inline-block; background: #D0EEFF; border: 1px solid #99D3F5; border-radius: 4px; /* padding: 4px 12px; */ overflow: hidden; color: #1E88C7; text-decoration: none; text-indent: 0; line-height: 20px; top:6px; } .file input { position: absolute; font-size: 100px; right: 0; top: 0; opacity: 0; } .file:hover { background: #AADFFD; border-color: #78C3F3; color: #004974; text-decoration: none; } .positionFile{ margin-left: 10px; margin-top: 30px; } .poConfirm{ margin-top: 40px; margin-left: 65px; } </style> </head> <body > <form id="formFile"> <input id="textId" type="text" value="" class="positionFile" readonly="readonly"> <a href="javascript:;" class="file">點擊上傳文件 <input type="file" id="fileUpload" name="files" > </a> <br> <input type="button" id="confirm" value="確定" class="co-win-button poConfirm"> <input type="button" id="cancel" value="取消" class="co-win-button poConfirm"> </form> </body> </html>
好啦,到這里你以及看完了整個過程,重點是要理解其中的思路,尤其是轉化方法上面。下面我將介紹導出json數據到excel文件中,其實這個就簡單了就在后台將你的json數據調用轉化方法,然后寫入到excel文件中,返回前台設置響應讓其下載即可。
這個是導出excel核心的方法。
/* src:定義下載的文件路徑 */ public static JSONObject createExcel(String src, JSONArray json) { JSONObject result = new JSONObject(); // 用來反饋函數調用結果 try { // 新建文件 File file = new File(src); file.createNewFile(); OutputStream outputStream = new FileOutputStream(file);// 創建工作薄 jxl.write.WritableWorkbook writableWorkbook = jxl.Workbook.createWorkbook(outputStream); jxl.write.WritableSheet sheet = writableWorkbook.createSheet("First sheet", 0);// 創建新的一頁 // JSONArray jsonArray = json.getJSONArray("dt");// 得到data對應的JSONArray JSONArray jsonArray = json;// 得到data對應的JSONArray jxl.write.Label label; // 單元格對象 int column = 0; // 列數計數 // 將第一行信息加到頁中。如:姓名、年齡、性別 JSONObject first = jsonArray.getJSONObject(0); Iterator<String> iterator = first.keys(); // 得到第一項的key集合 while (iterator.hasNext()) { // 遍歷key集合 String key = (String) iterator.next(); // 得到key label = new jxl.write.Label(column++, 0, key); // 第一個參數是單元格所在列,第二個參數是單元格所在行,第三個參數是值 sheet.addCell(label); // 將單元格加到頁 } // 遍歷jsonArray for (int i = 0; i < jsonArray.size(); i++) { JSONObject item = jsonArray.getJSONObject(i); // 得到數組的每項 iterator = item.keys(); // 得到key集合 column = 0;// 從第0列開始放 while (iterator.hasNext()) { String key = iterator.next(); // 得到key String value = item.getString(key); // 得到key對應的value label = new jxl.write.Label(column++, (i + 1), value); // 第一個參數是單元格所在列,第二個參數是單元格所在行,第三個參數是值 sheet.addCell(label); // 將單元格加到頁 } } writableWorkbook.write(); // 加入到文件中 writableWorkbook.close(); // 關閉文件,釋放資源 } catch (Exception e) { result.put("result", "failed"); // 將調用該函數的結果返回 result.put("reason", e.getMessage()); // 將調用該函數失敗的原因返回 return result; } // result.put("result", "successed"); return result; }
雖然在項目運用到了這個,昨天自己又從新搭建項目給大家提供一個演示例子,真的又彌補到了很多東西,包括struts2的配置請求方式,json數據轉化解析過程,ajax請求機制,poi對excel,word等文件編輯操作等等。如果大家覺得可以請點個贊,你們的贊是我前進的動力。
另外大神們看了有什么問題請指出來,我虛心學習,需要演示項目源碼的就在下方評論出來,大家一起分享學習。
需要演示項目的到我github上下載, https://github.com/chenpanpan0809/MyProjcet
別忘了點波推薦哦,大神們(*^_^*)