解決表單重複提交問題(使用單例模式)、(md5+base64)
阿新 • • 發佈:2019-01-10
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();
}
}