英文,數字和中文混合的彩色驗證碼實現
來源:程序員人生 發布時間:2016-07-09 13:12:30 閱讀次數:2433次
功能描寫:英文,數字和中文混合的彩色驗證碼是1種比較安全的驗證碼,雖然這樣的驗證碼會給用戶輸入帶來不便,但對保障用戶賬號的安全還是值得的。本實例介紹實現英文,數字和中文混合驗證碼的彩色驗證碼的方法,輸入用戶名和密碼后,還需要輸入正確的驗證碼才可以正常登陸。由于驗證碼是隨機生成的,可能會產生看不清楚的驗證碼,因此添加了重新生成驗證碼的功能,用戶單擊“看不清?換1個”超級鏈接和圖片本身,可以重新生成1個驗證碼。
1:編寫生成英文,數字和中文混合的彩色驗證碼的Servlet實現類
要生成英文,數字和中文混合的彩色驗證碼,首先需要編寫1個Servlet,這里的名稱為PictureCheckCode.java,該類繼承HttpServlet,只要通過service()方法生成驗證碼,其具體實現進程以下:
(1)創建名稱為PictureCheckCode.java的servlet,并將其保存到com包中,關鍵代碼以下:
package com;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class PictureCheckCode extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
public PictureCheckCode() {
super();
// TODO Auto-generated constructor stub
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//設置不緩存圖片
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 0);
//指定生成的響應圖片
response.setContentType("image/jpeg");
int width=86; //指定生成驗證碼的寬度
int height=22; //指定生成驗證碼的高度
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
Graphics2D g2d = (Graphics2D)g; //創建Graphics2D對象
Random random = new Random();
Font mFont = new Font("黑體", Font.BOLD, 16); //定義字體樣式
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height); //繪制背景
g.setFont(mFont); //設置字體
g.setColor(getRandColor(180, 200));
//繪制100根位置和色彩全部為隨機產生的線條,該線條為2f
for (int i = 0; i < 100; i++) {
int x = random.nextInt(width⑴);
int y = random.nextInt(height⑴);
int x1 = random.nextInt(6)+1;
int y1 = random.nextInt(12)+1;
BasicStroke bs = new BasicStroke(2f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL);
Line2D line = new Line2D.Double(x,y,x+x1,y+y1);
g2d.setStroke(bs);
g2d.draw(line); //繪制直線
}
//輸出由英文,數字和中文隨機組成的驗證文字,具體的組合方式根據生成隨機數肯定
String sRand = "";
//輸出隨機的驗證文字
String ctmp = "";
int itmp = 0;
for(int i = 0;i<4;i++){
//random = new Random(new java.util.Date().getTime()+i);
switch (random.nextInt(4)) {
case 1:
itmp = random.nextInt(26)+65; //生成A~Z的字母
ctmp = String.valueOf((char)itmp);
break;
case 2://生成漢字
String[] rBase = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
//生成第1位的區碼
int r1 = random.nextInt(3)+11; //生成11~14之間的隨機數
String str_r1 = rBase[r1];
//生成第2位的區碼
int r2;
if(r1==13){
r2 = random.nextInt(7); //生成0~7之間的隨數
}else{
r2 = random.nextInt(16); //生成0~16之間的隨機數
}
String str_r2 = rBase[r2];
//生成第1位的位碼
int r3 = random.nextInt(6)+10; //生成10~16之間的隨機數
String str_r3 = rBase[r3];
//生成第2位的位碼
int r4;
if(r3==10){
r4 = random.nextInt(15)+1; //生成1~16之間的隨機數
}else if(r3==15){
r4 = random.nextInt(15); //生成0~15之間的隨機數
}else {
r4 = random.nextInt(16); //生成0~16之間的隨機數
}
String str_r4 = rBase[r4];
//將生成的機內碼轉換為漢字
byte[] bytes = new byte[2];
//將生成的區碼保存到字節數組的第1個元素中
String str_r12 = str_r1+str_r2;
int tempLow=Integer.parseInt(str_r12,16);
bytes[0] = (byte)tempLow;
//將生成的位碼保存到字節數組的第2個元素中
String str_r34 = str_r3+str_r4;
int tempHigh = Integer.parseInt(str_r34,16);
bytes[1] = (byte)tempHigh;
ctmp = new String(bytes); //根據字節數組生成漢字
break;
default:
itmp = random.nextInt(10)+48; //生成0~9的數字
ctmp = String.valueOf((char)itmp);
break;
}
sRand+=ctmp;
Color color = new Color(20+random.nextInt(110), 20+random.nextInt(110), 20+random.nextInt(110));
g.setColor(color);
//將生成的隨機數進行隨機縮放病旋轉指定角度
//將文字旋轉指定角度
Graphics2D g2d_word = (Graphics2D)g;
AffineTransform trans = new AffineTransform();
trans.rotate(random.nextInt(45)*3.14/180,15*i+8,7);
//縮放文字
float scaleSize = random.nextFloat()+0.8f;
if(scaleSize>1f){
scaleSize = 1f;
}
trans.scale(scaleSize, scaleSize);
g2d_word.setTransform(trans);
g.drawString(ctmp, 15*i+18, 14);
}
//將生成的驗證碼保存道session中
HttpSession session = request.getSession(true);
session.setAttribute("randCheckCode", sRand);
//輸誕生成的驗證碼圖片
g.dispose();
ImageIO.write(image, "JPEG", response.getOutputStream());
}
@Override
public void destroy() {
// TODO Auto-generated method stub
super.destroy();
}
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
super.init();
}
public Color getRandColor(int s,int e){
Random random = new Random();
if(s>255)s = 255;
if(e>255)e = 255;
int r = s+random.nextInt(e-s);
int g = s+random.nextInt(e-s);
int b = s+random.nextInt(e-s);
return new Color(r, g, b);
}
}
2:配置Servlet
用于生成驗證碼的Servlet編寫完成后,還需要web.xml文件中配置該Servlet,具體配置代碼以下:web.xml
<?xml version="1.0" encoding="UTF⑻"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>CheckCode</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>PictureCheckCode</servlet-name>
<servlet-class>com.PictureCheckCode</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PictureCheckCode</servlet-name>
<url-pattern>/PictureCheckCode</url-pattern>
</servlet-mapping>
</web-app>
3:在Jsp頁面中插入生成的驗證碼
在Jsp頁面中茶如生成的驗證碼時,首先需要在頁面中添加1個用于輸入驗證碼的文本框,然后插入生成的驗證碼,具體代碼以下:index.jsp
4:加入重新生成驗證碼的功能
由于驗證碼是隨機生成的,極可能會產生看不清楚的驗證碼,因此還需要加入重新生成驗證碼的功能。實現重新生成驗證碼時,首先需要編寫1個自定義的JavaScript函數,在該函數中實現重新生成驗證碼的功能,具體代碼以下
<%@ page language="java" contentType="text/html; charset=utf⑻"
pageEncoding="utf⑻"%>
<!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⑻">
<title>Insert title here</title>
<script type="text/javascript">
function myReload() {
document.getElementById("createCheckCode").src=document.getElementById("createCheckCode").src+"?nocache"+new Date().getTime();
}
</script>
</head>
<body style="text-align: center;">
驗證碼:<input name="checkCode" type="text" id="checkCode" title="驗證碼辨別大小寫" size="8" maxlength="4">
<img src="PictureCheckCode" id="createCheckCode" onclick="myReload()">
<a href="#" onclick="myReload()"> 看不清?換1個</a>
</body>
</html>
5:獲得驗證碼并驗證吧輸入是不是正確
獲得驗證碼病驗證輸入是不是正確,通常是在處理頁完成的功能,本實例中,將頁面提交到deal.jsp頁面,在該頁面中通過request對象獲得用戶輸入的驗證碼,再將該驗證碼與保存到Session中的驗證碼進行比較,便可判斷輸入的驗證碼是不是正確。關鍵代碼以下:
<%@ page language="java" contentType="text/html; charset=utf⑻"
pageEncoding="utf⑻"%>
<!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⑻">
<title>Insert title here</title>
<%
String checkCode = request.getParameter("checkCode");
if("".equals(checkCode)||checkCode==null){
out.println("<script>alert('請輸入驗證碼!');window.location.href='index.jsp';</script>");
}else{
if(!checkCode.equals(session.getAttribute("randCheckCode"))){
out.println("<script>alert('您輸入的驗證碼不正確!');history.back(⑴);</script>");
}
}
%>
</head>
<body>
</body>
</html>
6:調試
在生成驗證碼時,由于對生成的圖片進行了隨機旋轉和縮放,結果常常產生看不清楚的驗證碼,而且概率比較大。
經過仔細比較發現,通過random.nextFloat()方法生成隨機數的范圍在0~1之間。當利用該值作為縮放尺寸時,如果生成的是小于0。8的數,驗證碼文字將被縮放的很小,以致于看不清。斟酌到這類情況,因而將生成的隨機數加上0.8,這時候,雖然文字不會被縮放的很小,但是文字會被放大到超越驗證碼的邊框,所以還需要對縮放尺寸的最大值進行控制,經過量次測試,總結出最大值不能超過1,因此得出驗證碼對圖片進行縮放的代碼以下:
float scaleSize = random.nextFloat()+0.8f;
if(scaleSize>1f)scaleSize = 1f;
trans.scale(scaleSize, scaleSize);
至此,英文,數字和中文混合的彩色驗證碼得以實現。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