当前位置: 移动技术网 > IT编程>开发语言>Java > Java仿12306图片验证码

Java仿12306图片验证码

2019年07月22日  | 移动技术网IT编程  | 我要评论
由于要做一个新项目,所以打算做一个简单的图片验证码。 先说说思路吧:在服务端,从一个文件夹里面找出8张图片,再把8张图片合并成一张大图,在8个小图里面随机生成一个要用户验

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

先说说思路吧:在服务端,从一个文件夹里面找出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();

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

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

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网