解决表单重复提交问题(使用单例模式)、(md5+base64)

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验证表单提交

满足重复提交的条件:

  1. 如果用户提交的form表单中没有token,则用户重复提交了表单
  2. 如果当前用户的session中不存在token(令牌),则用户重复提交了表单
  3. 储存在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(); 
    } 
  }

猜你喜欢

转载自blog.csdn.net/qq_26869339/article/details/82758731