Struts2中防止表单重复提交的两种方式
2018-01-09 21:34
465 查看
前言
防止表单重复提交,这是个很重要的知识点,而且经常会用到。当用户提交了一个表单,此时,地址栏显示的是处理这个表单的Action的地址,若此时刷新,则会重新发送一次表单数据,即又进行了一次提交,若这个Action是用来处理用户注册的,那么重复提交会再一次向数据库中插入之前已经插入的数据,这显然不是我们想要的。有两种方法,可以防止表单重复提交,一种是用Action的重定向,一种是用Session Token(Session令牌)。第一种方法,Action处理完用户提交的数据后,重定向到另一个Action或是一个页面,地址栏会发生变化,使用户提交后,所停留的位置,不是当前处理数据的Action,这样用户再刷新时,就不会再次执行这个Action了,就会避免表单重复提交的问题了。
第二种方法,是一种很经典的处理这个问题的机制。这种方法是在用户要提交的表单中,加入一个
<s:token>标签,这样,当浏览器第一次访问这个带有
<s:token>标签的页面时,在服务器中,解析
<s:token>标签的类,会生成一个随机的字符串(这个字符串,查看网页的源代码可以看到),并且发送给客户端的浏览器,同时,在服务器中,会把这个随机字符串保存到用户的session对象中。当第一次提交表单时,在服务器中,会比较客户端和服务器中分别保存的这个随机字符串,因为是第一次提交,所以这两个字符串相等,然后进行正常的业务处理。第一次提交后,在服务器中的session中保存的这个随机字符串,会改变为其他的随机值,注意,这是很重要的一步!此时,地址栏停留在处理用户提交数据的Action中,客户端中保存的随机字符串没有改变,若是刷新页面,即重复提交,服务器再进行两个字符串的比较,会不相等,就会跳转到name为invalid.token的结果页面中,这样就会防止表单重复提交了。
我们根据具体的案例来实现上面两个不同防止表单提交的方法。
案例
本案例主要的设计如下图所示:需求描述:三个功能:register.jsp -注册页面,用户注册保存到数据库中。保存成功跳转到用户信息列表list.jsp.然后在list.jsp页面可以进行修改操作。其中会在register.jsp表单中添加token标签,让其生成随机值,浏览器跟服务器各一份。
数据库表结构
CREATE TABLE employee ( id INT PRIMARY KEY AUTO_INCREMENT, empName VARCHAR(20), workDate DATE -- 入职时间 )
代码如下
EmployeeAction.javapublic class EmployeeAction extends ActionSupport implements ModelDriven<Employee> { private Employee employee = new Employee(); private EmployeeService service = new EmployeeService(); public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } @Override public Employee getModel() { return employee; } //注册 public String register(){ try { service.save(employee); return list(); } catch (Exception e) { e.printStackTrace(); return INPUT ; } } /** * 列表显示 */ public String list(){ try { List<Employee> employeeList =service.getAll(); for (Employee employee : employeeList) { System.out.println(employee.getWorkDate()); } //保存到域对象 ActionContext.getContext().getContextMap().put("employeeList", employeeList); return "list"; } catch (Exception e) { e.printStackTrace(); } return ERROR; } /** * 跳转到修改视图 */ public String viewUpdate(){ try { Employee emp = service.findById(employee.getId()); //保存到值栈中 ValueStack stack = ActionContext.getContext().getValueStack(); Employee pop = (Employee)stack.pop(); stack.push(emp); return "ViewUpdate"; } catch (Exception e) { e.printStackTrace(); } return ERROR; } /** * 修改 */ public String update(){ try { service.update(employee); return list(); } catch (Exception e) { e.printStackTrace(); } return ERROR; } }
Register.jsp
<form action="${pageContext.request.contextPath }/employee_register.action" method="post"> <s:token></s:token> 员工名:<input type="text" name="empName"> <s:fielderror fieldName="employee.empName"></s:fielderror><br/> 入职时间:<input type="text" name="workDate"> <s:fielderror fieldName="employee.workDate"></s:fielderror><br/> <input type="submit" value="注册"> </form>
List.jsp
<table align="center" border="1px" cellpadding="0px" cellspacing="0px"> <tr> <th>序号</th><th>编号</th><th>员工名</th><th>入职时间</th><th>操作</th> </tr> <s:if test="%{#request.employeeList!=null}"> <s:iterator var="emp" value="%{#request.employeeList}" status="vs"> <tr> <td><s:property value="#vs.count"/></td> <td><s:property value="#emp.id"/></td> <td><s:property value="#emp.empName"/></td> <td><s:date name="%{#emp.workDate}"/></td> <td><s:a href="employee_viewUpdate?id=%{#emp.id}">修改</s:a></td> </tr> </s:iterator> </s:if> <s:else> <tr> <td colspan="5">没有员工信息,请先注册!</td> </tr> </s:else> </table>
Update.jsp
<s:form action="/employee_update"> <s:hidden name="id" ></s:hidden> <s:textfield name="empName"/><br/> <s:date name="workDate"/> <s:submit value="修改"></s:submit> </s:form>
Struts.jsp
<struts> <!-- 修改主题 (当前项目所有的标签都用此主题)--> <constant name="struts.ui.theme" value="simple"></constant> <package name="employee" extends="struts-default"> <global-results> <result name="error">/error.jsp</result> </global-results> <action name="employee_*" class="edu.action.EmployeeAction" method="{1}"> <!-- 防止表单重复提交,第二步: 配置" 防止表单重复提交拦截器" --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="token"> <!-- 指定拦截哪些方法需要防止表单重复提交(register) --> <param name="includeMethods">register</param> </interceptor-ref> <!-- 防止表单重复提交,第三步: 如果用户重复提交了跳转到指定的错误页面 --> <result name="invalid.token" type="redirectAction">employee_list</result> <!-- 如果不用重定向默认是转发 地址不会变type="redirectAction" --> <result name="input">/register.jsp</result> <result name="ViewUpdate">/WEB-INF/ViewUpdate.jsp</result> <result name="list">/WEB-INF/list.jsp</result> </action> </package> </struts>
可以看到在访问register页面时的源代码如下:
<form action="/d909_Demo/employee_register.action" method="post"> <input type="hidden" name="struts.token.name" value="token" /> <input type="hidden" name="token" value="6FY7JZ0ME5YTZ809L2LR7EKWPHPXM77G" /> 员工名:<input type="text" name="empName"> <br/> 入职时间:<input type="text" name="workDate"> <br/> <input type="submit" value="注册"> </form>
服务器自动生成随机值,用于第二次访问时的比较。这样就可以防止表单重复提交了。
其他像service层、dao层代码这里就不再赘述了。
第二种防止表单重复提交的方式:
只需要把Action中register页面返回值在result中配置成重定向即可。修改代码如下:
Action中的register方法
public String register(){ try { service.save(employee); return "addSuccess"; } catch (Exception e) { e.printStackTrace(); return INPUT ; } }
struts.xml增加结果视图如下:
<result name="addSuccess" type="redirectAction">employee_list</result>
这样每次注册完之后,地址栏发生变化,避免了表单重复提交。
地址栏显示:http://localhost:8080/d909_Demo/employee_list.action
相关文章推荐
- Struts2中防止表单重复提交的两种方式及token拦截器的原理及作用
- Session Token机制-Struts2中防止表单重复提交的两种方式(一)
- Struts2中防止表单重复提交的两种方式
- Action的重定向-Struts2中防止表单重复提交的两种方式(二)
- Struts2中防止表单重复提交的两种方式
- Struts2中防止表单重复提交的两种方式
- 防止表单重复提交的两种方式
- 防止表单重复提交的两种方式
- 防止表单重复提交的两种方式
- 表单防止重复提交处理的前后台两种处理方式
- 防止表单重复提交的两种方式
- 防止表单重复提交的两种方式
- 防止表单重复提交的两种方式
- Spring MVC拦截器+注解方式实现防止表单重复提交
- Spring MVC拦截器+注解方式实现防止表单重复提交
- Struts2 TokenInterceptor防止表单重复提交
- 不用struts2的token机制,手动防止表单数据重复提交
- 防止表单重复提交(拦截器)一些struts2标签的使用
- Struts2防止表单重复提交
- Struts2防止表单重复提交 .