form表单重复提交
1.新建TokenProccessor工具类
package cn.kgc.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import sun.misc.BASE64Encoder;
public class TokenProccessor {
/**
* 单例设计模式[饿汉模式](保证类的对象在内存中只有一个)
* 1、把类的构造函数私有
* 2、自己创建一个类的对象
* 3、对外提供一个公共的方法,返回类的对象
*/
/**
* 构造器私有化
*/
private TokenProccessor() {
}
/**
* 自己创建一个类的对象
*/
private static final TokenProccessor instance = new TokenProccessor();
/**
* 返回类的对象
* @return
*/
public static TokenProccessor getInstance(){
return instance;
}
/**
* 生成Token
* @return
*
*/
public String makeToken(){
//String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
String token = System.currentTimeMillis()+UUID.randomUUID().toString();
try {
//获取md5算法
//MD5:消息摘要算法,其实就是一种算法,把任意长度的字符串转换成十六进制的一定长度的数字串
MessageDigest md = MessageDigest.getInstance("MD5");
//生成MD5摘要
byte[] md5 = md.digest(token.getBytes());
//BASE64Encoder encoder = new BASE64Encoder();//加密 BASE64Decoder decoder = new BASE64Decoder();// 解密
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
2.在进入form表单之前,向session作用域中放入token
package cn.kgc.servlet.client;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.kgc.entity.Goods;
import cn.kgc.service.GoodsService;
import cn.kgc.service.impl.GoodsServiceImpl;
import cn.kgc.utils.TokenProccessor;
@WebServlet("/searchIdServlet")
public class searchIdServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
GoodsService gs = new GoodsServiceImpl();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type","text/html; charset=UTF-8");
Integer id = Integer.valueOf(request.getParameter("id"));
Goods goods = new Goods(id, null, 0, 0, 0, 0, null);
Goods goodsBean = gs.searchGoodsId(goods);
request.setAttribute("goods", goodsBean);
//创建token令牌
String token = TokenProccessor.getInstance().makeToken();
//在服务器用session保存token令牌
request.getSession().setAttribute("token", token);
//跳转到form表单页面
request.getRequestDispatcher("/update.jsp").forward(request, response);
}
}
3.在form表单中使用hidden框保存session中token
<%@page import="cn.kgc.entity.Goods"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="updateServlet" method="post">
<table border="1" cellpadding="1" cellspacing="1">
<tr>
<td>商品编号</td>
<td>
<!-- 在form表单中使用hidden框保存token -->
<input type="hidden" name="token" value="${sessionScope.token}"/>
<input type="text" name="id" value="${goods.id}" readonly="readonly">
</td>
</tr>
<tr>
<td>商品名称</td>
<td><input type="text" name="goodsName" value="${goods.goodsName}"></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="goodsPrice" value="${goods.goodsPrice}"></td>
</tr>
<tr>
<td>库存数量</td>
<td><input type="text" name="goodsCount" value="${goods.goodsCount}"></td>
</tr>
<tr>
<td>订单状态</td>
<td>
<select id="billStatus" name="billStatus">
<option value="1">待处理</option>
<option value="2">处理中</option>
<option value="3">已处理</option>
</select>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"><input type="button" value="返回" onclick="window.history.go(-2)"></td>
</tr>
</table>
${succues}
</form>
<script type="text/javascript" src="jquery-1.7.2.js"></script>
<script type="text/javascript">
/* 处理select下拉框的选中状态 */
$(function(){
var optionvalue=${goods.billStatus};
$("#billStatus option").eq(optionvalue-1).attr("selected","selected");
})
</script>
</body>
</html>
4.新建servlet验证表单提交
满足重复提交的条件:
- 如果用户提交的form表单中没有token,则用户重复提交了表单
- 如果当前用户的session中不存在token(令牌),则用户重复提交了表单
- 储存在session中的token(令牌)和用户提交的token(令牌)不一致,则用户重复提交了表单
package cn.kgc.servlet.client;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import cn.kgc.entity.Goods;
import cn.kgc.service.GoodsService;
import cn.kgc.service.impl.GoodsServiceImpl;
@WebServlet("/updateServlet")
public class updateServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
GoodsService gs = new GoodsServiceImpl();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type","text/html; charset=UTF-8");
//首先判断用户是否重复提交表单
boolean repeatSubmit = isRepeatSubmit(request);
if(repeatSubmit){
System.out.println("请不要重复提交");
return;
}
//移除session中的token(令牌)
request.getSession().removeAttribute("token");
//处理用户的提交请求
Integer id = Integer.valueOf(request.getParameter("id"));
String GoodsName=request.getParameter("goodsName");
double GoodsPrice = Double.parseDouble(request.getParameter("goodsPrice"));
int BillStatus = Integer.parseInt(request.getParameter("billStatus"));
int goodsCount = Integer.parseInt(request.getParameter("goodsCount"));
Goods goods = new Goods(id, GoodsName, GoodsPrice, 0, BillStatus, goodsCount, null);
boolean b = gs.updateGoods(goods);
request.setAttribute("goods",goods);
if(b){
request.setAttribute("succues","修改成功");
request.getRequestDispatcher("/update.jsp").forward(request, response);
}
}
/**
* 判断用户提交的令牌(token)和服务器端生成的令牌(token)是否一致
* @param request
* @return true:表示用户重复提交了表单
* false:表示用户没有重复提交表单
*/
@SuppressWarnings("unused")
private boolean isRepeatSubmit(HttpServletRequest request){
String client_token = request.getParameter("token");
//1.如果用户提交的form表单中没有token,则用户重复提交了表单
if(client_token==null){
return true;
}
//取出session中的token(令牌)
String server_token = (String)request.getSession().getAttribute("token");
//2.如果当前用户的session中不存在token(令牌),则用户重复提交了表单
if(server_token==null){
return true;
}
//3.储存在session中的token(令牌)和用户提交的token(令牌)不一致,则用户重复提交了表单
if(!client_token.equals(server_token)){
return true;
}
return false;
}
}
补充:Base64
若eclipse中不能使用base64如下步骤解决:
右键项目–>Build Path -->Configure Build Path–>选择Libraries
–>点击JRE System Library–>选择 Access rules–>点击Edit -->Add
–>在Resolution下拉列表框中选择Accessible–>Rule Pattern 输入**,依次点击ok。
public static void main(String[] args) {
try {
String name="我爱你";
String pwd="你却不知道。";
BASE64Encoder en=new BASE64Encoder(); //加密
name=en.encode(name.getBytes("utf-8"));//5oiR54ix5L2g
pwd=en.encode(pwd.getBytes("utf-8"));//5L2g5Y205LiN55+l6YGT44CC
System.out.println(name+","+pwd);
BASE64Decoder den=new BASE64Decoder(); //解密
name=new String(den.decodeBuffer(name),"utf-8");
pwd=new String(den.decodeBuffer(pwd),"utf-8");
System.out.println(name+","+pwd);
} catch (IOException e) {
e.printStackTrace();
}
}