程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 仿12306的圖片驗證碼,仿12306圖片驗證碼

仿12306的圖片驗證碼,仿12306圖片驗證碼

編輯:JAVA綜合教程

仿12306的圖片驗證碼,仿12306圖片驗證碼


由於要做一個新項目,所以打算做一個簡單的圖片驗證碼。

先說說思路吧:在服務端,從一個文件夾裡面找出8張圖片,再把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>
        <div id="base">
            <img src="<%=request.getContextPath()%>/identify">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();

 驗證碼整體代碼完成了,還有有一些細節要處理。由於圖片容易被百度識圖,要對生成的圖片做模糊處理,暫時還沒想到什麼好的辦法~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved