回顾防止表单重复提交

当我们学习Session的时候已经通过Session来编写了一个防止表单重复提交的小程序了,我们来回顾一下我们当时是怎么做的:

  • 在Servlet上生成独一无二的token,保存在Session域中,并交给JSP页面
  • JSP页面在提交表单数据的时候,把token放在隐藏域中…一起带过去给Servlet
  • Servlet判断用户有没有带token值过来,判断token的值是否和Session的相匹配
  • 如果用户是第一次提交的话,那么就允许用户的请求,接着就把保存在Session中的token值去除
  • 等用户想要再次提交的时候,Servlet发现Session中并没有token了,所以不搭理用户的请求

我们以前写表达重复提交就花了这么几个步骤…如果有兴趣的同学可以看一下以前的实现思路:http://blog.csdn.net/hon_3y/article/details/54799494#t11


Struts2防止表单重复提交

Struts2是简化我们的开发的,表单重复提交也是一件非常常用的功能…Struts2也为我们实现了…当然啦,也是通过拦截器来实现

   <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>

它的实现原理和我们以前写的思路几乎一致…它不需要另外写一个组件来生成token值,struts2标签就有这么一个功能…因此是十分方便的

为了熟悉一下Struts2,我们也使用Struts2来编写一下上图的程序

编写DAO


package zhongfucheng.dao; import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import zhongfucheng.entity.User;
import zhongfucheng.utils.Utils2DB; import java.sql.SQLException;
import java.util.List; /**
* Created by ozc on 2017/5/3.
*/
public class UserDao { public void add(User user) {
try { String sql = "INSERT INTO user(id,username,cellphone,password,address) VALUES (?,?,?,?,?)";
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); queryRunner.update(sql, new Object[]{user.getId(), user.getUsername(), user.getCellphone(), user.getPassword(),user.getAddress()}); } catch (SQLException e) {
new RuntimeException("登陆失败了!");
}
} public User findUser(String id) {
try {
String sql = "SELECT * FROM user WHERE id=?";
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); return (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{id}); } catch (SQLException e) {
new RuntimeException("登陆失败了!");
}
return null;
} public List<User> getAll() { try {
String sql = "SELECT * FROM user";
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
return (List<User>) queryRunner.query(sql, new BeanListHandler(User.class));
} catch (SQLException e) {
new RuntimeException("登陆失败了!");
}
return null;
}
public void updateUser(User user) { try {
String sql = "UPDATE user SET username=?,password=?,cellphone=? WHERE id=?";
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); queryRunner.update(sql, new Object[]{user.getUsername(), user.getPassword(), user.getCellphone(), user.getId()});
} catch (SQLException e) {
new RuntimeException("登陆失败了!");
}
} }

编写service


package zhongfucheng.service; import zhongfucheng.dao.UserDao;
import zhongfucheng.entity.User;
import zhongfucheng.utils.WebUtils; import java.util.List; /**
* Created by ozc on 2017/5/3.
*/
public class Service { UserDao userDao = new UserDao(); public void add(User user) { //手动设置id,因为在数据库表我没使用自动增长id
user.setId(WebUtils.makeId()); //这是以前的表,规定要address,只能手动设置了
user.setAddress("广州");
userDao.add(user); } public User findUser(String id) { return userDao.findUser(id); } public List<User> getAll() { return userDao.getAll(); }
public void updateUser(User user) { userDao.updateUser(user); }
}

开发步骤

  • 编写添加用户JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
</head>
<body> <form action="${pageContext.request.contextPath}/user_register" method="post">
<table border="1"> <tr>
<td>用户名:<input type="text" name="username"></td>
</tr>
<tr>
<td> 密码:<input type="password" name="password"></td>
</tr>
<tr>
<td>电话:<input type="text" name="cellphone"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form> </body>
</html>
  • 使用了模型驱动封装数据,添加用户


    //这里一定要实例化
User user = new User(); public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} @Override
public User getModel() {
return user;
} /*******调用service********/
Service service = new Service(); public String register() throws Exception { service.add(user); //注册成功,就跳转到list()方法,list方法就跳转到查看所有用户页面了!
return list();
}
  • 列出全部的用户数据,提供修改功能,需要把id传递过去,明确修改的是哪一个用户

<%--
Created by IntelliJ IDEA.
User: ozc
Date: 2017/5/2
Time: 18:24
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>列出下载页面</title>
</head>
<body>
<table border="1" align="center">
<tr>
<td>用户id</td>
<td>用户姓名</td>
<td>用户密码</td>
<td>用户电话</td>
<td>操作</td>
</tr> <s:if test="#request.users!=null">
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>${user.cellphone}</td>
<td><a href="${pageContext.request.contextPath}/user_updatePage?id=${user.id}">修改</a></td>
</tr>
</c:forEach>
</s:if>
</table> </body>
</html>
  • Action得到web带过来的id,找到对象,添加到值栈中(数据回显)

public String updatePage() throws Exception { //得到用户带过来的id,根据id查找对象
User user222 = service.findUser(user.getId()); ActionContext.getContext().getValueStack().push(user222); return "updatePage";
}
  • 修改用户的JSP页面,使用Struts2提供的回显技术,并把id通过隐藏域带过去给Action..最终是通过id来修改用户的数据

<form action="${pageContext.request.contextPath}/user_update">
<table border="1"> <tr>
<td>用户名<s:textfield name="username"/></td>
</tr>
<tr>
<td>密码 <s:textfield name="password" /></td>
</tr>
<tr>
<td>电话<s:textfield name="cellphone"/></td>
</tr>
<s:hidden name="id"/> <tr>
<td><input type="submit" value="修改"></td>
</tr>
</table>
</form>

效果


防止表单重复提交

