1. 程式人生 > >解決表單重複提交問題(使用單例模式)、(md5+base64)

解決表單重複提交問題(使用單例模式)、(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(); 
    } 
  }