1. 程式人生 > >Web---圖片驗證碼生成教程詳解-從簡單到複雜-從本地到前後臺

Web---圖片驗證碼生成教程詳解-從簡單到複雜-從本地到前後臺

首先,我們先來看本地如何生成圖片驗證碼的,再來寫輸出到網頁的驗證碼如何實現。

先來看最簡單的—實現的功能是,將一個字串變成圖片寫入到檔案中

實現程式碼:

package cn.hncu.img;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
//該類包含一些用來查詢 ImageReader 和 ImageWriter 以及執行簡單編碼和解碼的靜態便捷方法。 
import org.junit.Test; public class ImgDemo { //學習如何把一個字串變成圖片寫到一個檔案 @Test public void ImgDemo1() throws FileNotFoundException, IOException{ BufferedImage img = new BufferedImage(60, 30, BufferedImage.TYPE_INT_RGB); // 表示一個影象,它具有合成整數畫素的 8 位 RGB 顏色分量。 Graphics g = img.getGraphics(); g.drawString("Hello"
,10,20); //使用此圖形上下文的當前字型和顏色繪製由指定 string 給定的文字。最左側字元的基線位於此圖形上下文座標系的 (x, y) 位置處。 g.dispose();////類似於流中的close()帶動flush()---把資料刷到img物件當中 //釋放此圖形的上下文以及它使用的所有系統資源。呼叫 dispose 之後,就不能再使用 Graphics 物件。 ImageIO.write(img, "JPG", new FileOutputStream("img/a.jpg")); //使用支援給定格式的任意 ImageWriter 將一個影象寫入 File。
} }

結果:

上面那個很簡單,對不對,我們看到的驗證碼都不是這樣的,那好,我們給它加點干擾線,背景色,字元和y座標隨機生成。

有干擾線、背景色的驗證碼-寫入檔案

演示程式碼:

package cn.hncu.img;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;
//該類包含一些用來查詢 ImageReader 和 ImageWriter 以及執行簡單編碼和解碼的靜態便捷方法。 

import org.junit.Test;

public class ImgDemo {
    //把上面的字串改成我們平時用的驗證碼---生成幾個隨機數字,有背景色和干擾線
    @Test
    public void ImgDemo2() throws FileNotFoundException, IOException{
        int width = 80;
        int height= 40;
        int lines = 10;
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        Graphics g = img.getGraphics();

        //設定背景色
        g.setColor(Color.white);
        g.fillRect(0, 0, width, height);//畫背景
        //填充指定的矩形。使用圖形上下文的當前顏色填充該矩形

        //設定字型
        g.setFont(new Font("宋體", Font.BOLD, 18));

        //隨機數字
        Date d = new Date();
        //System.out.println(d.getTime());
        Random r = new Random(d.getTime());
        for(int i=0;i<4;i++){
            int a = r.nextInt(10);//取10以內的整數[0,9]
            int y = 10+r.nextInt(20); //10~30範圍內的一個整數,作為y座標
            Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
            g.setColor(c);
            g.drawString(""+a, 5+i*width/4, y);
        }
        //干擾線
        for(int i=0;i<lines;i++){
            Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
            g.setColor(c);
            g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
        }

        g.dispose();//類似於流中的close()帶動flush()---把資料刷到img物件當中
        ImageIO.write(img, "JPG", new FileOutputStream("img/b.jpg"));

    }


}

演示結果:

最後來看一個可以旋轉和放縮的驗證碼-寫到圖片本地檔案中

演示程式碼:

package cn.hncu.img;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;
//該類包含一些用來查詢 ImageReader 和 ImageWriter 以及執行簡單編碼和解碼的靜態便捷方法。 

import org.junit.Test;

public class ImgDemo {
    @Test//可以旋轉和放縮的驗證碼
    public void ImgDemo3() throws FileNotFoundException, IOException{
        int width = 80;
        int height = 40;
        int lines = 10;
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = (Graphics2D)img.getGraphics();

        g2d.setFont(new Font("宋體", Font.BOLD, 20));


        Random r = new Random(new Date().getTime());

        //設定背景色
        g2d.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
        g2d.drawRect(0, 0, width, height);//繪製指定矩形的邊框。
        g2d.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
        g2d.fillRect(0, 0, width, height);//填充指定的矩形。

        for(int i=0;i<4;i++){
            String str = ""+r.nextInt(10);

            //處理旋轉
            AffineTransform Tx = new AffineTransform();
            Tx.rotate(Math.random(), 5+i*15, height-5);
            //用弧度測量的旋轉角度,旋轉錨點的 X 座標,旋轉錨點的 Y 座標
            //Tx.scale(0.7+Math.random(), 0.7+Math.random());
            //x座標方向的縮放倍數,y座標方向的縮放倍數
            g2d.setTransform(Tx);
            Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
            g2d.setColor(c);
            g2d.drawString(str, 2+i*width/4, height-13);
        }

        //干擾線
        for(int i=0;i<lines;i++){
            Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
            g2d.setColor(c);
            g2d.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
        }

        g2d.dispose();

        ImageIO.write(img, "JPG", new FileOutputStream("img/c.jpg"));
    }
}

演示結果:

下面就要開始演示前臺的圖片驗證技術了。

前臺的圖片驗證技術

這個專案的結構圖:

index.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <script type="text/javascript">
        function changImg(){
            var img = document.getElementById("servletImg");
            var d = new Date();
            var time = d.getTime();//如果沒有這個
            //下面這一句不會起作用,因為瀏覽器的快取技術,圖片並不會重新整理
            //img.src="/myHelloWeb/servlet/ImageServlet";
            img.src="/myHelloWeb/servlet/ImageServlet?"+time;
            //?號後面的東西是通過get方式傳遞的
        }

    </script>
  </head>

  <body>
    這是我的手動主頁!
    <br/>
    <img id="servletImg" src="/myHelloWeb/servlet/ImageServlet" /><a href="javascript:changImg()">看不清</a>
  </body>
</html>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>ImageServlet</servlet-name>
    <servlet-class>cn.hncu.img.ImageServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ImageServlet</servlet-name>
    <url-pattern>/servlet/ImageServlet</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

ImageServlet.java

package cn.hncu.img;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ImageServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //告訴客戶端,輸出的格式
        response.setContentType("image/jpeg");

        int width = 80;
        int height = 40;
        int lines = 10;
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        Graphics g = img.getGraphics();

        //設定背景色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);

        //設定字型
        g.setFont(new Font("宋體", Font.BOLD, 20));

        //隨機數字
        Random r = new Random(new Date().getTime());
        for(int i=0;i<4;i++){
            int a = r.nextInt(10);
            int y = 10+r.nextInt(20);//10~30範圍內的一個整數,作為y座標

            Color c = new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255));
            g.setColor(c);

            g.drawString(""+a, 5+i*width/4, y);
        }

        //干擾線
        for(int i=0;i<lines;i++){
            Color c = new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255));
            g.setColor(c);
            g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
        }

        g.dispose();//類似於流中的close()帶動flush()---把資料刷到img物件當中

        ImageIO.write(img, "JPG", response.getOutputStream());
    }

}

演示結果:

下面這個是在index.jsp中:
如果是用這句:
img.src=”/myHelloWeb/servlet/ImageServlet”;
大家可以看看響應頭:

再看看用這句的響應頭:
img.src=”/myHelloWeb/servlet/ImageServlet?”+time;

多了個Date響應!
因為時間一直在變,所以每次點看不清,都會再向伺服器請求一次,而不會因為瀏覽器的快取,而不去請求了。

驗證碼就先到這裡結束啦。