轉發博客原址:https://segmentfault.com/a/1190000015718785
表單form的提交和servlet的取值
一、前言
對於后端開發來說,經常要和前端進行聯系的兩個面就是:1、表單form提交至servlet。2、ajax提交至servlet進行處理。
顯然,有必要對這兩個常用的功能進行一次梳理。
1、一個中文亂碼的坑
在表單傳值和后台進行交流的時候,一個最大的坑就是中文的亂碼問題了。這個坑的具體分析不過多闡述,最佳實踐就是: 使用post
方式進行數據的提交,后台設置字符集過濾器,對request
、response
的字符集都設置為utf-8
。
2、表單form的enctype字段
HTML表單如何打包數據文件是由enctype這個屬性決定的。enctype有以下幾種取值:
-
application/x-www-form-urlencoded
在發送數據之前,編碼所有字符(空格被編碼為’+’,特殊字符被編碼為ASCII十六進制字符,中文會被編碼,英文不會)。此時,數據是以編碼后的字符串形式進行傳輸。 -
multipart/form-data
不對字符編碼。在使用包含文件上傳控件的表單時,必須使用該值。此時,數據是以二進制流的形式進行傳輸。 -
text/plain
空格轉換為 “+” 加號,但不對特殊字符編碼。
默認值是enctype=application/x-www-form-urlencoded
,所以表單的內容會按URL規則編碼,然后根據表單的提交方法:
-
method="get"
,編碼后的表單內容附加在請求連接后 -
method="post"
,編碼后的表單內容作為post請求的正文內容
二、使用action
的表單
前端的表單,在填寫了數據之后將數據發送給后端進行處理。這里,我們所指的表單意為通過action
字段進行提交,通過ajax
模擬提交的情況放在下一大點中討論。
而這里的表單又分為2種情況:
- 表單form單純的只有數據項,只提交文本數據,通常是
key-value
的形式,對於復選框亦如此。 - 表單form既有文本數據項,又有文件數據,即包含
<input type="file" ...>
字段。
1、只提交文本數據的表單
例如表單:
<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中獲取數據:
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
。
傳輸方式: 數據傳輸方式method
: 如果使用get
,那么該字符串會追加到請求的url地址后面;而如果使用post
,那么打開調試台,查看Form Data
項也可以查看到字符串。
這種表單提交數據的方式最為簡單。
2、提交文本數據和文件數據的表單
例如表單:
<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
。
3、servlet的處理再談一談
既然我們在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技術,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()
方法。第2、3層都是調用了第1層來實現的。
1、一個提交后頁面自動刷新的坑
有時候,在點擊提交之后,頁面會自動刷新,我們無法查看相關的數據,這是一個大坑。正確的解決方法,使用<input type="button" value="提交" />
這個按鈕來進行事件綁定並提交。當然,這是針對ajax來用的。
2、 僅發送請求至servlet,接收返回數據
當我們不需要發送數據的時候,其實只需要在一個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();
3、 攜帶文本數據,發送請求至servlet,接收返回數據
有的時候,我們需要攜帶一些數據,可以是常見的表單,也可以是一些零散的數據。在這種情況下,我們需要將數據封裝成json
數據格式進行傳輸。
3.1 第一種封裝的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處理代碼:(接收數據,返回數據)