zoukankan      html  css  js  c++  java
  • java实现点选汉字验证码(转)

    package com.rd.p2p.web;
    
    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.io.UnsupportedEncodingException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletOutputStream;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.ss.formula.functions.T;
    import org.apache.struts2.convention.annotation.Action;
    
    import com.alibaba.fastjson.JSON;
    import com.rd.p2p.additional.redisCaptcha.util.ResponseUtil;
    import com.rd.p2p.common.util.redis.RedisValidImgCodeUtils;
    import com.rd.p2p.core.core.Global;
    import com.rd.p2p.core.core.constant.Constant;
    import com.rd.p2p.core.core.web.BaseAction; 
    
    public class CodeAction extends BaseAction<T> {
        
          private static final String KEY = "randomCode";
          //点选文字图片验证码刷新次数
          private static final String KEY_TOTAL = "select_random_code_total";
          //点选文字图片验证码验证通过次数
          private static final String KEY_SUCC = "select_random_code_succ";
          //点选文字图片验证码验证失败次数
          private static final String KEY_FAIL = "select_random_code_fail";
          //缓存时间单位秒 设置成7天
          private static final int CACHE_SECONDS = 604800;
          //定义点选文字图片验证码允许的误差值
          private static final int ERROR_AMOUNT = 12;// 定义允许的误差值,单位是px
          //生成汉字的个数
          private static Integer[] arr = new Integer[] {1, 2, 3, 4, 5};
          //汉字颜色随机范围
          private static Color[] colors = {Color.GRAY, Color.LIGHT_GRAY, Color.CYAN};
           
        
        /**
         * 跳转页面
         * @return
         */
        @Action("/verification")
        public String verification() {
            request.setAttribute("web_url", Global.getString("web_url"));
            return "verification";
        }
        
        /**生成验证码
         * @param src
         * @param x
         * @param y
         */
        @Action("/code/getVerificationCode")
        public void readUsingImageReaderBigcH() {
            ServletOutputStream outStream = null;  
            try {
            // http://localhost:8080/gtop/img/149679.jpg
            //String url = "d:/4.png";
            //url = request.getSession().getServletContext().getRealPath("") + url;    
           /* InputStream source = new FileInputStream(src);
            BufferedImage image = null;
            image = ImageIO.read(source);*/
                
            //生成背景图片
            BufferedImage image = getBackGround();
            int hight = image.getHeight();
            Graphics graphics = image.getGraphics();
            // 设置颜色
            graphics.setColor(Color.red);
            graphics.setFont(new Font("宋体", Font.BOLD, 30));
        
            StringBuilder sb = new StringBuilder();
            Random random = new Random();
    
            //转成集合
            List<Integer> intList = Arrays.asList(arr);
            //重新随机排序
            Collections.shuffle(intList);
        
            //list参数坐标参数 用于校验是否验证通过
            List<String> codeList = new ArrayList<String>();
            
            int x = 0;
            int y = 0;
            
            //定义随机1到arr.length某一个字不参与校验
            int num = random.nextInt(arr.length)+1;
            
            for (int i = 0; i < arr.length; i++) { // 5个汉字,只点4个
                String ch = getRandomChineseChar();
                
                int place = intList.get(i);
                if (place == 1) {
                    x = new Random().nextInt(30) + 40; // 自己定义的位子坐标
                    y = new Random().nextInt(30) + 40; // i=1的时候,y的值
                }
                if (place == 2) {
                    x = new Random().nextInt(40) + 120; // 自己定义的位子坐标
                    y = new Random().nextInt(30) + 50; // i=2的时候,y的值
                }
                if (place == 3) {
                    x = new Random().nextInt(70) + 200; // 自己定义的位子坐标
                    y = new Random().nextInt(50) + 100; // i=3的时候,y的值
                }
                if (place == 4) {
                    x = new Random().nextInt(70) + 80; // i=4的时候,x的值
                    y = new Random().nextInt(30) + 90; // 自己定义的位子坐标
                }
                if (place == 5) {
                    x = new Random().nextInt(70) + 180; // i=4的时候,x的值
                    y = new Random().nextInt(30) + 50; // 自己定义的位子坐标
                }
                
                Constant.LOGGER.info("x:" + x + ",y:" + y + ",hight:" + hight);
                //字体颜色
                graphics.setColor(colors[random.nextInt(colors.length)]);
                graphics.drawString(ch, x, y);   
                if (place != num) {
                    sb.append(ch);
                    codeList.add(x + "_" + y); // jsp页面坐标原点在字的中间,drawString方法坐标原点在中间
                }
            }
        
            Constant.LOGGER.info("汉字:" + sb);
            //放入session
            //将产生的随机汉字验证码存进session中进行保存
            String sessionid = request.getSession().getId();
            RedisValidImgCodeUtils.save(sessionid + KEY, codeList);
            //增加验证码请求次数
            RedisValidImgCodeUtils.increment(KEY_TOTAL, CACHE_SECONDS);
        
            // 可以将图片合并传入前端  也可以直接传数据汉字给前端
            // 创建顶部图片
            BufferedImage bi = new BufferedImage(image.getWidth(), 25, BufferedImage.TYPE_INT_RGB);
            Graphics gra = bi.getGraphics();
        
            // 设置背景颜色
            gra.setColor(Color.WHITE);
            // 填充区域
            gra.fillRect(0, 0, bi.getWidth(), bi.getHeight());
        
            // 设置边框颜色
            gra.setColor(Color.BLUE);
            // 设置边框区域
            gra.drawRect(1, 1, bi.getWidth() - 2, bi.getHeight() - 2);
        
            // 设置文字背景颜色
            Font font = new Font("Microsoft YaHei", Font.BOLD, 16);
            gra.setFont(font);
            gra.setColor(Color.BLACK);
            gra.drawString("按顺序点击:" + sb.toString(), (bi.getWidth() - 10*font.getSize())/2, bi.getHeight()/2 + font.getSize()/2);//设置文字字体 与位子  居中
        
            BufferedImage combined = new BufferedImage(image.getWidth(), image.getHeight() + bi.getHeight(), BufferedImage.TYPE_INT_RGB);
        
            Graphics g = combined.getGraphics();      //合并
            g.drawImage(bi, 0, 0, null);
            g.drawImage(image, 0, bi.getHeight(), null);
            outStream=  response.getOutputStream();
            ImageIO.write(combined, "jpg", outStream);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (outStream != null) {
                        outStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }  
            }
        }
        
        @Action("/code/verify")
        public void verify() throws IOException {
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("result", false);
            String value = request.getParameter("code");
            String sessionid = request.getSession().getId();
            if (RedisValidImgCodeUtils.get(sessionid + KEY) == null) {
                printWebJson(JSON.toJSONString(data));
                 return;
            }
            List<String> sValue = (List<String>) RedisValidImgCodeUtils.get(sessionid + KEY);
            
            //取到数据后直接清掉redis
            RedisValidImgCodeUtils.del(sessionid + KEY);
            
            Constant.LOGGER.info("**前端请求数据***"+value);
            Constant.LOGGER.info("**后端实际数据**"+sValue.toString());
          
            //为null 或者"" 或者 " "
            if (StringUtils.isBlank(value) || sValue == null || sValue.size() < 1) {
                printWebJson(JSON.toJSONString(data));
                return;
            }
        
            String [] valueStr = value.split(",");
            if(valueStr.length != sValue.size() || valueStr.length != 4){
                printWebJson(JSON.toJSONString(data));
                return;
            }
        
            /*判断坐标参数是否正确*/
            String str = "";
            for (int i = 0; i < valueStr.length; i++) {
                str = valueStr[i].toString();
                if(StringUtils.isBlank(str) || StringUtils.isBlank(sValue.get(i).toString())){
                    printWebJson(JSON.toJSONString(data));
                    return;
                }
                String [] vL = valueStr[i].toString().split("_");
                String [] svL = sValue.get(i).toString().split("_");
                if(vL.length != svL.length || svL.length != 2){
                    printWebJson(JSON.toJSONString(data));
                    return;
                }
                //x轴  y轴判断    坐标点在左上角 ,图片宽度30px  点击范围扩大12px,  范围在      x-13 < x <x+13  ;
                if(!(Integer.parseInt(svL[0])-ERROR_AMOUNT < Integer.parseInt(vL[0])-15 && Integer.parseInt(vL[0])-15 < Integer.parseInt(svL[0])+ERROR_AMOUNT )
                    || !(Integer.parseInt(svL[1])-ERROR_AMOUNT < Integer.parseInt(vL[1])-15 && Integer.parseInt(vL[1])-15 < Integer.parseInt(svL[1])+ERROR_AMOUNT)){
                    //增加验证失败次数
                    RedisValidImgCodeUtils.increment(KEY_FAIL, CACHE_SECONDS);
                    printWebJson(JSON.toJSONString(data));
                    return;
                }
            }
            //增加验证通过次数
            RedisValidImgCodeUtils.increment(KEY_SUCC, CACHE_SECONDS);
            data.put("result", true);
            printWebJson(JSON.toJSONString(data));
        }
        
        /**
         * 生成背景图片
         * @return
         */
        public BufferedImage getBackGround(){
            int width=300;           //指定生成验证码的宽度  
            int height=200;          //指定生成验证码的高度  
            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));    //线条色
            
            //绘制88根位置和颜色全部为随机产生的线条,该线条为2f  
            for (int i = 0; i < 88; i++) {  
                int x = random.nextInt(width-1);  
                int y = random.nextInt(height-1);  
                int x1 = random.nextInt(100)+1;  
                int y1 = random.nextInt(120)+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);             //绘制直线  
    //            g2d.setColor(getRandColor(random, 30, 150));  //随机每条线条的颜色
            }  
              
            //输出生成的验证码图片  
            g.dispose();  
            return image;
        }
        
        private static Color getRandColor(Random random, int fc, int bc){  
            if (fc > 255)  
                fc = 255;  
            if (bc > 255)  
                bc = 255;  
            int r = fc + random.nextInt(bc - fc);  
            int g = fc + random.nextInt(bc - fc);  
            int b = fc + random.nextInt(bc - fc);  
            return new Color(r, g, b);  
        }  
      
        private static String[] generateCheckCode() {  
            String[] res = new String[2];  
            Random random = new Random();  
            int intTemp;  
            int intFirst = random.nextInt(100);  
            int intSec = random.nextInt(100);  
            String checkCode = "";  
            int result = 0;  
            switch (random.nextInt(6)) {  
                case 0:  
                    if (intFirst < intSec) {  
                        intTemp = intFirst;  
                        intFirst = intSec;  
                        intSec = intTemp;  
                    }  
                    checkCode = intFirst + " - " + intSec + " = ?";  
                    result = intFirst-intSec;  
                    break;  
                case 1:  
                    if (intFirst < intSec) {  
                        intTemp = intFirst;  
                        intFirst = intSec;  
                        intSec = intTemp;  
                    }  
                    checkCode = intFirst + " - ? = "+(intFirst-intSec);  
                    result = intSec;  
                    break;  
                case 2:  
                    if (intFirst < intSec) {  
                        intTemp = intFirst;  
                        intFirst = intSec;  
                        intSec = intTemp;  
                    }  
                    checkCode = "? - "+intSec+" = "+(intFirst-intSec);  
                    result = intFirst;  
                    break;  
                case 3:  
                    checkCode = intFirst + " + " + intSec + " = ?";  
                    result = intFirst + intSec;  
                    break;  
                case 4:  
                    checkCode = intFirst + " + ? ="+(intFirst+intSec);  
                    result = intSec;  
                    break;  
                case 5:  
                    checkCode = "? + " + intSec + " ="+(intFirst+intSec);  
                    result = intFirst;  
                    break;  
            }  
            res[0] = checkCode;
            res[1] = String.valueOf(result);
            Constant.LOGGER.info("result=" + result);
            return res;  
        }  
        
        
        @Action("/code/calc")
        public void calcCode() throws IOException{
            int width = 140, height = 37;  
            try {  
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
                Graphics g = image.getGraphics();  
                Random random = new Random();  
                g.setColor(getRandColor(random, 200, 250));  
                g.fillRect(0, 0, width, height);  
          
                String[] fontTypes = { "u5b8bu4f53", "u65b0u5b8bu4f53", "u9ed1u4f53", "u6977u4f53", "u96b6u4e66" };  
                int fontTypesLength = fontTypes.length;  
          
                g.setColor(getRandColor(random, 160, 200));  
                g.setFont(new Font("Times New Roman", Font.PLAIN, 14 + random.nextInt(6)));  
                  
                for (int i = 0; i < 255; i++) {  
                    int x = random.nextInt(width);  
                    int y = random.nextInt(height);  
                    int xl = random.nextInt(12);  
                    int yl = random.nextInt(12);  
                    g.drawLine(x, y, x + xl, y + yl);  
                }  
                  
                String[] result = generateCheckCode();  
                RedisValidImgCodeUtils.save(request.getSession().getId() + "calc_code", result[1]);
                String [] baseChar = result[0].split(" ");  
                for (int i = 0; i < baseChar.length; i++) {  
                    g.setColor(getRandColor(random, 30, 150));  
                    g.setFont(new Font(fontTypes[random.nextInt(fontTypesLength)], Font.BOLD, 22 + random.nextInt(6)));  
                    g.drawString(baseChar[i], 24 * i + 10, 24);  
                }  
                g.dispose();  
                //发送图片
                ResponseUtil.sendImg(response, image, "image/jpeg", "code", "jpg");
            } catch (IllegalStateException e) {  
                Constant.LOGGER.error(e.getMessage());  
                e.printStackTrace();  
            }  
        }
        
        @Action("/code/getRandomCode")
        public void getRandomCode() throws 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=140;           //指定生成验证码的宽度  
            int height=37;          //指定生成验证码的高度  
            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, 22); //定义字体样式  
            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-1);  
                int y = random.nextInt(height-1);  
                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++){  
                switch (random.nextInt(2)) {  
                case 0:
                    itmp = random.nextInt(26)+65;               //生成A~Z的字母  
                    ctmp = String.valueOf((char)itmp);  
                    break;  
                default:
                    ctmp = String.valueOf(random.nextInt(8)+2);       //生成2~9的数字  
                    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, 20*i+18, 18);   //每个字的间距xy
            }  
            //将生成的验证码保存道session中  
            RedisValidImgCodeUtils.save(request.getSession().getId() + "randCheckCode", sRand);
              
            //输出生成的验证码图片  
            g.dispose();  
            ImageIO.write(image, "JPEG", response.getOutputStream());  
        }  
        
        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);  
        }  
        
        public static String getRandomChineseChar() {
            String str = null;
            int hs, ls; 
            Random random = new Random();
            hs = (176 + Math.abs(random.nextInt(39))); 
            ls = (161 + Math.abs(random.nextInt(93)));
            byte[] b = new byte[2];
            b[0] = (new Integer(hs).byteValue());
            b[1] = (new Integer(ls).byteValue());
            try  {
                str = new String(b, "GBk"); //转成中文
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
            }
            return str;
        }
        
    }
    <!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-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
    <script src="${web_url}/api/themes/theme_default/media/js/jquery.js"></script>
    <title>验证码</title>
    </head>
    <body>
    <div style="text-align:center;position:relative;">
    <!--<h2>这是点击的验证码</h2> -->
    <!-- 这是点击的验证码 -->
    <img id="codeT3" src="${web_url}/api/code/getVerificationCode.html?flag=" +Math.random()"/>
    </br>
    <!-- 
    <input type="button" value="刷新" onclick="getCodeTree();" /> 
            
    <input type="button" value="校验" onclick="cheakOutTree();" />
    -->
    <select id="codeSelect" style="display: none;"></select>
    <img src="${web_url}/api/refresh.png" style="position:absolute;right:0;top:0; 20px; height: 20px;" onclick="getCodeTree();" />
    </div>
    
    
    <script type="text/javascript">
    //点击次数
    var number=0;
    
    //获取验证码3
    function getCodeTree() {
    number = 0;
    $(".zhezhao").remove();
    document.getElementById("codeSelect").options.length = 0;
    $("#codeT3").attr("src","${web_url}/api/code/getVerificationCode.html?flag="+Math.random());
    }
    
    $(function() {
    $("#codeT3").bind("click", function(ev) {
    var oEvent = ev || event;
    //var number = $("#codeSelect option").length;
    number++;
    
    if (number > 4) {
    return;
    }
    
    var x = oEvent.pageX;
    var y = oEvent.pageY;
    var img = document.getElementById('codeT3'); //获取图片的原点
    var nodex = getNodePosition(img)[0];//原点x 与原点y
    var nodey = getNodePosition(img)[1];
    
    
    var xserver = parseInt(x) - parseInt(nodex);
    var yserver = parseInt(y) - parseInt(nodey);
    
    
    $("#codeSelect").append(
    "<option value='"+ (parseInt(number)+1) +"'>" + xserver + "_" + yserver
    + "</option>");
    var oDiv = document.createElement('img');
    oDiv.style.left = (parseInt(x)-15) + 'px'; // 指定创建的DIV在文档中距离左侧的位置 图片大小30 左右移动5
    oDiv.style.top = (parseInt(y) -15) + 'px'; // 指定创建的DIV在文档中距离顶部的位置
    oDiv.style.border = '1px solid #FF0000'; // 设置边框
    oDiv.style.position = 'absolute'; // 为新创建的DIV指定绝对定位
    oDiv.style.width = '30px'; // 指定宽度
    oDiv.style.height = '30px'; // 指定高度
    //oDiv.src = 'select.png';
    oDiv.style.opacity = '0.5'; //透明度
    oDiv.className = 'zhezhao';//加class 点刷新后删除遮罩
    document.body.appendChild(oDiv);
    
    //第四次点击后自动提交
    if (number == 4) {
    cheakOutTree();
    }
    
    });
    
    })
    
    //校验验证码
    function cheakOutTree() {
    var txt = "";
    $("#codeSelect option").each(function (){ 
    var text = $(this).text(); 
    if(txt == ""){
    txt = text;
    }else{
    txt = txt + "," + text;
    }
    }); 
    $.ajax({ 
    type:"post", 
    url:"${web_url}/api/code/verify.html",
    data : {"code" : txt},
    cache : false,
    success : function(data) {
    alert(data.result);
    if (!data.result) {
    getCodeTree();
    }
    }
    }); 
    }
    
    function getNodePosition(node) { 
    var top = left = 0;
    while (node) { 
    if (node.tagName) {
    top = top + node.offsetTop;
    left = left + node.offsetLeft; 
    node = node.offsetParent;
    }
    else {
    node = node.parentNode;
    }
    } 
    return [left, top];
    }
    
    
    </script>
    
    
    </body>
    </html>
    

      

  • 相关阅读:
    DAS存储未死,再次欲获重生
    Minimum edit distance(levenshtein distance)(最小编辑距离)初探
    AC自己主动机
    手动脱UPX 壳实战
    edge中断分析
    ubuntu默认的Python版本号修改
    Linux 下 pushd,popd,cd- 用法
    目标检测算法的历史及分类
    openjtag 的硬件连接踩坑历程
    ubuntu 16.04 python版本切换(python2和python3)
  • 原文地址:https://www.cnblogs.com/SimonHu1993/p/9485423.html
Copyright © 2011-2022 走看看