一、表单重复提交
表单重复提交第一种情况:
提交完表单,服务器使用请求转来进行页面跳转。这个时候,用户按下功能键 F5,就会发起最后一次的请求,造成表单重复提交问题。这种情况可以使用重定向来进行跳转。
// 如果是请求转发的话,浏览器会保存最后一次请求,以及所有参数,刷新会继续提交表单项,
//使用重定向则是新的一次请求,重定向到list,相当于最后一次请求是list,所以即使刷新,还是在list页面
response.sendRedirect(request.getContextPath() + "/");
表单重复提交第二种情况:
用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候如果多点了几次提交操作,也会造成表单重复提交。
表单重复提交第三种情况:
用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器,然后重新提交,这样也会造成表单重复提交。
二、验证码解决表单重复提交的底层原理
使用谷歌 kaptcha 图片验证码
在 web.xml
中去配置用于生成验证码的 Servlet
程序
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Session中的验证码
String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
//删除Session中的验证码
request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
//1.获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
User user = WebUtils.copyParamToBean(request.getParameterMap(), new User());
//2.检查验证码是否正确
if (token != null && token.equalsIgnoreCase(code)){
//3.验证码正确,检查用户名是否可用
if (userService.existUsername(username)){
System.out.println("用户名[" + username + "]已存在!");
//把回显信息保存到request域中
request.setAttribute("msg","用户名已存在!");
request.setAttribute("username",username);
request.setAttribute("email",email);
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}else {
userService.registerUser(user);
request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request,response);
}
}else {
//把回显信息保存到request域中
request.setAttribute("msg","验证码错误!");
request.setAttribute("username",username);
request.setAttribute("email",email);
//4.验证码不正确,跳回注册页面
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}
还可以实现切换验证码
//给验证码绑定切换图片的单击事件
$("#code_img").click(function () {
//在事件响应的function函数中有一个this对象,这个this对象就是当前正在响应事件的dom对象
//这里的this就是验证码图片响应事件,所以this就表示<img/>这个标签
//src属性表示验证码img标签的图片路径,src可读可写,赋值之后会重新发起一次请求
//末尾加上时间戳是为了使得每次刷新验证码请求地址不一样,进而跳过浏览器缓存
this.src = "${basePath}/kaptcha.jpg";
});