Java仿12306图片验证码

由于要做一个新项目,所以打算做一个简单的图片验证码。

先说说思路吧:在服务端,从一个文件夹里面找出8张图片,再把8张图片合并成一张大图,在8个小图里面随机生成一个要用户验证的图片分类,如小狗、啤酒等。在前端,访问这个页面时,把图片加载上去,用户在图片上选择提示所需要的图片,当用户点登陆时,根据用户选择的所有坐标判断所选的图片是不是实际上的验证图片。

先放两张效果图:

为了让文件查找比较简单,在图片文件结构上可以这样:

这样方便生成用户要选择的Key图片,和取出8张小图合并成大图。

上代码:这是选择8张图片,并且在每张图片选取时用递归保证选取的图片不会重复。

//选取8个图片
public static List<Object> getEightImages() {
 //保存取到的每一个图片的path,保证图片不会重复
 List<String> paths = new ArrayList<String>();

 File[] finalImages = new File[8];
 List<Object> object = new ArrayList<Object>();

 //保存tips
 String[] tips = new String[8];

 for (int i = 0; i < 8; i++) {
  //获取随机的二级目录
  int dirIndex = getRandom(secondaryDirNumbers);
  File secondaryDir = getFiles()[dirIndex];

  //随机到的文件夹名称保存到tips中
  tips[i] = secondaryDir.getName();

  //获取二级图片目录下的文件
  File[] images = secondaryDir.listFiles();

  int imageIndex = getRandom(imageRandomIndex);
  File image = images[imageIndex];

  //图片去重
  image = dropSameImage(image, paths, tips, i);  

  paths.add(image.getPath());

  finalImages[i] = image;

 }
 object.add(finalImages);
 object.add(tips);
 return object;
}

在生成这8张图片中,用一个数组保存所有的文件分类。在这个分类里面可以用随机数选取一个分类做为Key分类,就是用户要选择的所有图片。由于数组是有序的,可以遍历数组中的元素,获取每个key分类图片的位置,方便在用户验证时,进行匹配。

//获取位置,返回的是第几个图片,而不是下标,从1开始,集合第一个元素为tip
 public static List<Object> getLocation(String[] tips) {
  List<Object> locations = new ArrayList<Object>();

  //获取Key分类
  String tip = getTip(tips);
  locations.add(tip);

  int length = tips.length;
  for (int i = 0; i < length; i++) {
   if (tip.equals(tips[i])) {

    locations.add(i+1);
   }
  }
  return locations;
 }
 

选取了8张图片后,接下来就是合并图片。合并图片可以用到BufferedImage这个类的方法:setRGB()这个方法如果不明白可以看下api文档,上面有详细的说明。

public static void mergeImage(File[] finalImages, HttpServletResponse response) throws IOException {

  //读取图片
  BufferedImage mergeImage = new BufferedImage(800, 400, BufferedImage.TYPE_INT_BGR);

  for (int i = 0; i < 8; i++) {
   File image = finalImages[i];

   BufferedImage bufferedImage = ImageIO.read(image);
   int width = bufferedImage.getWidth();
   int height = bufferedImage.getHeight();
   //从图片中读取RGB
   int[] imageBytes = new int[width*height];
   imageBytes = bufferedImage.getRGB(0, 0, width, height, imageBytes, 0, width);
   if ( i < 4) {
    mergeImage.setRGB(i*200, 0, width, height, imageBytes, 0, width);
   } else {
    mergeImage.setRGB((i -4 )*200, 200, width, height, imageBytes, 0, width);
   }   

  }

  ImageIO.write(mergeImage, "jpg", response.getOutputStream());
  //ImageIO.write(mergeImage, "jpg", destImage);
 }

  在controller层中,先把key分类保存到session中,为用户选择图片分类做提示和图片验证做判断。然后把图片流输出到response中,就可以生成验证图片了。

response.setContentType("image/jpeg");
  response.setHeader("Pragma", "No-cache");
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", 0);

  List<Object> object = ImageSelectedHelper.getEightImages();
  File[] finalImages = (File[]) object.get(0);

  String[] tips = (String[]) object.get(1);
  //所有key的图片位置,即用户必须要选的图片
  List<Object> locations = ImageSelectedHelper.getLocation(tips);

  String tip = locations.get(0).toString();
  System.out.println(tip);
  session.setAttribute("tip", tip);
  locations.remove(0);

  int length = locations.size();
  for (int i = 0; i < length; i++) {
   System.out.println("实际Key图片位置:" + locations.get(i));
  }

  session.setAttribute("locations", locations);
  ImageMerge.mergeImage(finalImages, response);

  在jsp中,为用户的点击生成小图片标记。当用户点图片击时,在父div上添加一个子div标签,并且把他定位为relative, 并且设置zIndex,然后再这个div上添加一个img标签,定位为absolute。在用户的点击时,可以获取点击事件,根据点击事件获取点击坐标,然后减去父div的坐标,就可以获取相对坐标。可以根据自己的喜好定坐标原点,这里的坐标原点是第8个图片的右下角。  

