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="注 册"/>&nbsp;&nbsp;
                    <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]

在线交谈

原文地址:https://www.cnblogs.com/dennisit/p/2913263.html