背景:最近須要作一個excel模板導入的功能,以便用戶能夠本身增刪改查數據,固然,只有特別的用戶纔能有此權限,捋了捋思路,仍是從前端寫起前端
實現:c++
頁面最後的效果以下,能夠本身修改,刪除,導入導出數據,爲了統一規範,防止數據不規範解析不了,模板由咱們提供下載,用戶填充數據統一導入,ajax
涉及到機密,打碼請見諒。sql
頁面主要我分爲三大塊功能,json
一是分權分域,只有特定的用戶才能導入修改,刪除,添加數據,這個看你怎麼保存當前用戶,驗證下用戶權限等,這裏不作過多闡述:數組
二是數據的查詢,導出,由於以前作的幾乎都有這兩個功能,因此集成過來,須要看導出代碼的能夠看我以前的博客參考;app
三是數據導入,修改,刪除,添加和模板的下載,這裏主要說模板下載和導入數據的解析工具
模板下載這塊,前端用的按鈕點擊事件,window.location.href指定到後臺路徑,後臺模板下載方法代碼以下:post
public static void getTemplate(HttpServletRequest request, HttpServletResponse response,String filename) throws IOException { String path = TEMPLATE_PATH + filename; File file = new File(path); if(!file.exists()){ return; } response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename="+ new String(filename.getBytes("utf-8"), "ISO-8859-1")); BufferedInputStream bi = new BufferedInputStream(new FileInputStream(file)); OutputStream os = response.getOutputStream(); byte[] bytes = new byte[1024]; int i = bi.read(bytes); while (i != -1){ os.write(bytes, 0, i); i = bi.read(bytes); } if (bi != null) { try { bi.close(); } catch (IOException e) { e.printStackTrace(); } } }
這裏path我指定了一個位置來放模板下載的文件,由於模塊較多,因此按照名稱下載,url
導入模板,前端代碼以下:
<li class='item'> <input type="button" class="button" id="uploading" value="導入"> </li> <li class='item'> <input type="file" id="file1"> </li>
兩個按鈕,導入的按鈕綁定click事件,裏面只驗證了文檔的格式是否是excel,使用FormData對象做爲data上傳,FormData對象用以將數據編譯成鍵值對,以便用XMLHttpRequest
來發送數據,後臺使用MultipartFile對象接收:
click事件以下:
ExportIn: function () { if($("#file1").val().length <=0){ alert("請選擇文件"); return false; }else{ var filepath = $("#file1").val(); var extStart = filepath.lastIndexOf("."); var ext = filepath.substring(extStart,filepath.length).toUpperCase(); if (ext != ".XLSX" && ext != ".XLS" && ext != ".XLSM") { alert("請上傳excel格式文檔"); return false; } } //獲取到上傳的文件信息 var data =document.getElementById("file1").files[0]; var fromData = new FormData(); if(data != null){ fromData.append("file",data); $.ajax({ type: "post", url: dss.rootPath + "plugin/labourCompetition/NpsCompetitionScore_mobile_uploading", data: fromData, dataType: "json", contentType: false, processData: false, beforeSend: function () { dss.load(true); }, complete: function () { dss.load(false); }, success: function (data) { if (data.status != "OK") { alert(data.status); } else if (data.status == "OK") { alert("導入成功!"); } window.location.reload(); } }); } },
後臺使用MultipartFile 接收,綁定了前端的file參數,驗證文件是否爲空,而後判斷文件格式,是xls仍是xlsx格式,建立對應的對象解析,而後把數據存到list<String[]>中,
一行爲一個string數組,由於解析模板要複用,還有驗證不爲空,日期格式等因此有些地方寫的很麻煩,能夠用簡單的辦法解決,可是又不能影響複用的模塊,因此個人處理可
能麻煩了點,各位能夠按照自己的需求來。
後臺接收的方法以下:
@RequestMapping("plugin/labourCompetition/NpsCompetitionScore_mobile_uploading") @ResponseBody public JsonData importTemplate(@RequestParam(value = "file")MultipartFile file) throws Exception { JsonData jsonData = new JsonData(); Boolean bool = ImportExcel.checkFile(file); if(!bool){ jsonData.setStatus("文件類型不正確或爲空"); return jsonData; } //工具類在下面 HashMap<String, ArrayList<String[]>> hashMap = ImportExcel.analysisFile(file); ArrayList<String[]> arrayList = hashMap.get("OK"); if(arrayList == null){ Set<String> strings = hashMap.keySet(); String next = strings.iterator().next(); jsonData.setStatus(next); return jsonData; } //數據都在arrayList中,循環入庫,記得最後一個字段加上loadTime ConnectSettings dwConnect = commUtil.getDwConnect(); String sql = " INSERT INTO 表名 values "; String nowDate = ImportExcel.getNowDate(); for(int n = 0;n < arrayList.size();n++){ String[] str = arrayList.get(n); sql += " ( "; for(int num =0;num<str.length;num++){ sql += "'" +str[num]+"',"; if(num == str.length-1){ sql += "to_date('"+nowDate+"','yyyy-mm-dd hh24:mi:ss')"; } } if( n != arrayList.size()-1 ){ sql += " ),"; }else{ sql += " )"; } } System.err.println(sql); int i = DbHelper.executeNonQuery(sql, dwConnect); System.err.println("成功執行行數"+i); if(i < 1){ jsonData.setStatus("導入失敗"); return jsonData; } jsonData.setStatus("導入成功"); return jsonData; }
@Component public class ImportExcel { private static Calendar calendar = Calendar.getInstance(); private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月"); private static SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private static SimpleDateFormat simpleDateFormat3 = new SimpleDateFormat("yyyy/MM/dd"); //解析excel文件 public static HashMap<String, ArrayList<String[]>> analysisFile(MultipartFile file) throws IOException { HashMap<String, ArrayList<String[]>> hashMap = new HashMap<>(); //獲取workbook對象 Workbook workbook = null; String filename = file.getOriginalFilename(); InputStream inputStream = file.getInputStream(); //根據後綴名是否excel文件 if(filename.endsWith("xls")){ //2003 workbook = new HSSFWorkbook(inputStream); }else if(filename.endsWith("xlsx")){ //2007 workbook = new XSSFWorkbook(inputStream); } //建立對象,把每一行做爲一個String數組,因此數組存到集合中 ArrayList<String[]> arrayList = new ArrayList<>(); if(workbook != null){ //循環sheet,如今是單sheet for(int sheetNum = 0;sheetNum < workbook.getNumberOfSheets();sheetNum++){ //獲取第一個sheet Sheet sheet = workbook.getSheetAt(sheetNum); if(sheet == null){ hashMap.put("文件sheet爲空!",arrayList); return hashMap; } //獲取當前sheet開始行和結束行 int firstRowNum = sheet.getFirstRowNum(); int lastRowNum = sheet.getLastRowNum(); //循環開始,除了前兩行 for(int rowNum = firstRowNum + 2;rowNum <= lastRowNum;rowNum++){ //獲取當前行 Row row = sheet.getRow(rowNum); //獲取當前行的開始列和結束列 short firstCellNum = row.getFirstCellNum(); short lastCellNum = row.getLastCellNum(); //獲取總行數 int lastCellNum2 = row.getPhysicalNumberOfCells(); String[] strings = new String[lastCellNum2]; //循環當前行 for(int cellNum = firstCellNum;cellNum < lastCellNum;cellNum++){ Cell cell = row.getCell(cellNum); if( cell == null || "".equals(cell) || cell.getCellType()== Cell.CELL_TYPE_BLANK ){ hashMap.put("第"+(rowNum+1)+"行,第"+(cellNum+1)+"列爲空",arrayList); return hashMap; } String cellValue = ""; cellValue = getCellValue(cell); strings[cellNum] = cellValue; } arrayList.add(strings); } } } inputStream.close(); hashMap.put("OK",arrayList); return hashMap; } //把每個cell轉換爲string public static String getCellValue(Cell cell){ String cellValue = ""; if(cell == null){ return cellValue; } //把數字轉換成string,防止12.0這種狀況 if(cell.getCellType() == cell.CELL_TYPE_NUMERIC){ cell.setCellType(cell.CELL_TYPE_STRING); } //判斷數據的類型 switch (cell.getCellType()) { case Cell.CELL_TYPE_NUMERIC: //數字0 cellValue = String.valueOf(cell.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: //字符串1 cellValue = String.valueOf(cell.getStringCellValue()); break; case Cell.CELL_TYPE_BOOLEAN: //Boolean cellValue = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_FORMULA: //公式 //cellValue = String.valueOf(cell.getCellFormula()); try { cellValue = String.valueOf(cell.getNumericCellValue()); } catch (IllegalStateException e) { cellValue = String.valueOf(cell.getRichStringCellValue()); } break; case Cell.CELL_TYPE_BLANK: //空值 cellValue = ""; break; case Cell.CELL_TYPE_ERROR: //故障 cellValue = "非法字符"; break; default: cellValue = "未知類型"; break; } return cellValue; } //判斷row是否爲空 public static boolean isRowEmpty(Row row) { for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) { Cell cell = row.getCell(c); if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK) { return false; } } return true; } //檢查文件類型 public static Boolean checkFile(MultipartFile file){ //檢查文件是否爲空 boolean empty = file.isEmpty(); if(empty || file == null){ return false; } //檢查文件是不是excel類型文件 String filename = file.getOriginalFilename(); if(!filename.endsWith("xls") && !filename.endsWith("xlsx")){ return false; } return true; } //轉換excel導入以後時間變爲數字,月時間 public static String getCorrectMonth(int i){ calendar.set(1900,0,1); calendar.add(calendar.DATE,i); Date time = calendar.getTime(); String s = simpleDateFormat.format(time); return s; } //轉換excel導入以後時間變爲數字,年月日時間 public static String getCorrectDay(int i){ calendar.set(1900,0,-1,0,0,0); calendar.add(calendar.DATE,i); Date time = calendar.getTime(); String s = simpleDateFormat3.format(time); return s; } //獲取當前時間的字符串 public static String getNowDate(){ Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = simpleDateFormat.format(date); return format; } //文件讀取到指定的位置 public String saveFile(MultipartFile file) throws IOException { MultipartFile update = file; //文件中參數名字 String name = update.getName(); //文件名字 String originalFilename = update.getOriginalFilename(); //是否爲空 boolean empty = update.isEmpty(); //傳輸文件到指定路徑中 String path = "F://LDJS/boco/uploading/"+originalFilename; update.transferTo(new File(path)); //文件類型 String contentType = update.getContentType(); InputStream inputStream = update.getInputStream(); inputStream.close(); //是否存在此路徑 boolean path1 = new File(path).exists(); if(path1){ return "OK"; }else{ return "導入文件失敗"; } } //顯示時間,把數字轉換成時間類型的 public static String getExcelDate(Cell cell){ Date dateCellValue = cell.getDateCellValue(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); String format = simpleDateFormat.format(dateCellValue); return format; } public static String getDetailDate(String date){ int dayNum = (int)Double.parseDouble(date); String s1 = "0."+ date.split("\\.")[1]; String hour = Double.parseDouble(s1)*24 +""; int hourNum = Integer.parseInt(hour.split("\\.")[0]); String s2 = "0."+ hour.split("\\.")[1]; String minte = Double.parseDouble(s2)*60 +""; int minteNum = Integer.parseInt(minte.split("\\.")[0]); String s3 = "0."+ minte.split("\\.")[1]; String second = Double.parseDouble(s3)*60 +""; int secondNum = Integer.parseInt(second.split("\\.")[0]); calendar.set(1900,0,-1,0,0,0); calendar.add(calendar.DATE,dayNum); calendar.add(calendar.HOUR,hourNum); calendar.add(calendar.MINUTE,minteNum); calendar.add(calendar.SECOND,secondNum); Date time = calendar.getTime(); String s = simpleDateFormat2.format(time); return s; } //檢查是不是數字 public static Boolean checkWhetherNumber(String str){ try { BigDecimal bigDecimal = new BigDecimal(str); }catch (Exception e){ return false; } return true; } //檢查是否是時間類型 public static Boolean checkWhetherDate(String str){ try { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); // 設置lenient爲false. 不然SimpleDateFormat會比較寬鬆地驗證日期,好比2007/02/29會被接受,並轉換成2007/03/01 simpleDateFormat.setLenient(false); simpleDateFormat.parse(str); }catch (Exception e){ return false; } return true; } //檢查是否是時間類型 public static Boolean checkWhetherDate2(String str){ try { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd"); simpleDateFormat.setLenient(false); simpleDateFormat.parse(str); }catch (Exception e){ return false; } return true; } //檢查是否是月的時間類型 public static Boolean checkWhetherMonth(String str){ try { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月"); simpleDateFormat.setLenient(false); simpleDateFormat.parse(str); }catch (Exception e){ return false; } return true; } }