上面我们已经完成了大部分的功能了,但当我们如果提交之后,再刷新页面,那么表单的数据就会重复提交…我们使用Struts2我们提供的防止表单重复提交的功能把!

在需要提交的表单上使用token标签


<table border="1">
<s:token></s:token>
<tr>
<td>用户名:<input type="text" name="username"></td>
</tr>
<tr>
<td> 密码:<input type="password" name="password"></td>
</tr>
<tr>
<td>电话:<input type="text" name="cellphone"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
</tr>
</table>

在struts配置文件中配置拦截器

token拦截器默认是不会启动的,也就是说:需要我们手动配置

当我们配置拦截器的时候,Struts2默认的拦截器是不会执行的,所以要把Struts2默认的拦截器也写上


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"> <struts>
<constant name="struts.ui.theme" value="simple"/>
<package name="xxx" extends="struts-default"> <action name="user_*" class="zhongfucheng.action.UserAction" method="{1}"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="token">
<!-- 要拦截的方法! -->
<param name="includeMethods">register</param>
</interceptor-ref> <!--如果是list,那么就跳转到list的JSP页面-->
<result name="list"> /list.jsp</result> <!--请求跳转到修改页面-->
<result name="updatePage">/update.jsp</result> <!--如果校验成功,跳转到login.jsp页面回显-->
<result name="success">/login.jsp</result> <result name="redirectList" type="redirect">/user_list</result>
</action>
</package> <include file="config.xml"/> </struts>
  • 当我们重复提交的时候,它会报错,因此,如果它报错了,我们就跳转到register页面把

测试

Struts2第十三篇【防止表单重复提交】的更多相关文章

  1. Struts2笔记——利用token防止表单重复提交

    在一些项目中经常会让用户提交表单,当用户点击按钮提交后,如果再次浏览器刷新,这就会造成表单重复提交,若是提交的内容上传至服务器并请求数据库保存,重复提交的表单可能会导致错误,然后跳转到错误界面,这是一 ...

  2. spring boot 学习(七)小工具篇:表单重复提交

    注解 + 拦截器:解决表单重复提交 前言 学习 Spring Boot 中,我想将我在项目中添加几个我在 SpringMVC 框架中常用的工具类(主要都是涉及到 Spring AOP 部分知识).比如 ...

  3. struts2 模拟令牌机制防止表单重复提交

    web.xml: <?xml version="1.0" encoding="UTF-8"?><web-app version="3 ...

  4. 12、Struts2表单重复提交

    什么是表单重复提交 表单的重复提交: 若刷新表单页面, 再提交表单不算重复提交. 在不刷新表单页面的前提下: 多次点击提交按钮 已经提交成功, 按 "回退" 之后, 再点击 &qu ...

  5. Struts2防止表单重复提交

    1.说明 系统拦截器的应用. 表单重复提交:当使用请求转化进行跳转的时候,存在着表单重复提交的问题. 2.在表单中加入s:token 如果页面加入了struts2的标签,页面的请求必须进入struts ...

  6. 【转】Struts2解决表单重复提交问题

    用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此,重复提 ...

  7. [原创]java WEB学习笔记73:Struts2 学习之路-- strut2中防止表单重复提交

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. struts2视频学习笔记 29-30(Struts 2常用标签,防止表单重复提交)

    课时28 Struts 2常用标签解说 property标签 property标签用于输出指定值: <s:set name="name" value="'kk'&q ...

  9. struts2之防止表单重复提交

    struts.xml配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts ...

随机推荐

  1. 一个项目经理对主流项目管理工具的对比:禅道VS华为软件开发云

    禅道与软件开发云对比分析报告 1. 产品介绍 禅道是易软天创出品的一款项目管理软件,集产品管理.项目管理.测试管理.文档管理.组织管理于一体,覆盖了项目管理和测试管理的核心流程. 华为软件开发云 (D ...

  2. Oracle锁表查询与解锁

    锁表查询和解锁 --查询SELECT object_name, machine, s.sid, s.serial# FROM gv$locked_object l, dba_objects o, gv ...

  3. C#高级编程:泛型优点和特性

    泛型是CLR 2.0的一个新特性,在CLR 1.0中,要创建一个灵活的类或方法,但该类或方法在编译期间不知道使用什么类,就得以Object类为基础.而Object在编译期间没有类型安全性,因此必须进行 ...

  4. 【Java学习笔记之二十八】深入了解Java8新特性

    前言: Java8 已经发布很久了,很多报道表明java8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java 8 ...

  5. 【JSP 标签】格式化日期

    在使用JSP开发页面时,java.util.Date在JSP页面直接输出的格式不好看,需要进行格式化. <%@ page language="java" contentTyp ...

  6. Cell

    首先需要创建一个model类,继承于NSObject: 定义两个属性: @property(nonatomic,retain)NSString imageName; @property(nonatom ...

  7. go web 第二天 学习笔记之文件上传

    package main import ( "crypto/md5" "fmt" "html/template" "io" ...

  8. Andrew Ng机器学习课程笔记--week6(精度&召回率)

    Advice for applying machine learning 本周主要学习如何提升算法效率,以及如何判断学习算法在什么时候表现的很糟糕和如何debug我们的学习算法.为了让学习算法表现更好 ...

  9. java中 this 的三种用法

    Java中this的三种用法 调用属性 (1)this可以调用本类中的任何成员变量 调用方法(可省略) (2)this调用本类中的成员方法(在main方法里面没有办法通过this调用) 调用构造方法 ...

  10. Java线程池之ThreadPoolExecutor

    前言 线程池可以提高程序的并发性能(当然是合适的情况下),因为对于没有线程的情况下,我们每一次提交任务都新建一个线程,这种方法存在不少缺陷: 1.  线程的创建和销毁的开销非常高,线程的创建需要时间, ...