转发博客原址: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处理代码:(接收数据,返回数据)