<div><br>  <div id="base"><br>   <img src="<%=request.getContextPath()%>/identify" style="width: 300px; height: 150px;" onclick="clickImg(event)" id="bigPicture"><br>  </div><br>  <br> </div><br><br>function clickImg(e) {
  var baseDiv = document.getElementById("base");
  var topValue = 0;
  var leftValue = 0;
  var obj = baseDiv;
  while (obj) {
   leftValue += obj.offsetLeft;
   topValue +=obj.offsetTop;
   obj = obj.offsetParent;
  }
  //解决firefox获取不到点击事件的问题
  var clickEvent = e ? e : (window.event ? window.event : null);

  var clickLeft = clickEvent.clientX + document.body.scrollLeft - document.body.clientLeft - 10;
  var clickTop = clickEvent.clientY + document.body.scrollTop - document.body.clientTop - 10;
  var divId = "img_" + index++;

  var divEle = document.createElement("div");

  divEle.setAttribute("id", divId);
  divEle.style.position = "relative";
  divEle.style.zIndex = index;
  divEle.style.width = "20px";
  divEle.style.height = "20px";
  divEle.style.display = "inline";

  divEle.style.top = clickTop - topValue - 150 + 10 + "px";
  divEle.style.left = clickLeft - leftValue - 300 + "px";

  divEle.setAttribute("onclick", "remove('" + divId + "')");
  baseDiv.appendChild(divEle);

  var imgEle = document.createElement("img");
  imgEle.src = "<%=request.getContextPath()%>/resources/timo.png";
  imgEle.style.width = "20px";
  imgEle.style.height = "20px";
  imgEle.style.top = "0px";
  imgEle.style.left = "0px";
  imgEle.style.position = "absolute";
  imgEle.style.zIndex = index;
  divEle.appendChild(imgEle);
 }

用户选择登录后,服务器端根据用户的选择坐标进行判断

public List<Integer> isPass(String result) {

  String[] xyLocations = result.split(",");
  //保存用户选择的坐标落在哪些图片上
  List<Integer> list = new ArrayList<Integer>();
  //每一组坐标
  System.out.println("用户选择图片数:"+xyLocations.length);
  for (String xyLocation : xyLocations) {
   String[] xy = xyLocation.split("\\|\\|");
   int x = Integer.parseInt(xy[0]);
   int y = Integer.parseInt(xy[1]);

   //8,4图片区间
   if ( x > -75 && x <= 0) {

    if ( y > -75 && y <= 0) {  //8号
     list.add(8);

    } else if ( y >= -150 && y <= -75 ) {  //4号
     list.add(4);
    }
   } else if ( x > -150 && x <= -75) {  //7,3图片区间

    if ( y > -75 && y <= 0) {  //7号
     list.add(7);

    } else if ( y >= -150 && y <= -75 ) {  //3号
     list.add(3);
    }
   } else if ( x > -225 && x <= -150) {  //6,2图片区间

    if ( y > -75 && y <= 0) {  //6号
     list.add(6);

    } else if ( y >= -150 && y <= -75 ) {  //2号
     list.add(2);
    }

   } else if ( x >= -300 && x <= -225) {  //5,1图片区间

    if ( y > -75 && y <= 0) {  //5号
     list.add(5);

    } else if ( y >= -150 && y <= -75 ) {  //1号
     list.add(1);
    }
   } else {
    return null;
   }
  }
  return list;
 }

刷新生成新的图片,由于ajax不支持二进制流,可以自己用原生的xmlHttpRequest对象加html5的blob来完成。

