热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Java仿12306图片验证码

这篇文章主要为大家详细介绍了Java仿12306的图片验证码的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

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

先放两张效果图:

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

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

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

//选取8个图片
public static List getEightImages() {
 //保存取到的每一个图片的path,保证图片不会重复
 List paths = new ArrayList();
 
 File[] finalImages = new File[8];
 List object = new ArrayList();
 
 //保存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 getLocation(String[] tips) {
 List locatiOns= new ArrayList();
 
 //获取Key分类
 String tip = getTip(tips);
 locations.add(tip);
  
 int length = tips.length;
 for (int i = 0; i 

选取了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 = ImageSelectedHelper.getEightImages();
 File[] finalImages = (File[]) object.get(0);
 
 String[] tips = (String[]) object.get(1);
 //所有key的图片位置,即用户必须要选的图片
 List 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 

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








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 &#63; e : (window.event &#63; 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 isPass(String result) {
  
 String[] xyLocatiOns= result.split(",");
 //保存用户选择的坐标落在哪些图片上
 List list = new ArrayList();
 //每一组坐标
 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();

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

更多关于验证码的文章请点击查看:《java验证码》

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


推荐阅读
  • ServletContext接口在Java Web开发中扮演着重要角色,它提供了一种方式来获取关于整个Web应用程序的信息。通过ServletContext,开发者可以访问初始化参数、共享数据以及应用资源。 ... [详细]
  • 本文探讨了如何通过WebBrowser控件在用户点击输入框时自动显示图片验证码。该过程可能涉及JavaScript事件的触发与响应。 ... [详细]
  • C# 对象转 JSON 字符串的方法与应用
    本文介绍如何在 C# 中使用一般处理程序(ASHX)将对象转换为 JSON 字符串,并通过设置响应类型为 application/json 来确保客户端能够正确解析返回的数据。同时,文章还提供了 HTML 页面中不依赖 jQuery 的 AJAX 方法来接收和处理这些 JSON 数据的具体实现。 ... [详细]
  • 理解文档对象模型(DOM)
    本文介绍了文档对象模型(DOM)的基本概念,包括其作为HTML文档的节点树结构,以及如何通过JavaScript操作DOM来实现网页的动态交互。 ... [详细]
  • 本文探讨了浏览器的同源策略限制及其对 AJAX 请求的影响,并详细介绍了如何在 Spring Boot 应用中优雅地处理跨域请求,特别是当请求包含自定义 Headers 时的解决方案。 ... [详细]
  • Microsoft即将发布WPF/E的CTP(Community Technology Preview)和SDK,标志着RIA(Rich Internet Application)技术的新里程碑。更多详情及下载链接请参见MSDN官方页面。 ... [详细]
  • AJAX技术允许网页在不重新加载整个页面的情况下进行异步更新,通过向服务器发送请求并接收JSON格式的数据,实现局部内容的动态刷新。 ... [详细]
  • 深入理解Django中的AJAX应用
    本文详细介绍了AJAX技术及其在Django框架中的应用。AJAX,即异步JavaScript和XML,允许网页在不重新加载整个页面的情况下与服务器交换数据并更新部分网页。 ... [详细]
  • 本文详细介绍了在Ubuntu 7.10操作系统上安装多种常用软件的方法,包括RAR压缩工具、即时通讯软件Pidgin、办公软件永中Office 2007试用版、多线程下载软件MultiGet及d4x、FTP客户端gFTP与FireFTP插件,以及P2P下载工具aMule。每部分都提供了具体的安装步骤和配置方法。 ... [详细]
  • 深入解析Serverless架构模式
    本文将详细介绍Serverless架构模式的核心概念、工作原理及其优势。通过对比传统架构,探讨Serverless如何简化应用开发与运维流程,并介绍当前主流的Serverless平台。 ... [详细]
  • yikesnews第11期:微软Office两个0day和一个提权0day
    点击阅读原文可点击链接根据法国大选被黑客干扰,发送了带漏洞的文档Trumps_Attack_on_Syria_English.docx而此漏洞与ESET&FireEy ... [详细]
  • 本文介绍了如何利用Selenium和Python通过执行JavaScript代码来控制网页中的滚动条,包括垂直和水平滚动条的控制,以及特定元素的聚焦技术。 ... [详细]
  • 本文介绍了ThinkPHP框架的基本概念及其主要特性。作为一款遵循Apache许可证的开源框架,ThinkPHP不仅支持多种平台和Web服务器,还提供了丰富的功能以适应不同的开发需求。 ... [详细]
  • 本文深入探讨了 Prototype.js 框架及其与 JavaScript 原生 toString() 方法之间的区别,适合对前端开发感兴趣的开发者阅读。文章将帮助读者理解两者在功能实现和应用场景上的不同,从而更好地利用这些工具进行高效编程。 ... [详细]
  • 本文详细探讨了成为一名合格的初级Java工程师所需掌握的知识体系,以及从初级到中级乃至高级工程师的成长路径和职业发展前景。 ... [详细]
author-avatar
exit佑
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有