Java生成中文验证码
1980年,为了使每一个汉字有一个全国统一的编码,我国制定了”中华人民共和国国家标准信息交换汉字编码”,标准代号为GB2312-80,这种编码又称为国标码,国标码字符集中共收录了一级汉字3755个,二级汉字3008个,图形符号682个,3项字符总计7445个.
国标GB2312-80中规定,所有的国标汉字及符号分配在一个94行,94列的方阵中,方阵的每一个行称为一个”区”,编号为01-94曲,每一个列称为一个”位”,编号为01-94位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的4个阿拉伯数字就是他们的”区位码”,区位码的前两位是它的区号,后两位是它的位号,用区位码就可以唯一的确定一个汉字或符号,反之,任何一个汉字或符号也都对应一个唯一的区位码.
所有的汉字和符号所在的区 分为以下4个组.
1). 01-15区,图形符号,其中01-09区分标准符号区,10-15区为自定义符号区
2). 16-55区, 一级常用汉字区,包括3755个一统汉字.这40个区中的汉字是按汉语拼音排序的.同音字按笔划顺序排序.其中55区的90-94位未定义汉字
3). 56-87区, 二级汉字区,包括3008个二级汉字,按部首排序
4). 89-94区,自定义汉字区
其中,第10-15区的自定义符号区和第88-94区的自定义符号区, 可由用户自定义,国标码中未定义的符号和汉字.
与汉字的区位码类似的还有汉字机内码,它是在汉字区位码的区码和位码上分别加上A0H(这里的H表示前两位数字为16进制数)而得到的,使用机内码表示的一个汉字占用2个字节,分别称为高位字节和低位字节.这两位字节的机内码按一下规则表示:
高位字节=区码+20H+80H(或区码+A0H),
低位字节=位码+20H+80H(或位码+A0H),
例如,汉字”啊”的区位码为1601,区码和位码分别用16进制表示即为1001H.它的机内码的高位字节为B0H,低位字节为A1H.机内码就是B0A1H.
实例截图
前端代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>中文验证码</title>
<link href="css2/css.css" rel="stylesheet" type="text/css" />
<style type="text/css">
table {
width:560px;
border-collapse:collapse; /* 合并单元格之间的边 */
border:1px solid #0099aa;
font:normal 12px/1.5em "宋体", Verdana,Lucida, Arial, Helvetica, sans-serif;
} /* 定义表格的整体宽度以及边框样式,并且定义表格内所有文字的样式 */
</style>
<script type="text/javascript">
function changeCode(){
document.getElementById("imgcode").src="checkCode?nocache="+new Date().getTime();
}
</script>
</head>
<body onload="checkCode">
<form id="regist" method="post" >
<table align="center" border="1" bordercolor="#0099aa">
<tr>
<td align="right" width="130px">用户名:</td>
<td >
<input type="text" name="name" id="name" />
<font color="red">* 用户名由字母数字和下划线组成</font>
</td>
</tr>
<tr>
<td align="right">验证码:</td>
<td >
<img title="看不清,点击更换验证码" style="cursor:pointer" id="imgcode" alt="" src="checkCode" onclick="changeCode()" >
</td>
</tr>
<tr>
<td align="right">输入验证码:</td>
<td><input type="text" name="code" id="code" /></td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="注 册"/>
<input type="reset" value="重 置" />
</td>
</tr>
</table>
</form>
</body>
</html>
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>ChineseCheckCode</servlet-name>
<servlet-class>com.webapp.service.ChineseCheckCode</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ChineseCheckCode</servlet-name>
<url-pattern>/checkCode</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
服务端生成文字验证码,需要使用 response.setContentType("image/jpeg");指定生成的响应是图片
package com.webapp.service;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
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;
/**
*
* ChineseCheckCode.java
*
* @version : 1.1
*
* @author : 苏若年 <a href="mailto:DennisIT@163.com">发送邮件</a>
*
* @since : 1.0 创建时间: 2013-2-13 下午06:45:59
*
* TODO : class ChineseCheckCode.java is used for ...
*
*/
public class ChineseCheckCode extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//禁止缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 0);
// 指定生成的响应是图片
response.setContentType("image/jpeg");
int width = 155; //指定验证码的宽度
int height = 45; //指定验证码的高度
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics(); //获取Graphics类的对象
Random random = new Random(); //实例化一个Random对象
Font mFont = new Font("宋体", Font.ITALIC, 26); //通过Font构造字体
graphics.setColor(getRandomColor(200, 250)); //设置颜色
graphics.fillRect(0, 0, width, height);
graphics.setFont(mFont); //设置字体
graphics.setColor(getRandomColor(180, 200)); //设置文字的颜色
String chckcode = "";
String ctmp = "";
for(int i=0; i<4; i++){
String[] rBase = { "0", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "a", "b", "c", "d", "e", "f" };
//生成第一位的区码
int rand1 = random.nextInt(3)+11; //生成11到14之间的随机数
String strR1 = rBase[rand1];
//生成第二位的区码
int rand2 ;
if(rand1 == 13){
rand2 = random.nextInt(7); //生成0-7之间的随机数
}else{
rand2 = random.nextInt(16); //生成0-16之间的随机数
}
String strR2 = rBase[rand2];
//生成第一位的位码
int rand3 = random.nextInt(15)+1; //生成1到16之间的随即数
String strR3 = rBase[rand3];
//生成第二位的位吗
int rand4;
if(rand3==10){
rand4 = random.nextInt(15)+1; //生成1到16之间的随机数
}else if(rand3==15){
rand4 = random.nextInt(15); //生成0到15之间的随机数
}else{
rand4 = random.nextInt(16); //生成0到16之间的随机数
}
String strR4 = rBase[rand4];
//将生成的机内码转换为汉字
byte[] bytes = new byte[2];
//将生成的区码保存到字节数组的第一个元素中
String strR12 = strR1 + strR2;
int tempLow = Integer.parseInt(strR12, 16);
bytes[0] = (byte) tempLow;
String strR34 = strR3 + strR4;
int tempHigh = Integer.parseInt(strR34, 16);
bytes[1] = (byte) tempHigh;
ctmp = new String(bytes); //根据字节数组生成汉字
chckcode = chckcode + ctmp;
Color color = new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110));
graphics.setColor(color);
/** **随机缩放文字并将文字旋转指定角度* */
Graphics2D graphics2d = (Graphics2D) graphics;
//实例化AffineTransform类的对象
AffineTransform trans = new AffineTransform();
//进行旋转
trans.rotate(random.nextInt(25) * 3.14 / 180, 26 * i + 8, 7);
// 缩放文字
float scaleSize = random.nextFloat() +0.7f;
if (scaleSize > 1f) scaleSize = 1f;
trans.scale(scaleSize, scaleSize); //进行缩放
graphics2d.setTransform(trans);
graphics.drawString(ctmp, width/6 * i+30, height/3+5);
}
//将生成的验证码保存到Session中
HttpSession session = request.getSession(true);
session.setAttribute("chckcode", chckcode);
graphics.dispose();
ImageIO.write(image, "JPEG", response.getOutputStream());
}
/**
* 生成随即颜色
* @param fc
* @param bc
* @return
*/
public Color getRandomColor(int fc, int bc){
Random random = new Random();
Color randomColor = null;
if(fc>255) fc=255;
if(bc>255) bc=255;
//设置个0-255之间的随机颜色值
int r=fc+random.nextInt(bc-fc);
int g=fc+random.nextInt(bc-fc);
int b=fc+random.nextInt(bc-fc);
randomColor = new Color(r,g,b);
return randomColor;//返回具有指定红色、绿色和蓝色值的不透明的 sRGB 颜色
}
}
转载请注明出处:[http://www.cnblogs.com/dennisit/archive/2013/02/16/2913263.html]