對於後端開發來講,常常要和前端進行聯繫的兩個面就是:一、表單form提交至servlet。二、ajax提交至servlet進行處理。javascript
顯然,有必要對這兩個經常使用的功能進行一次梳理。html
在表單傳值和後臺進行交流的時候,一個最大的坑就是中文的亂碼問題了。這個坑的具體分析不過多闡述,最佳實踐就是: 使用post
方式進行數據的提交,後臺設置字符集過濾器,對request
、response
的字符集都設置爲utf-8
。前端
HTML表單如何打包數據文件是由enctype這個屬性決定的。enctype有如下幾種取值:java
application/x-www-form-urlencoded
在發送數據以前,編碼全部字符(空格被編碼爲’+’,特殊字符被編碼爲ASCII十六進制字符,中文會被編碼,英文不會)。此時,數據是以編碼後的字符串形式進行傳輸。 multipart/form-data
不對字符編碼。在使用包含文件上傳控件的表單時,必須使用該值。此時,數據是以二進制流的形式進行傳輸。 text/plain
空格轉換爲 「+」 加號,但不對特殊字符編碼。默認值是enctype=application/x-www-form-urlencoded
,因此表單的內容會按URL規則編碼,而後根據表單的提交方法:jquery
method="get"
,編碼後的表單內容附加在請求鏈接後method="post"
,編碼後的表單內容做爲post請求的正文內容action
的表單前端的表單,在填寫了數據以後將數據發送給後端進行處理。這裏,咱們所指的表單意爲經過action
字段進行提交,經過ajax
模擬提交的狀況放在下一大點中討論。web
而這裏的表單又分爲2種狀況:ajax
key-value
的形式,對於複選框亦如此。<input type="file" ...>
字段。例如表單:spring
<form action="/webapp/formServlet" method="post"> <input type="text" name="username"> <!-- 單選框 --> <input type="radio" name="sex" value="male">male <input type="radio" name="sex" value="female">female <!-- 下拉框 --> <select name="education"> <option value="primary">primary</option> <option value="middle">middle</option> <option value="high">high</option> </select> <!-- 複選框 --> <input type="checkbox" name="hobby" value="basket">basket <input type="checkbox" name="hobby" value="tennis">tennis <input type="checkbox" name="hobby" value="football">football <input type="submit" value="提交"> </form>
在servlet中獲取數據:apache
String username = request.getParameter("username"); String sex = request.getParameter("sex"); String education = request.getParameter("education"); String[] hobby = request.getParameterValues("hobby");
數據編碼: 對於純文本的表單,其字段enctype=application/x-www-form-urlencoded
是默認值,表示表單的數據進行url編碼,如:表單的數據被編碼成username=123&password=222
。json
傳輸方式: 數據傳輸方式method
: 若是使用get
,那麼該字符串會追加到請求的url地址後面;而若是使用post
,那麼打開調試臺,查看Form Data
項也能夠查看到字符串。
這種表單提交數據的方式最爲簡單。
例如表單:
<form action="/webapp/formServlet" method="post" enctype="multipart/form-data"> <input type="text" name="username"> <input type="password" name="password"> <input type="file" name="file"> <input type="submit" value="提交"> </form>
在servlet中獲取數據以及保存文件:
由於傳輸過來的是二進制流,所以沒法使用getParameter()
等現成的方法來獲取值。推薦使用apache upload
框架來進行數據的讀取操做。固然,servlet也有原生的方法來獲取,參考(https://docs.oracle.com/javae... 、(https://docs.oracle.com/javae... 。
傳輸方式: 由於是二進制流, 因此method
只能使用post
進行提交,沒法使用get
。
既然咱們在servlet中能夠獲取到表單傳過來的值了,那麼咱們的返回又應該是什麼樣的呢?對於使用action
提交的表單,咱們的servlet必須將請求轉發或者使用重定向,以此進行頁面的切換(跳轉)。若是想攜帶新的數據,只能在請求轉發的request
對象上進行數據的添加。
請求轉發:
request.setAttribute("msg","登陸成功!"); // 攜帶數據 request.getRequestDispatcher("/success.jsp").forward(request,response);
重定向:
response.sendRedirect("/webapp/success.jsp");
解讀
很明顯,直接使用action
提交是很很差的。由於在提交至servlet時,地址欄的路徑會變成指向servlet的路徑,而這時候,若是使用請求轉發的話,那麼地址欄的路徑並不會改變,這樣就不是很優雅。而若是使用重定向的話,就沒法攜帶數據,對於常見的登陸驗證(須要錯誤信息)就沒法完成了。另外一個缺點就是,不管是請求轉發仍是重定向,本來填寫的表單數據都被清空,這樣是極爲糟糕的。
表單提交的最多見場景,每每就是用戶登陸或者是文件上傳,這些都須要服務器作出反饋,鑑於上面所說的缺點,咱們就不會使用action
的表單,而是使用更爲強大ajax技術。
前言:
咱們先聊一聊ajax技術,ajax是發起一個http請求,固然能夠攜帶數據,這個數據是以字符串的形式來傳輸的。固然,這個請求被髮送至servlet進行處理,servlet返回處理後的信息,這個信息被ajax的回調函數所接受,而後ajax就能夠進行相應的操做了。
當使用ajax時,能夠沒有表單的存在,由於咱們不須要action
了,咱們只須要獲得要傳輸的數據便可。同時,對於type="submit"
字段也要當心設置,由於咱們其實能夠不設置該值,或者在js事件中進行表單提交的判斷。
區別:
ajax的過程和表單提交幾乎差很少,不一樣的是:ajax發出的http請求並非瀏覽器發出的請求,所以servlet是沒有辦法影響頁面的跳轉的 ,因此要想進行頁面的跳轉只能是ajax的回調函數中進行處理。而且大多數時候,servlet的處理也會返回json
數據至前臺。這裏的話,就涉及到json
數據的反序列化和java
對象(或者是Map
、List
)的序列化了。
緩存: ajax發出的請求一般會被瀏覽器緩存,所以咱們能夠應該拒絕緩存。一般是在url地址後面追加一個隨機字符參數,而使用jquery的ajax能夠設置cache:false
這個屬性就ok了。
jquery的ajax:
由於原生的ajax技術代碼較多,所以咱們使用jquery封裝好的ajax函數來說解其用法。在jQuery中,$.ajax()
方法屬於最底層的方法,第2層是$.load()
,$.get()
,和$.post()
,第3層是$.getScript()
和$.getJSON()
方法。第二、3層都是調用了第1層來實現的。
有時候,在點擊提交以後,頁面會自動刷新,咱們沒法查看相關的數據,這是一個大坑。正確的解決方法,使用<input type="button" value="提交" />
這個按鈕來進行事件綁定並提交。固然,這是針對ajax來用的。
當咱們不須要發送數據的時候,其實只須要在一個js的事件中使用ajax就能夠了,不須要表單。這種方式實際用的比較少。
一個觸發ajax的按鈕:
<button id="bt_1">ajax_1</button>
jquery代碼:(請求servlet,接收返回數據)
var bt_1=$("#bt_1"); bt_1.on("click",function () { $.ajax({ url:"/webTest/ajax1", // 請求的servlet type:"post", // 由於沒有攜帶數據,無所謂 async: true, // 異步 cache: false, // 不準緩存 success:function(data){ // 請求成功,200 console.log(data); }, error:function(error){ // 請求失敗 console.log(error); } }) })
servlet處理代碼:(返回數據)
PrintWriter out = null; try { out = response.getWriter(); // 打開response的輸入流 } catch (IOException e) { e.printStackTrace(); } out.print("I give u a feedback"); // 寫入信息到response out.close();
有的時候,咱們須要攜帶一些數據,能夠是常見的表單,也能夠是一些零散的數據。在這種狀況下,咱們須要將數據封裝成json
數據格式進行傳輸。
json
數據:對象形式jquery代碼:
var sub=$("#sub"); sub.on("click",function () { $.ajax({ url:"/webTest/ajax2", type:"post", async:true, cache: false, data: { // json數據(注意,不能使用JSON.stringify()方法,不然出錯) "username": "liSi", "password": "ps" }, success:function(data){ console.log(data); }, error:function(error){ console.log(error); } }) })
servlet處理代碼:(接收數據,返回數據)
String username = request.getParameter("username"); String password = request,getParameter("password"); PrintWriter out = null; try { out = response.getWriter(); // 打開response的輸入流 } catch (IOException e) { e.printStackTrace(); } out.print("I give u a feedback"); // 寫入信息到response中 out.close();
在這種狀況下,封裝的json數據由於比較簡單,因此數據被編碼成字符串發送至servlet,就和以前使用action
的表單提交文本數據的狀況同樣。
注意,一旦json
數據複雜一點點,如{"username":"liSi","hobby":{"todya":"ttennis"}}
;就沒法使用getParameter("hobby")
來獲取數據了,這也是下面要將的第二種封裝的json
數據。顯然,這種封裝的json
數據的獲取,是一種特殊狀況,在大多數不復制的狀況是一種很好的方式。
當咱們使用了表單的時候,若是咱們只是想傳輸表單的值,那麼就沒有必要手工取值化成json形式,jquery提供了相應的方法來簡化操做。固然,只是針對文本數據而言。
jquery代碼1:
var data_json = $("#form_1").serialize(); data: data_json,
這裏經過序列化函數,會自動把表單的數據轉化爲字符串形式(url),也就是和action
表單提交一致的效果。在servlet中能夠直接經過getParameter()
方法來獲取參數。
jquery代碼2:
var data_json = $("#form_1").serializeArray(); data: data_json,
這裏經過序列化函數,會自動把表單的數據轉化爲json數據格式,省去了手工封裝成json的過程。
json
數據:數組形式一旦json
數據變複雜,那麼在servlet中就沒法經過getParameter()
獲取數據了。這個時候咱們須要把json
數據先字符串化,使得json
在傳輸的時候就是原數據(打開調試臺看到的Form Data
就和json
原數據同樣)。
jquery代碼:
var sub=$("#sub"); var data_json=[{"sex": '男',"submit":"111"},{"sex": '女',"submit":"222"}]; sub.on("click",function () { $.ajax({ url:"/webTest/ajax2", type:"post", async:true, cache: false, data: JSON.stringify(data_json), // 先序列化json數據 success:function(data){ console.log(data); }, error:function(error){ console.log(error); } }) })
在這裏,json
數據就是比較複雜的了,咱們要先使用JSON.stringify()
序列化json
數據。
servlet代碼:
BufferedReader reader = request.getReader(); // 獲取請求的輸出流 String jsonData = ""; jsonData += reader.readLine(); reader.close(); // 獲取到一致的json數據 System.out.println(json); // [{"sex": '男',"submit":"111"},{"sex": '女',"submit":"222"}]
java操做json
數據:
對於獲得的json
數據,咱們須要反序列,把咱們須要的值給取出來。一般是使用json
的解析庫,如GSON、fastJson等。這裏咱們使用GSON來說解。
因爲篇幅的緣由,GSON
操做json
數據,序列化與反序列化的內容在另外一章中進行講解。總之,咱們能夠操做任何複雜的json
數據,而且從中取出咱們須要的屬性。
得益於json
數據格式,使得先後端之間的數據交流變得十分方便。具體如何在java中操做json,請看有關於json的文章。
ajax
技術參數解讀在ajax的代碼中,有幾個參數比較重要。
一、 contentType: "application/json;charset=utf-8"
這個參數是指明提交的數據的數據類型,不指明的話,默認是:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
。
而指明瞭數據格式爲json
的話,在後臺有些框架能夠直接獲取,好比說springmvc。
注意: 一旦使用了指明瞭數據類型是json以後,就應該使用JSON.stringify()
方法來處理json數據。在後臺的處理程序中就沒法使用getParameter()
方法來獲取值了。
二、 dataType:"json"
這個參數是指明返回的數據的數據類型,不指明的話,默認是:"text"
。
一樣的一句話,只要涉及到文件數據,那麼就是二進制流傳輸,是沒法使用getParameter()
直接獲取數據的。而且再囉嗦一句,之因此推薦使用ajax,就是由於它能夠作到頁面不跳轉的提交。
咱們仍是能夠選擇是否使用表單,這也無所謂。當multiple="multiple"
時,能夠一次上傳多個文件。
表單:
<form id="form_1"> <input type="text" name="user" id="user"> <input type="file" name="file" multiple="multiple" id="file"> <input type="button" id="sub" value="submit it"/> </form>
jquery代碼:
var formData = new FormData(); var name = $("input").val(); // formData對象放入值 formData.append("name",name); formData.append("file",$("#file")[0].files[0]); // 只選擇第一個文件 $.ajax({ url : Url, type : 'POST', data : formData, processData : false, // 告訴jQuery不要去處理髮送的數據 contentType : false, // 告訴jQuery不要去設置Content-Type請求頭 success:function(data){ console.log(data); }, error:function(error){ console.log(error); } });
固然,咱們能夠直接傳入表單對象。這樣更加快速。
var form_1 = document.getElementById("form_1"); var formData = new FormData(form_1); data: formData,
關於前端的表單提交數據至後臺servlet的總結就先告一段落了。內容上能夠分紅2塊,一是直接使用action
的表單提交,二是使用ajax
技術模擬的表單提交。而在數據上又能夠分紅2塊,一是隻含有文本數據,而是含有上傳文件。