利用jqueryFrom傳檔案到servlet,以及兩個伺服器之間傳檔案和其他資料
阿新 • • 發佈:2018-12-15
專案背景:有兩個伺服器,一個是使用者操作的手機端伺服器,一個是後臺(響應前一個伺服器,並能訪問資料庫) 專案需求:使用者從手機端上傳身份證以及個人資訊,我們需要將資料傳給後臺,並且在資訊認證通過後將身份證照片存在後臺伺服器的D盤資料夾下。 jqueryForm上傳資料是利用的表單提交,下面是html頁面的form:
<form id="form1" action="../registerRealInfo" method="post" enctype="multipart/form-data" class="mui-input-group"> <input type="hidden" id="loginName" name="loginName"/> <input type="hidden" id="loginPwd" name="loginPwd"/> <div class="mui-input-row"> <label id="reName">真實姓名</label> <input type="text" id="realName" name="realName" autocomplete="off" class="dev-input" placeholder="請輸入身份證上的真實姓名" value="" /> </div> <div class="mui-input-row"> <label id="reNum">身份證號碼</label> <input type="text" id="IDCardNum" maxlength="18" name="IDCardNum" onkeyup="value=value.replace(/[\u4E00-\u9FA5]/g,'')" autocomplete="off" class="dev-input" placeholder="請輸入18位身份證號碼" value="" /> </div> <div class="title img-title" id="reImage">證件圖片</div> <ul class="mui-table-view mui-grid-view"> <li class="mui-table-view-cell mui-col-xs-12"> <a href="#"> <div class="image-box"> <input type="file" name="IDCardImage" id="IDCardImage" accept="image/*" class="choseBtn" /> <div id="forsee" class="upImageBox"></div> </div> <div class="mui-media-body" id="IdCard">身份證個人資訊面</div> </a> </li> </ul> </form>
下面是js方法,利用jqueryForm的ajaxSubmit可實現非同步的表單提交:
$('#comRegister').click(function(){ var options = { url: "../registerRealInfo", //提交地址:預設是form的action,如果申明,則會覆蓋 type: "post", //預設是form的method(get or post),如果申明,則會覆蓋 beforeSubmit: beforeCheck, //提交前的回撥函式 success: function (data) { //提交成功後的回撥函式 if(data.result=="success"){ $(location).attr('href','registerSuccessful.html?loginName='+loginName); }else if(data.result=="true"){ if(data.resultMsg == 1){//身份資訊驗證失敗 mui.toast(infoWrong); }else if(data.resultMsg == 2){//身份證圖片驗證失敗 mui.toast(photoWrong); }else if(data.resultMsg == 5){//每臺裝置每天認證次數限5次,請明天再來 mui.toast(timesLimited); } }else if(data.result=="false"){ mui.toast(registerFail); }else if(data.result=="done"){ mui.toast(alreadyDone); } }, error:function (data) { mui.toast(programError); }, target: "#output", //把伺服器返回的內容放入id為output的元素中 dataType: "json", //html(預設), xml, script, json...接受服務端返回的型別 clearForm: false, //成功提交後,是否清除所有表單元素的值 resetForm: false, //成功提交後,是否重置所有表單元素的值 timeout: 300000 //限制請求的時間,當請求大於300秒後,跳出請求 }; $('#form1').ajaxSubmit(options); });
**非同步的表單提交的目的:**常規的表單提交,無論後臺如何反饋資訊,都會重新整理頁面,而jqueryForm的ajaxSubmit既可實現表單提交,也能實現ajax的功能,保證頁面不會重新整理,等待後臺返回結果,再進行需要的操作。那麼為什麼不用ajax呢,因為ajax不能傳檔案。 下面是後臺servlet接收前端傳來的資料:
public class RegisterInfoServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); HttpSession session = request.getSession(); String ip = Util_GetData.getInboundIp(); //獲取IP String deviceName = Util_GetData.getDeviceSN(); String resultMsg = ""; String url = "http://"+ip+"/deviceRegister"; DiskFileItemFactory factory = new DiskFileItemFactory();//從這裡開始接受前端的資料 // 建立一個檔案上傳解析器 ServletFileUpload upload = new ServletFileUpload(factory); Map<String, String> strParams = new HashMap<>(); String loginName=null; List<FileItem> list = null; String filename=null; InputStream stream=null; try { list = upload.parseRequest(request);//獲取到前端所有的資料(即表單裡有name屬性的標籤) } catch (FileUploadException e) { e.printStackTrace(); } for(FileItem item : list) {//遍歷這個list if (item.isFormField()) {//如果fileitem中封裝的是普通輸入項的資料 String name = item.getFieldName(); String value = item.getString("UTF-8"); strParams.put(name,value); if(name.equals("loginName")){ loginName = value; } continue; } else {//如果fileitem中封裝的是上傳檔案 stream = item.getInputStream();//上傳檔案需要的檔案流引數 如果只有單個檔案,這裡就已經獲取了檔案的InputStream filename = item.getName();//上傳檔案需要的引數 這裡獲取了檔名稱 } } HttpConnectionUtil cnnUtil = new HttpConnectionUtil(); strParams.put("deviceName",deviceName);//把所有普通資料放入Map resultMsg = cnnUtil.uploadFile(url,stream,filename,strParams);//呼叫這個方法訪問另一個伺服器,此方法緊跟在下面 if(null != resultMsg && !"".equals(resultMsg) && resultMsg.indexOf("success") > 0){ session.setAttribute("loginName", loginName); } PrintWriter pw = response.getWriter(); pw.print(resultMsg); pw.flush(); pw.close(); } } //訪問後臺伺服器的方法 package com.util; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.Map; import java.util.UUID; /** * Java原生的API可用於傳送HTTP請求,即java.net.URL、java.net.URLConnection,這些API很好用、很常用, * 但不夠簡便; * * 1.通過統一資源定位器(java.net.URL)獲取聯結器(java.net.URLConnection) * 2.設定請求的引數 * 3.傳送請求 * 4.以輸入流的形式獲取返回內容 5.關閉輸入流 * @author H__D * */ public class HttpConnectionUtil { private static final int TIME_OUT = 80 * 1000; //超時時間 private static final String CHARSET = "utf-8"; //編碼格式 private static final String PREFIX = "--"; //字首 private static final String boundary = UUID.randomUUID().toString(); //邊界標識 隨機生成 private static final String CONTENT_TYPE = "multipart/form-data"; //內容型別 private static final String LINE_END = "\r\n"; /** * 檔案上傳的方法 * * @param actionUrl:上傳的路徑 * @param filename:檔名稱 * @param stream:上傳檔案需要的檔案流引數 * @return */ public String uploadFile(String actionUrl, InputStream stream,String filename,Map<String, String> strParams) { DataOutputStream ds = null; InputStream inputStream = null; InputStreamReader inputStreamReader = null; BufferedReader reader = null; StringBuffer resultBuffer = new StringBuffer(); try { // 統一資源 URL url = new URL(actionUrl); // 連線類的父類,抽象類 URLConnection urlConnection = url.openConnection(); // http的連線類 HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; // 設定是否從httpUrlConnection讀入,預設情況下是true; httpURLConnection.setDoInput(true); // 設定是否向httpUrlConnection輸出 httpURLConnection.setDoOutput(true); // Post 請求不能使用快取 httpURLConnection.setUseCaches(false); // httpURLConnection.setReadTimeout(TIME_OUT); // httpURLConnection.setConnectTimeout(TIME_OUT); // 設定請求的方法,預設是GET httpURLConnection.setRequestMethod("POST"); // 設定字元編碼連線引數 httpURLConnection.setRequestProperty("Connection", "Keep-Alive"); // 設定字元編碼 httpURLConnection.setRequestProperty("Charset", "UTF-8"); // 設定請求內容型別 httpURLConnection.setRequestProperty("Content-Type", CONTENT_TYPE+";boundary=" + boundary); // 設定DataOutputStream ds = new DataOutputStream(httpURLConnection.getOutputStream()); //引數上傳 ds.write(getStrParams(strParams).toString().getBytes());//普通資料上傳完成,這裡有個方法包裝普通資料的Map,在下面 ds.flush(); StringBuilder fileSb = new StringBuilder(); //檔案上傳 fileSb.append(PREFIX) .append(boundary) .append(LINE_END) /** * 這裡重點注意: name裡面的值為服務端需要的key 只有這個key 才可以得到對應的檔案 * filename是檔案的名字,包含字尾名的 比如:abc.png */ .append("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"" + LINE_END) .append("Content-Type: image/jpg" + LINE_END) //此處的ContentType不同於 請求頭 中Content-Type .append("Content-Transfer-Encoding: 8bit" + LINE_END) .append(LINE_END);// 引數頭設定完以後需要兩個換行,然後才是引數內容 ds.writeBytes(fileSb.toString()); ds.flush(); byte[] buffer = new byte[1024]; int length; while ((length = stream.read(buffer)) != -1) { ds.write(buffer, 0, length); } stream.close(); ds.writeBytes(LINE_END); //請求結束標誌 ds.writeBytes(PREFIX + boundary + PREFIX + LINE_END); ds.flush(); ds.close(); //檔案上傳完成 if (httpURLConnection.getResponseCode() >= 300) { throw new Exception("請求失敗:" + httpURLConnection.getResponseCode()); } if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { inputStream = httpURLConnection.getInputStream(); inputStreamReader = new InputStreamReader(inputStream); reader = new BufferedReader(inputStreamReader); String tempLine = null; resultBuffer = new StringBuffer(); while ((tempLine = reader.readLine()) != null) { resultBuffer.append(tempLine); } } } catch (Exception e) { e.printStackTrace(); } finally { if (ds != null) { try { ds.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (inputStreamReader != null) { try { inputStreamReader.close(); } catch (IOException e) { e.printStackTrace(); } } if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return resultBuffer.toString(); } } private static StringBuilder getStrParams(Map<String,String> strParams){ StringBuilder strSb = new StringBuilder(); for (Map.Entry<String, String> entry : strParams.entrySet() ){ strSb.append(PREFIX) .append(boundary) .append(LINE_END) .append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END) .append("Content-Type: text/plain; charset=" + CHARSET + LINE_END) .append("Content-Transfer-Encoding: 8bit" + LINE_END) .append(LINE_END)// 引數頭設定完以後需要兩個換行,然後才是引數內容 .append(entry.getValue()) .append(LINE_END); } return strSb; } }
檔案上傳很艱難,檔案接受更艱難。之前有過很多上傳檔案的方式,但苦於不知道後臺該如何接收檔案。這次的接收方式也很奇葩。
//設備註冊並實名認證
@RequestMapping(value = "/deviceRegister")
@ResponseBody
public String deviceRegister(HttpServletRequest req, HttpServletResponse res, @RequestParam("file") MultipartFile file, @RequestParam("loginName") String loginName, @RequestParam("loginPwd") String loginPwd, @RequestParam("realName") String realName, @RequestParam("IDCardNum") String IDCardNum, @RequestParam("deviceName") String deviceName){
//資料傳送完成,開始你的表演
}
沒錯,上面接收資料的方式就是在方法體裡面,通過@RequestParam和所有的name,接收對應的資料。 後續還會有各種情況和各種架構下,傳遞+接收檔案的部落格,哪天心情好就寫咯,反正都是我工作裡面碰到的,第一次開發,又沒有經驗,只能到處百度,到處拼接方法這樣子,唉,說不出的滋味。