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

先说说思路吧:在服务端,从一个文件夹里面找出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 < 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 = 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 < 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个图片的右下角。

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 = "/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 = "/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 验证码 仿12306_Java仿12306图片验证码相关推荐

  1. 爬虫笔记40之反爬系列三:复杂验证码的处理(12306图片验证码、行为验证:selenium鼠标行为链 + 算法)

    一.12306图片验证码 ​ 解决方案: selenium(鼠标行为链) + 打码平台 ​ 思路: 通过selenium来加载登录页面,获取验证码图片.我就可以把验证码图片交给超级鹰打码平台进行处理. ...

  2. Python破解12306图片验证码

    不知从何时起,12306的登录验证码竟然变成了按字找图,可以说是又提高了一个等次,竟然把图像识别都用上了.不过有些图片,不得不说有些变态,图片的清晰图就更别说了,明显是从网络上的图库中搬过来的. 谁知 ...

  3. python识别12306验证码_Python 识别12306图片验证码物品的实现示例

    1.PIL介绍以及图片分割 Python 3 安装:  pip3 install Pillow 1.1 image 模块 Image模块是在Python PIL图像处理中常见的模块,主要是用于对这个图 ...

  4. Java实现点击中文文字图片验证码

    Java实现点击中文文字图片验证码 环境条件 JDK1.8 MAVEN-3.3 spring-boot-2.1.17.RELEASE Redis 注意事项 Java AWT在背景图片上绘写文件时候设置 ...

  5. php实现12306验证码,PHP仿12306图片验证码

    生成验证码的demo使用模型model读取图库,有需要对接框架的朋友可以自己修改,如下: # 引入测试的数据库model require_once dirname(__FILE__).'/Model. ...

  6. 用深度学习破解12306图片验证码,识别率超96%- web效果版

    12306最新版图片验证码已被破解已是公开的秘密.比如市面上那么专业多抢票软件,早就破解了这个图片验证码.     那他们到底是怎么实现的呢???     据本人猜测,应该都是基于近2年流行的深度学习 ...

  7. Python——12306图片验证码

    本次爬虫,我们来模拟一下12306的验证码验证                           本次练习用到的模块: requests re base64 urllib3 第一步,按F12查看验证 ...

  8. java自动识别图片验证码插件_JMeter开发插件——图片验证码识别

    我们在性能测试中总会时不时地遭遇到来自于应用系统的各种阻碍,图片验证码就是一类最常见的束缚,登录或交易时需要按照图片中的内容输入正确的验证信息后,数据才可以提交成功,这使得许多性能测试工具只能望而却步 ...

  9. php验证码大全(实例分享),php图片验证码的例子

    代码如下: /** * 生成验证码图片 * site www.jbxue.com * @param String $word 验证码在session中的变量名称 */ function valiCod ...

  10. java 拖动验证码实现_java实现拖动图片验证码

    思路是,对原图产生两张图片,一张是底图,被抠掉一部分的图片,另外一张是移动图,被抠出的来部分 只写了后台怎么生成拖动验证码的两个图片,前端的还没写,待续.以下是后台的代码 class="ja ...

最新文章

  1. 心得丨深度学习的技术原理、迭代路径与局限
  2. 十大互联网公司都在寻找她!她是什么样的?
  3. Metro Win8风格的按钮(Filp翻转)
  4. [转]一张图理解prototype、proto和constructor的三角关系
  5. linux搭建环境经验,经验总结54--搭建linux虚拟机环境
  6. linux 查看其他磁盘分区,Linux 查看磁盘分区.pdf
  7. matlab 合并相同元素,matlab中删除相邻相同元素
  8. 聊聊lettuce的sentinel连接
  9. 射电天文谱线接收机和终端系统
  10. oracle 建立一个游戏库,Power Designer怎么新建Oracle数据?建立Oracle数据教程分享
  11. Linux 环境边配置边学(针对家里电脑) 【五】
  12. ARM指令集之乘法指令
  13. MSCS+FailSafe 双机集群做HA 小结
  14. 云栖大会day2总结 上午
  15. 工程师,请把你的英语磨锐
  16. Git 远程篇之查看远程仓库信息
  17. Android开发模式万佛朝中MVX(MVC、MVP、MVVM)
  18. (python)约瑟夫(Josephus)个人围成一圈,并按顺时针依次编号1-n。从编号为1的人开始,按顺时针方向每隔一 人选出一个,剩下的人重新围成一圈,如此循环直到剩下两人,这剩下的两人就是幸运儿
  19. 【mac】设置的环境变在重启终端后不生效。
  20. 小李飞刀系列之Oracle EBS期间平均成本(PAC)--生产成本计算(五)制造费用分摊

热门文章

  1. c语言编程泰勒展开式计算,学习笔记:用c语言编写泰勒展开公式myexp()实现math.h.数学函数...
  2. TortoiseGit解决冲突
  3. 干法:经营者应该怎样工作
  4. 2021年危险化学品生产单位安全生产管理人员新版试题及危险化学品生产单位安全生产管理人员找解析
  5. 【winRAR去广告弹窗】
  6. 项目播报 | 方正璞华×联影医疗,赋能医疗行业新升级!
  7. CSS3-3D变换 transform-style:preserve-3d
  8. 【车间调度】柔性作业车间调度问题的研究方法
  9. 关系数据库标准语言SQL——详解版2
  10. MIT线性代数笔记二十八讲 相似矩阵和若尔当标准型