1.JSP页面
1 <%@page import="cn.gs.ly.app2.MD5Util"%> 2 <%@page import="java.util.UUID"%> 3 <%@page import="java.util.Random"%> 4 <%@ page language="java" contentType="text/html" pageEncoding="utf-8"%> 5 <!DOCTYPE html> 6 <html> 7 <head> 8 <title>MD5加密</title> 9 <script type="text/javascript"> 10 function toSubmit() { 11 document.getElementById("f1").submit(); 12 document.getElementById("t1").disabled=true; //点击后不可被选中,防止网络延迟时多次点击 13 } 14 </script> 15 </head> 16 <body> 17 <% 18 //String token = UUID.randomUUID().toString(); //UUID随机生成唯一的随机号 19 String token = ""+System.currentTimeMillis()+new Random().nextLong()+""; 20 token = MD5Util.md5(token); 21 session.setAttribute("token", token); //设置 属性 值为token。 22 //后台获取token属性值与隐藏域参数作比较,相同即为同一网页 23 %> 24 <form action="RegisterServlet" method="post" id="f1"> 25 姓名:<input type="text" name="name"> 26 <input type="hidden" name="token" value="<%=token%>"> <!-- 隐藏域存放token值 --> 27 <input type="button" value="注册" onclick="toSubmit()" id="t1"> 28 </form> 29 </body> 30 </html>
2.JAVA。验证同意网页防止重复提交
1 package cn.gs.ly.app2; 2 import java.io.IOException; 3 import java.io.PrintWriter; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class RegisterServlet extends HttpServlet{ 11 @Override 12 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 13 req.setCharacterEncoding("UTF-8"); 14 resp.setCharacterEncoding("UTF-8"); 15 resp.setContentType("text/html;charset=utf-8"); 16 17 String name = req.getParameter("name"); 18 String ftoken = req.getParameter("token"); 19 String stoken = (String)req.getSession().getAttribute("token"); 20 21 PrintWriter out = resp.getWriter(); 22 try { 23 Thread.sleep(4000); //模拟网络延迟 24 } catch (InterruptedException e) { 25 e.printStackTrace(); 26 } 27 if(ftoken.equals(stoken)){ //已知比未知 28 System.out.println(name+" save success"+ftoken); 29 out.println("<h1>"+name+" save success</h1>"); 30 req.getSession().removeAttribute("token"); 31 }else{ 32 System.out.println("重复提交"); 33 out.println("<h1>请不要重复提交</h1>"); 34 } 35 } 36 @Override 37 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 38 this.doPost(req, resp); 39 } 40 }
3.MD5加密。
1 package cn.gs.ly.app2; 2 import java.security.MessageDigest; 3 import java.security.NoSuchAlgorithmException; 4 5 import sun.misc.BASE64Encoder; 6 public class MD5Util { 7 /** 8 * @param message 要加密的字符串 9 * @param getInstance() 生成实现指定摘要算法(md5)的 MessageDigest 对象。 10 * @param digest(message.getBytes()) 使用指定的字节数组对摘要进行最后更新,然后完成摘要计算 11 * @param base64.encode(b) 加密后信息用Base64编码 转为base64的 12 * @param msg 得到的最终的加密信息 13 * */ 14 public static String md5(String message){ 15 String msg = ""; 16 try { 17 MessageDigest md = MessageDigest.getInstance("md5"); //生成实现指定摘要算法(md5)的 MessageDigest 对象。 18 System.out.println("加密前:"+new String(message.getBytes()));//加密前信息 19 byte [] b = md.digest(message.getBytes()); // 使用指定的字节数组对摘要进行最后更新,然后完成摘要计算 20 System.out.println("加密后:"+new String(b)); //加密后信息 21 BASE64Encoder base64 = new BASE64Encoder(); 22 msg = base64.encode(b); //把字节数组转化成字符串 23 System.out.println("base64处理后:"+msg);//最终加密信息.MD5加密有的显示为乱码经base64再加密后得到可读性强的形式 24 } catch (NoSuchAlgorithmException e) { 25 e.printStackTrace(); 26 } 27 return msg; 28 } 29 }
构造方法摘要 | |
---|---|
protected |
MessageDigest(String algorithm) 创建具有指定算法名称的MessageDigest 实例对象。 |
方法摘要 | |
---|---|
Object |
clone() 如果实现是可复制的,则返回一个副本。 |
byte[] |
digest() 通过执行诸如填充之类的最终操作完成哈希计算。 |
byte[] |
digest(byte[] input) 使用指定的字节数组对摘要进行最后更新,然后完成摘要计算。 |
int |
digest(byte[] buf, int offset, int len) 通过执行诸如填充之类的最终操作完成哈希计算。 |
String |
getAlgorithm() 返回标识算法的独立于实现细节的字符串。 |
int |
getDigestLength() 返回以字节为单位的摘要长度,如果提供程序不支持此操作并且实现是不可复制的,则返回 0。 |
static MessageDigest |
getInstance(String algorithm) 生成实现指定摘要算法的 MessageDigest 对象。 |
static MessageDigest |
getInstance(String algorithm, Provider provider) 生成实现指定提供程序提供的指定算法的 MessageDigest 对象,如果该算法可从指定的提供程序得到的话。 |
static MessageDigest |
getInstance(String algorithm, String provider) 生成实现指定提供程序提供的指定算法的 MessageDigest 对象,如果该算法可从指定的提供程序得到的话。 |
Provider |
getProvider() 返回此信息摘要对象的提供程序。 |
static boolean |
isEqual(byte[] digesta, byte[] digestb) 比较两个摘要的相等性。 |
void |
reset() 重置摘要以供再次使用。 |
String |
toString() 返回此信息摘要对象的字符串表示形式。 |
void |
update(byte input) 使用指定的字节更新摘要。 |
void |
update(byte[] input) 使用指定的字节数组更新摘要。 |
void |
update(byte[] input, int offset, int len) 使用指定的字节数组,从指定的偏移量开始更新摘要。 |
void |
update(ByteBuffer input) 使用指定的 ByteBuffer 更新摘要。 |
二、实际实践
2.1、创建 MessageDigest 对象
计算信息摘(即散列码)要做的第一步是创建 MessageDigest对象 实例。像所有的引擎类一样,获取某类报文摘要算法(即散列算法,比如MD5)的 MessageDigest 对象的途径是调用 MessageDigest 类中的 getInstance 静态 factory 方法:
public static MessageDigest getInstance(String algorithm)
注意:算法名不区分大小写。例如,以下所有调用都是相等的:
MessageDigest.getInstance("SHA");
MessageDigest.getInstance("sha");
MessageDigest.getInstance("sHa");
调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:
public static MessageDigest getInstance(String algorithm, String provider);
调用 getInstance 将返回已初始化过的MessageDigest对象。因此,它不需要进一步的初始化。
2.2、向MessageDigest传送要计算的数据
计算数据的摘要的第二步是向已初始化的MessageDigest对象提供传送要计算的数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:
public void update(byte input);
public void update(byte[] input);
public void update(byte[] input, int offset, int len);
2.3、计算摘要
通过调用 update 方法向MessageDigest对象提传送要计算的数据后,你就可以调用以下某个 digest(摘要)方法来计算摘要(即生成散列码):
public byte[] digest();
public byte[] digest(byte[] input);
public int digest(byte[] buf, int offset, int len);
前两个方法返回计算出的摘要。后一个方法把计算出的摘要储存在所提供的 buf 缓冲区中,起点是 offset。len 是 buf 中分配给该摘要的字节数。该方法返回实际存储在 buf 中的字节数。
对第二个接受输入字节数组变量的 digest 方法的调用等价于用指定的输入调用:
public void update(byte[] input)
,接着调用不带参数的 digest 方法.
三、例子演示
3.1、★ 编程思路:
java.security包中的MessageDigest类提供了计算消息摘要(即生成散列码)的方法,首先生成对象,执行其update( )方法可
以将原始数据传递给该对象,然后执行其digest( )方法即可得到消息摘要。具体步骤如下:
(1)生成MessageDigest对象
MessageDigest m=MessageDigest.getInstance("MD5");
MessageDigest类也是一个工厂类,其构造器是受保护的,不允许
直接使用new MessageDigist( )来创建对象,而必须通过其静态方法getInstance( )生成MessageDigest对象。
其中传入的参数指定计算消息摘要所使用的算法,常用的有"MD5","SHA"等。
(2)传入需要计算的字符串
m.update(x.getBytes("UTF8" ));
分析:x为需要计算的字符串,update传入的参数是字节类型或字节类型数组,对于字符串,需要先使用getBytes( )方法生成字符串数组。
(3)计算消息摘要
byte s[ ]=m.digest( );
分析:执行MessageDigest对象的digest( )方法完成计算,计算的结果通过字节类型的数组返回。
(4)处理计算结果
必要的话可以使用如下代码将计算结果(byte数组)转换为字符串。
static String convertToHexString(byte data[]) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
strBuffer.append(Integer.toHexString(0xff & data[i]));
}
return strBuffer.toString();
}
3.2、示例一
★完整程序如下:
public class MessageDigestDemo extends Thread {
public void run() {
String text = "abc";
byte data[] = null;
MessageDigest m;
try {
data = text.getBytes("UTF8");
m = MessageDigest.getInstance("MD5");
m.update(data);
byte resultData[] = m.digest();
System.out.println(convertToHexString(resultData));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static String convertToHexString(byte data[]) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
strBuffer.append(Integer.toHexString(0xff & data[i]));
}
return strBuffer.toString();
}
}
★运行结果
900150983cd24fb0d6963f7d28e17f72
3.3、示例二
在这里我们将对计算生成的md5使用 sun.misc.BASE64Encoder进行简单的加密。
public String md5sumWithEncoder(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException{
/*确定计算方法*/
MessageDigest md5=MessageDigest.getInstance("MD5");
BASE64Encoder base64en = new BASE64Encoder();
/*加密后的散列码字符串*/
String strMd5=base64en.encode(md5.digest(text.getBytes("utf-8")));
return strMd5;
}
调用函数
String str="0123456789"
System.out.println(md5sumWithEncoder(str));
输出
eB5eJF1ptWaXm4bijSPyxw==
构造方法摘要 | |
---|---|
protected |
MessageDigest(String algorithm) 创建具有指定算法名称的MessageDigest 实例对象。 |
方法摘要 | |
---|---|
Object |
clone() 如果实现是可复制的,则返回一个副本。 |
byte[] |
digest() 通过执行诸如填充之类的最终操作完成哈希计算。 |
byte[] |
digest(byte[] input) 使用指定的字节数组对摘要进行最后更新,然后完成摘要计算。 |
int |
digest(byte[] buf, int offset, int len) 通过执行诸如填充之类的最终操作完成哈希计算。 |
String |
getAlgorithm() 返回标识算法的独立于实现细节的字符串。 |
int |
getDigestLength() 返回以字节为单位的摘要长度,如果提供程序不支持此操作并且实现是不可复制的,则返回 0。 |
static MessageDigest |
getInstance(String algorithm) 生成实现指定摘要算法的 MessageDigest 对象。 |
static MessageDigest |
getInstance(String algorithm, Provider provider) 生成实现指定提供程序提供的指定算法的 MessageDigest 对象,如果该算法可从指定的提供程序得到的话。 |
static MessageDigest |
getInstance(String algorithm, String provider) 生成实现指定提供程序提供的指定算法的 MessageDigest 对象,如果该算法可从指定的提供程序得到的话。 |
Provider |
getProvider() 返回此信息摘要对象的提供程序。 |
static boolean |
isEqual(byte[] digesta, byte[] digestb) 比较两个摘要的相等性。 |
void |
reset() 重置摘要以供再次使用。 |
String |
toString() 返回此信息摘要对象的字符串表示形式。 |
void |
update(byte input) 使用指定的字节更新摘要。 |
void |
update(byte[] input) 使用指定的字节数组更新摘要。 |
void |
update(byte[] input, int offset, int len) 使用指定的字节数组,从指定的偏移量开始更新摘要。 |
void |
update(ByteBuffer input) 使用指定的 ByteBuffer 更新摘要。 |
二、实际实践
2.1、创建 MessageDigest 对象
计算信息摘(即散列码)要做的第一步是创建 MessageDigest对象 实例。像所有的引擎类一样,获取某类报文摘要算法(即散列算法,比如MD5)的 MessageDigest 对象的途径是调用 MessageDigest 类中的 getInstance 静态 factory 方法:
public static MessageDigest getInstance(String algorithm)
注意:算法名不区分大小写。例如,以下所有调用都是相等的:
MessageDigest.getInstance("SHA");
MessageDigest.getInstance("sha");
MessageDigest.getInstance("sHa");
调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:
public static MessageDigest getInstance(String algorithm, String provider);
调用 getInstance 将返回已初始化过的MessageDigest对象。因此,它不需要进一步的初始化。
2.2、向MessageDigest传送要计算的数据
计算数据的摘要的第二步是向已初始化的MessageDigest对象提供传送要计算的数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:
public void update(byte input);
public void update(byte[] input);
public void update(byte[] input, int offset, int len);
2.3、计算摘要
通过调用 update 方法向MessageDigest对象提传送要计算的数据后,你就可以调用以下某个 digest(摘要)方法来计算摘要(即生成散列码):
public byte[] digest();
public byte[] digest(byte[] input);
public int digest(byte[] buf, int offset, int len);
前两个方法返回计算出的摘要。后一个方法把计算出的摘要储存在所提供的 buf 缓冲区中,起点是 offset。len 是 buf 中分配给该摘要的字节数。该方法返回实际存储在 buf 中的字节数。
对第二个接受输入字节数组变量的 digest 方法的调用等价于用指定的输入调用:
public void update(byte[] input)
,接着调用不带参数的 digest 方法.
三、例子演示
3.1、★ 编程思路:
java.security包中的MessageDigest类提供了计算消息摘要(即生成散列码)的方法,首先生成对象,执行其update( )方法可
以将原始数据传递给该对象,然后执行其digest( )方法即可得到消息摘要。具体步骤如下:
(1)生成MessageDigest对象
MessageDigest m=MessageDigest.getInstance("MD5");
MessageDigest类也是一个工厂类,其构造器是受保护的,不允许
直接使用new MessageDigist( )来创建对象,而必须通过其静态方法getInstance( )生成MessageDigest对象。
其中传入的参数指定计算消息摘要所使用的算法,常用的有"MD5","SHA"等。
(2)传入需要计算的字符串
m.update(x.getBytes("UTF8" ));
分析:x为需要计算的字符串,update传入的参数是字节类型或字节类型数组,对于字符串,需要先使用getBytes( )方法生成字符串数组。
(3)计算消息摘要
byte s[ ]=m.digest( );
分析:执行MessageDigest对象的digest( )方法完成计算,计算的结果通过字节类型的数组返回。
(4)处理计算结果
必要的话可以使用如下代码将计算结果(byte数组)转换为字符串。
static String convertToHexString(byte data[]) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
strBuffer.append(Integer.toHexString(0xff & data[i]));
}
return strBuffer.toString();
}
3.2、示例一
★完整程序如下:
public class MessageDigestDemo extends Thread {
public void run() {
String text = "abc";
byte data[] = null;
MessageDigest m;
try {
data = text.getBytes("UTF8");
m = MessageDigest.getInstance("MD5");
m.update(data);
byte resultData[] = m.digest();
System.out.println(convertToHexString(resultData));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static String convertToHexString(byte data[]) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
strBuffer.append(Integer.toHexString(0xff & data[i]));
}
return strBuffer.toString();
}
}
★运行结果
900150983cd24fb0d6963f7d28e17f72
3.3、示例二
在这里我们将对计算生成的md5使用 sun.misc.BASE64Encoder进行简单的加密。
public String md5sumWithEncoder(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException{
/*确定计算方法*/
MessageDigest md5=MessageDigest.getInstance("MD5");
BASE64Encoder base64en = new BASE64Encoder();
/*加密后的散列码字符串*/
String strMd5=base64en.encode(md5.digest(text.getBytes("utf-8")));
return strMd5;
}
调用函数
String str="0123456789"
System.out.println(md5sumWithEncoder(str));
输出
eB5eJF1ptWaXm4bijSPyxw==