首先是web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <servlet>
- <servlet-name>FormServlet</servlet-name>
- <servlet-class>com.jadyer.servlet.FormServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>FormServlet</servlet-name>
- <url-pattern>/servlet/FormServlet</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>form.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>FormServlet</servlet-name>
<servlet-class>com.jadyer.servlet.FormServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FormServlet</servlet-name>
<url-pattern>/servlet/FormServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>form.jsp</welcome-file>
</welcome-file-list>
</web-app>
然后是表单页面form.jsp
- <%@ page language="java" pageEncoding="UTF-8"%>
- <%@ page import="com.jadyer.util.DataCoderUtil"%>
- <%
- //生成表单令牌
- session.setAttribute("myToken", DataCoderUtil.generateToken());
- //request包含页面:也可以使用这种方式,把页面包含进来
- //request.getRequestDispatcher("/form.jsp").include(request, response);
- %>
- <form action="<%=request.getContextPath()%>/servlet/FormServlet" method="POST">
- <input type="hidden" name="myToken" value="${myToken}">
- 用户:<input type="text" name="username"><br/>
- 密码:<input type="password" name="password"><br/>
- <input type="submit" value="提交">
- </form>
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page import="com.jadyer.util.DataCoderUtil"%>
<%
//生成表单令牌
session.setAttribute("myToken", DataCoderUtil.generateToken());
//request包含页面:也可以使用这种方式,把页面包含进来
//request.getRequestDispatcher("/form.jsp").include(request, response);
%>
<form action="<%=request.getContextPath()%>/servlet/FormServlet" method="POST">
<input type="hidden" name="myToken" value="${myToken}">
用户:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="提交">
</form>
下面是用于生成表单令牌的工具类DataCoderUtil.java
- package com.jadyer.util;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.Random;
- import sun.misc.BASE64Encoder;
- /**
- * DataCoderUtil
- * @see ========================================================================================
- * @see 这里的generateToken()是处理表单重复提交时,创建的表单令牌生成器,其返回经MD5和base64加密后的String
- * @see ========================================================================================
- * @see Java中每个数据都有一个摘要,即数据指纹。无论这个数据有多大,它的指纹都是固定的128位,即16个字节
- * @see 我们可以使用Java中提供的java.security.MessageDigest工具类,得到随机数的数据摘要,即数据指纹
- * @see ========================================================================================
- * @see 全新算法:base64编码
- * @see 任何数据经base64算法编码后,都会返回明文的字符串。该算法有一个特点:它会把每三个字节,都变成四个字节
- * @see 比如00110010.11001101.00101001会被变成00001100.00101100.00110100.00101001
- * @see 也就是把原来的24Bit平均分为四份,然后在每一份前面补两个零,以此凑成32Bit,即四个字节
- * @see 故,改变之后的四个字节,每个字节的最小值就是00000000,最大值就是00111111,即最小为零,最大为63
- * @see 所以,经过base64算法编码后,每个字节的最大值都不会超过64
- * @see 最后,base64算法会查询它自己定制的码表,该码表记录的是0--63所对应键盘上的明文字符,最后将其返回
- * @see ========================================================================================
- * @author 宏宇
- * @create Mar 6, 2012 2:38:04 AM
- */
- public class DataCoderUtil {
- public static String generateToken() {
- String myToken = System.currentTimeMillis() + new Random().nextInt() + "";
- try {
- byte[] myTokenMD5 = MessageDigest.getInstance("md5").digest(myToken.getBytes()); //MD5算法加密
- return new BASE64Encoder().encode(myTokenMD5); //base64算法加密,最后返回
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
- }
package com.jadyer.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Encoder;
/**
* DataCoderUtil
* @see ========================================================================================
* @see 这里的generateToken()是处理表单重复提交时,创建的表单令牌生成器,其返回经MD5和base64加密后的String
* @see ========================================================================================
* @see Java中每个数据都有一个摘要,即数据指纹。无论这个数据有多大,它的指纹都是固定的128位,即16个字节
* @see 我们可以使用Java中提供的java.security.MessageDigest工具类,得到随机数的数据摘要,即数据指纹
* @see ========================================================================================
* @see 全新算法:base64编码
* @see 任何数据经base64算法编码后,都会返回明文的字符串。该算法有一个特点:它会把每三个字节,都变成四个字节
* @see 比如00110010.11001101.00101001会被变成00001100.00101100.00110100.00101001
* @see 也就是把原来的24Bit平均分为四份,然后在每一份前面补两个零,以此凑成32Bit,即四个字节
* @see 故,改变之后的四个字节,每个字节的最小值就是00000000,最大值就是00111111,即最小为零,最大为63
* @see 所以,经过base64算法编码后,每个字节的最大值都不会超过64
* @see 最后,base64算法会查询它自己定制的码表,该码表记录的是0--63所对应键盘上的明文字符,最后将其返回
* @see ========================================================================================
* @author 宏宇
* @create Mar 6, 2012 2:38:04 AM
*/
public class DataCoderUtil {
public static String generateToken() {
String myToken = System.currentTimeMillis() + new Random().nextInt() + "";
try {
byte[] myTokenMD5 = MessageDigest.getInstance("md5").digest(myToken.getBytes()); //MD5算法加密
return new BASE64Encoder().encode(myTokenMD5); //base64算法加密,最后返回
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
最后是用于处理表单请求的FormServlet.java
- package com.jadyer.servlet;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class FormServlet extends HttpServlet {
- private static final long serialVersionUID = -3435386674549645942L;
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- /**
- * 利用referer防盗链
- * @see 客户端访问时,只认可以http://127.0.0.1为首的URL
- */
- String referer = request.getHeader("referer");
- if(null==referer || !referer.startsWith("http://127.0.0.1")){
- response.sendRedirect("/index.jsp");
- return; //如果没有这行代码,那么重定向之后,下面的代码仍会执行
- }
- /**
- * 判断表单重复提交
- * @see 思路:详见我的另一篇文章http://blog.csdn.net/jadyer/article/details/6174095
- */
- if(!isTokenValid(request, response)){
- System.out.println("请不要重复提交表单...");
- return;
- }
- request.getSession().removeAttribute("myToken");
- System.out.println("向数据库中注册用户...");
- }
- /**
- * 判断表单令牌是否有效
- */
- private boolean isTokenValid(HttpServletRequest request, HttpServletResponse response){
- String client_token = request.getParameter("myToken");
- String server_token = (String)request.getSession().getAttribute("myToken");
- if(null == client_token){
- return false;
- }
- if(null == server_token){
- return false;
- }
- if(!client_token.equals(server_token)){
- return false;
- }
- return true;
- }
- }