function refresh() {
 var url = "<%=request.getContextPath()%>/identify";
 var xhr = new XMLHttpRequest();
 xhr.open('GET', url, true);
 xhr.responseType = "blob";
 xhr.onload = function() {
  if (this.status == 200) {
   var blob = this.response;
   //加载成功后释放blob
   bigPicture.onload = function(e) {
    window.URL.revokeObjectURL(bigPicture.src);
   };
   bigPicture.src = window.URL.createObjectURL(blob);
  }
 }
 xhr.send();

验证码整体代码完成了,还有有一些细节要处理。

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • Java生成验证码

    Java 生成验证码的流程是: 收到请求->生成验证码所用的随机数->使用随机数写出图片->将随机数记录到Session中->输出验证码 Java 验证验证码的流程是: 收到请求->获取用户传过来的验证码数字->验证是否正确->输出验证结果 下面通过一个例子来展示验证码的生成流程,该例子使用基本Java Spring框架的Rest接口,可以使用任何平台来获取验证码: 服务器处理验证码的例子: 1.接收验证码请求: /** * 接收验证码请求 */ @Request

  • Java随机生成手机短信验证码的方法

    本文实例讲述了Java随机生成手机短信验证码的方法.分享给大家供大家参考,具体如下: /** * 创建指定数量的随机字符串 * @param numberFlag 是否是数字 * @param length * @return */ public static String createRandom(boolean numberFlag, int length){ String retStr = ""; String strTable = numberFlag ? "1234

  • Java Web开发之图形验证码的生成与使用方法

    本文实例讲述了Java Web开发之图形验证码的生成与使用方法.分享给大家供大家参考.具体如下: 图形验证码的主要目的是为了增强的安全性,增加用户通过遍历所有可能性来破解密码的难度. 图形验证码的使用包括如下3部分: ① 图形验证码的生成: ② 在页面中的使用: ③ 验证: 1.图形验证码的生成 假设在Servlet生成图形验证码,在JavaBean或者JSP中生成的基本过程是相同的.设计如下过程: ① 设置响应的文档类型: ② 生成随机码: ③ 把随机码保存到session中: ④ 生成图片:

  • java web中图片验证码功能的简单实现方法

    用户在注册网站信息的时候基本上都要数据验证码验证.那么图片验证码功能该如何实现呢? 大概步骤是: 1.在内存中创建缓存图片 2.设置背景色 3.画边框 4.写字母 5.绘制干扰信息 6.图片输出 废话不多说,直接上代码 package com.lsgjzhuwei.servlet.response; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.Buffer

  • Java实现仿淘宝滑动验证码研究代码详解

    通过下面一张图看下要实现的功能,具体详情如下所示: 现在我就来介绍些软件的其它功能.希望大家有所受益. 模拟人为搜索商品 在刷单的时候,不能直接拿到一个商品网址就进入购买页面吧,得模拟人为搜索. 在这一个过程中有两个难点: 1)商品列表的异步加载 ; 2)翻页并且截图; 在园子里,我就不在关公面前耍大刀了. 直接上关键代码: i:搜索商品,并且翻页 public bool? SearchProduct(TaskDetailModel taskDetailData) { bool? result

  • Java实现验证码具体代码(图片、汉字)

    本文为大家分享两个实例,相信大家一定会喜欢. 实例1:随机生成验证码图片并将之输出为一个png文件 效果图: import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Random; import javax.

  • java生成图片验证码实例代码

    关于java图片验证码的文章最近更新了不少,帮助大家掌握java验证码的生成技术,下文为大家分享了java生成图片验证码最简单的方法,供大家参考. 现在各行业在定制系统时都会考虑到机器注册,现在最有效的方式就是输入验证.现在的验证方式有很多种: 一.问题验证,其实也是图片验证,在图片上生成问题,然后输入框输入答案. 二.图片验证,输入图片上展示的文字信息. 三.短信验证,比较繁杂,用户也不怎么喜欢. 四.还有就是百度最新的验证方式.图片上生成文字,然后出现一个文字点击框,选择你在验证图片上看到的

  • java实现验证码类生成中文验证码

    复制代码 代码如下: package xwcms.net.service;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.image.BufferedImage;import java.io.IOException;import java.util.Random;import javax.imageio.ImageIO;im

  • Java实现验证码具体代码

    这里实现我使用到了struts2模拟一个登录功能来验证java实现的验证码功能. Java实现验证码的步骤: 1.创建RandomImageGenerator.java类,该类实现验证码图片的生成 2.创建一个servlet类,RandomImageServlet.java,将生成的验证码输出到页面 3.创建一个Action类,LoginAction.java,控制登录 4.配置struts.xml一个web.xml文件 5.编写页面 具体实现用代码表达 1.创建RandomImageGener

  • Java Web项目中验证码功能的制作攻略

    一.前言 在表单页面中使用验证码的好处在于有效防止用户恶意提交表单,或者使用外挂非法攻击系统. 二.准备条件 1.一个普通的web项目 webProject: 2.一个web服务器 Tomcat. 三.实现思路: 1.自定义一个servlet  VerifyCodeServlet 画一个包含验证字符的验证码图片,这里的图片需要使用Graphics2D手动去画: 2.在具体页面使用img标签的src引用这个servlet即可显示servlet: 3.因为画图的时候把验证码信息放入了session,

随机推荐