花了一天半的時間學習了一下導入Excel用戶表,調用存儲過程,主要是學習存儲過程。由於以前沒有具體在項目中應用過。html
這裏咱們採用導入Excel到臨時表,而後存儲過程當中讀取臨時表判斷數據類型和數據格式,而後保存到正式表。java
導入Excel採用spring 的POI技術。spring
本文內容較多,請選擇性閱讀。sql
controller裏面的代碼:jsp
/** * Excel導入用戶表,調用存儲過程,先導入臨時表,再在存儲過程當中判斷,判斷經過後導入正式表,錯誤的則記錄錯誤日誌表中。 lijianbo * * @param request * @param respnse * @throws Exception */ public void excelImport(HttpServletRequest request, HttpServletResponse response, UpLoadFile upLoadFile) throws Exception { ExcelImportResult excelToUserTemp = new ExcelImportResult(); try { response.setCharacterEncoding("GBK"); if (upLoadFile == null || upLoadFile.isEmpty()) { response.getWriter().println("<script>parent.uploadCallback('0','請選擇導入的文件');</script>"); return; } /** * 清空臨時表 <select id="truncate" > truncate table USERTEMP </select> */ excelImportManager.truncate(); /** * 讀取Excel數據封裝爲List */ excelToUserTemp = saveExcelToUserTemp(request, response, upLoadFile); if (excelToUserTemp.getResultFlag() == 0) { response.setCharacterEncoding("UTF-8"); response.getWriter().println( "<script>parent.uploadCallback('0','" + excelToUserTemp.getErrorMsg() + "');</script>"); return; } else {// 保存數據到臨時表 @SuppressWarnings("unchecked") List<String> resultList = (List<String>) excelToUserTemp.getResultList(); if (resultList != null && resultList.size() > 0) { for (String sqlStr : resultList) { this.excelImportManager.excuteInsertSql(sqlStr); } } } HashMap<String, String> parmMap = new HashMap<String, String>(); parmMap.put("totalCount", ""); // 調用存儲過程,判斷數據格式,保存數據到正式表,記錄錯誤日誌 userManager.batchImportUser(parmMap); String totalCount = parmMap.get("totalCount"); System.out.println("保存的總記錄數爲:" + totalCount); response.setCharacterEncoding("UTF-8"); response.getWriter().println("<script>parent.uploadCallback('0','導入成功!共導入" + totalCount + "條');</script>"); } catch (Exception e) { response.setCharacterEncoding("UTF-8"); response.getWriter().println( "<script>parent.uploadCallback('0','導入失敗!'" + excelToUserTemp.getErrorMsg() + ");</script>"); e.printStackTrace(); } } /** * 導入Excel到臨時表 * * @throws IOException */ public ExcelImportResult saveExcelToUserTemp(HttpServletRequest request, HttpServletResponse response, UpLoadFile upLoadFile) throws Exception { String result = ""; ExcelImportResult excelImportResult = new ExcelImportResult(); List<String> dataList = new ArrayList<String>(); // 建立工做簿 Workbook wb = WorkbookFactory.create(upLoadFile.getFile().getInputStream()); // 取得第一個sheets Sheet sheet = wb.getSheetAt(0); // 最大的行數 int lastRowNum = sheet.getLastRowNum(); // 檢查表的列數是否和模板一致 result = excelLineCheck(sheet); if ("true".equals(result)) { // 讀取excel內容 for (int i = 1; i <= lastRowNum; i++) { Row row = sheet.getRow(i); // 獲取行(row)對象 if (row == null) { // row爲空的話,不處理 continue; } String sqlvalue = ""; for (int j = 0; j < 4; j++) { Cell cell = row.getCell(j); // 得到單元格(cell)對象 // 將單元格的數據添加至一個對象 在sql中 sqlvalue = sqlvalue + "'" + cell.toString() + "',"; } sqlvalue = sqlvalue.substring(0, sqlvalue.length() - 1); String sql = "insert into USERTEMP(ID,NAME,CARDTYPE,CARDNO,STATUS) values(SEQ_USERTEMP.NEXTVAL," + sqlvalue + ")"; System.out.println("sql:" + sql); dataList.add(sql); excelImportResult.setResultList(dataList); excelImportResult.setResultFlag(1); } } else { excelImportResult.setErrorMsg(result); excelImportResult.setResultFlag(0); } return excelImportResult; } /** * 檢查Excel的列是否與模板一致 * @param sheet * @return */ private String excelLineCheck(Sheet sheet) { /** * getPhysicalNumberOfRows()獲取的是物理行數,也就是不包括那些空行(隔行)的狀況。 * getLastRowNum()獲取的是最後一行的編號(編號從0開始) */ // 物理行數(不包括隔行) int rowNumbers = sheet.getPhysicalNumberOfRows(); if (rowNumbers == 0) { return "excel中數據爲空!"; } Row excelRow = sheet.getRow(0); int excelFirstRow = excelRow.getFirstCellNum(); int excelLastRow = excelRow.getLastCellNum(); if (4 != (excelLastRow - excelFirstRow)) { System.out.println("模版列數與excel列數不相符,請檢查"); return "模版列數與excel列數不相符,請檢查"; } else { return "true"; } }
user.xml裏面調用存儲過程。參數咱們只有一個返回參數count,即成功導入的條數。ide
<!-- 存儲過程 --> <parameterMap id="map_batchImportUser" type="java.util.HashMap"> <parameter property="totalCount" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT" /> </parameterMap> <select id="batchImportUser" parameterMap="map_batchImportUser" statementType="CALLABLE" > <![CDATA[ {call BATCHIMPORTUSER(?)} ]]> </select>
存儲過程BATCHIMPORTUSER爲:oop
CREATE OR REPLACE procedure "BATCHIMPORTUSER"(TOTALCOUNT out VARCHAR2) is v_sql varchar2(2000); excellogid NUMBER; userId NUMBER; totalCount1 NUMBER; cardtype varchar2(255); status varchar2(125); cardNo varchar2(255); flag NUMBER; Cursor cursor is select * from USERTEMP;-- 顯性遊標,cursor 存儲了全部數據 begin dbms_output.put_line('start--BATCHIMPORTUSER'); -- 讀取臨時表,驗證數據。 totalCount1:=0; TOTALCOUNT:=0; for us in cursor LOOP if us.CARDTYPE ='×××' then cardtype:=1; else if us.CARDTYPE ='護照' then cardtype:=2; else if us.CARDTYPE ='駕駛證' then cardtype:=3; else -- 保存錯誤日誌,證件類型錯誤 v_sql := 'SELECT SEQ_EXCEL_LOG.NEXTVAL FROM dual'; execute immediate v_sql into excellogid; INSERT INTO EXCEL_LOG(ID,ROW_NO,CODE,ERROR_FIELD,TYPE,CREATE_TIME,BATCH_NO,BATCH_NAME,REMARK ) VALUES (excellogid,'','','cardtype','1',sysdate,'',us.name,'證件類型錯誤'); flag:=0; end if; end if; end if; if us.STATUS ='正常' then status:=2; else if us.STATUS ='異常' then status:=1; else -- 保存錯誤日誌,狀態錯誤 v_sql := 'SELECT SEQ_EXCEL_LOG.NEXTVAL FROM dual'; execute immediate v_sql into excellogid; INSERT INTO EXCEL_LOG( ID,ROW_NO,CODE,ERROR_FIELD,TYPE,CREATE_TIME,BATCH_NO,BATCH_NAME,REMARK ) VALUES (excellogid,'','','status','2',sysdate,'',us.name,'狀態錯誤,只能填正常、異常'); flag:=0; end if; end if; --判斷是否爲數字 if translate(replace(us.CARDNO,'0',''), '0123456789', '$') is not null then -- 保存錯誤日誌,證件號格式錯誤。 v_sql := 'SELECT SEQ_EXCEL_LOG.NEXTVAL FROM dual'; execute immediate v_sql into excellogid; INSERT INTO EXCEL_LOG( ID,ROW_NO,CODE,ERROR_FIELD,TYPE,CREATE_TIME,BATCH_NO,BATCH_NAME,REMARK ) VALUES (excellogid,'','','cardNo','3',sysdate,'',us.name,'證件號格式錯誤,必須爲字母數字格式'); flag:=0; else cardNo:=us.CARDNO; end if; v_sql := 'SELECT SEQ_USERS.NEXTVAL AS id FROM dual'; execute immediate v_sql into userId; --用戶數據導入 if flag=0 then null; else INSERT INTO USERS(ID,COMPANY_ID,NAME,EMAIL,STATUS,PHONE,GMT_UPDATE_PWD,CONTACT_TYPE,MOBILE,IDX_NUM, ID_TYPE,ID_NO,ID_EXPIRE_DATE,ID_TYPE2,ID_NO2,SEX,ETHNICITY,NATION,POST_ADDRESS,RESIDENCE_ADDRESS,HOMETOWN, BIRTHDAY,BANK,BANK_ACCOUNT_NO,MARITAL_STATUS,FINGER_PRINT ,BLOOD_TYPE,HOBBY,WEI_XIN_ID,QQ,CHANGE_BY, CHANGE_AT,CREATE_BY,CREATE_AT,PROVIDER_ID, LOGIN_ID,PASSWORD ) VALUES (userId,'', us.NAME,'',status,'','','','','',cardtype,cardNo,'','','','','','','','','','','','','','','','','','','','','',sysdate,'','',''); totalCount1:=totalCount1+1; end if; end LOOP; totalCount:=totalCount1; end ;
總結:學習
①能夠直接在sql中用SEQ_USERTEMP.NEXTVAL 表示自增的主鍵ID(前提是已經建立了序列 SEQ_USERTEMP)this
這裏還要注意zhangs等字符串要加單引號,不然會報錯。日誌
INSERT INTO USERTEMP(id,name,cardtype,cardno,status) VALUES(SEQ_USERTEMP.NEXTVAL,'zhangs','1','511322','2');
②邏輯判斷時,若是隻是須要判讀是否成功,則通常返回TRUE或FALSE。
若是要根據不一樣的狀況處理,則須要封裝到一個類或map中,根據不一樣的flag處理。
若是是最後返回頁面了,則一般爲成功或失敗,這裏則用try--catch。
③POI技術:
*主要就是建立工做簿workbook
*建立表sheets
*獲取最大行,循環,
*對每一行數據循環,取單元格。
*處理具體的單元格。
/** * 導入Excel到臨時表 * * @throws IOException */ public ExcelImportResult saveExcelToUserTemp(HttpServletRequest request, HttpServletResponse response, UpLoadFile upLoadFile) throws Exception { String result = ""; ExcelImportResult excelImportResult = new ExcelImportResult(); List<String> dataList = new ArrayList<String>(); // 建立工做簿 Workbook wb = WorkbookFactory.create(upLoadFile.getFile().getInputStream()); // 取得第一個sheets Sheet sheet = wb.getSheetAt(0); // 最大的行數 int lastRowNum = sheet.getLastRowNum(); // 檢查表的列數是否和模板一致 result = excelLineCheck(sheet); if ("true".equals(result)) { // 讀取excel內容 for (int i = 1; i <= lastRowNum; i++) { Row row = sheet.getRow(i); // 獲取行(row)對象 if (row == null) { // row爲空的話,不處理 continue; } String sqlvalue = ""; for (int j = 0; j < 4; j++) { Cell cell = row.getCell(j); // 得到單元格(cell)對象 // 將單元格的數據添加至一個對象 在sql中 sqlvalue = sqlvalue + "'" + cell.toString() + "',"; } sqlvalue = sqlvalue.substring(0, sqlvalue.length() - 1); String sql = "insert into USERTEMP(ID,NAME,CARDTYPE,CARDNO,STATUS) values(SEQ_USERTEMP.NEXTVAL," + sqlvalue + ")"; dataList.add(sql); excelImportResult.setResultList(dataList); excelImportResult.setResultFlag(1); } } else { excelImportResult.setErrorMsg(result); excelImportResult.setResultFlag(0); } return excelImportResult; }
④存儲過程當中的,在loop循環中繼續下一次循環,怎麼作?至關於Java中的continue。
?????
⑤獲取Excel文件:
jsp頁面上傳文件:
<tr> <td> <div class="file_down"> <input name="file" type="file" id="file" style="width:90%"/> </div> </td> </tr>
後臺能獲取到一個:
UpLoadFile upLoadFile public class UpLoadFile{ //文件 二進制 protected MultipartFile file; protected String busiAlias; protected Long busiId; protected String description; protected Long categoryId; protected Long upLoadStaffId; protected String ifDown; }
這樣就能獲得Excel文件MultipartFile。