天天看點

自己動手實作一次性圖檔驗證碼

  以前碰到注冊登入需要圖形驗證碼的時候,一般都是到網絡上直接淘一個,也不讀代碼,直接就用了,今天靜下來,從頭到尾讀了一遍代碼,自己又照着寫了一遍,加上了完整的注釋,下面介紹步驟,首先建立一個web項目,src建立一個class類:

1 import java.awt.BasicStroke;
  2 import java.awt.Color;
  3 import java.awt.Font;
  4 import java.awt.Graphics;
  5 import java.awt.Graphics2D;
  6 import java.awt.image.BufferedImage;
  7 import java.io.FileNotFoundException;
  8 import java.io.FileOutputStream;
  9 import java.io.IOException;
 10 import java.io.OutputStream;
 11 import java.util.Random;
 12 
 13 import javax.imageio.ImageIO;
 14 
 15 public class VCode {
 16 
 17     private int w;// 圖檔寬
 18     private int h;// 圖檔高
 19     private Color bgColor = new Color(240, 240, 240);// 背景色
 20     private Random random = new Random();// 随機數對象
 21     // 設定字型範圍
 22     private String[] fontNames = { "宋體", "華文楷體", "黑體", "華文新魏", "華文隸書", "微軟雅黑",
 23             "楷體" };
 24     //設定字型樣式範圍
 25     private int[] fontstyles = { 0, 1, 2, 3 };
 26     //設定字号範圍
 27     private int[] fontSizes={24,25,26,27,28};
 28     //設定所有字元串範圍
 29     private String codes="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
 30     
 31     
 32     //無參構造方法
 33     public VCode() {
 34     }
 35     
 36     //帶寬和高的構造函數 
 37     public VCode(int w, int h) {
 38         super();
 39         this.w = w;
 40         this.h = h;
 41     }
 42 
 43 
 44     // 傳回一張背景圖檔
 45     private BufferedImage createImage() {
 46         /**
 47          * 1:建立圖檔 2:設定背景色
 48          */
 49         // 1:建立圖檔
 50         BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
 51         // 2:設定背景色
 52         Graphics g = img.getGraphics();
 53         g.setColor(bgColor);
 54         g.fillRect(0, 0, w, h);
 55 
 56         return img;
 57     }
 58 
 59     // 随機傳回字型顔色
 60     private Color randomColor() {
 61         int r = random.nextInt(256);
 62         int g = random.nextInt(256);
 63         int b = random.nextInt(256);
 64         return new Color(r, g, b);
 65     }
 66 
 67     // 随機傳回字型樣式
 68     private Font randomFont() {
 69         //随機生成字型下标,随機從給定的範圍内擷取一個字型
 70         int index=random.nextInt(fontNames.length);
 71         String name=fontNames[index];
 72 
 73         //随機生成字型樣式下表,随機從給定的傳回内擷取到一個字型樣式
 74         index=random.nextInt(fontstyles.length);
 75         int style = fontstyles[index];
 76 
 77         //随機生成字型大小下标,随機從給定的傳回内擷取到一個字型大小
 78         index=random.nextInt(fontSizes.length);
 79         int size = fontSizes[index];
 80 
 81         return new Font(name, style, size);
 82     }
 83 
 84     // 随機傳回字型内容
 85     private String randomChar() {
 86         int index=random.nextInt(codes.length());
 87         
 88         return codes.charAt(index)+"";
 89     }
 90 
 91     //随即傳回幾條幹擾線
 92     private void getLine(BufferedImage img){
 93         //設定幹擾線的寬度為1.5倍寬,随機畫五條
 94         Graphics2D g=(Graphics2D)img.getGraphics();
 95         g.setColor(Color.BLACK);
 96         g.setStroke(new BasicStroke(1.5f));
 97         for(int i=0;i<5;i++){
 98             int x1=random.nextInt(w);
 99             int y1=random.nextInt(h);
100             int x2=random.nextInt(w);
101             int y2=random.nextInt(h);
102             g.drawLine(x1, y1, x2, y2);
103             
104         }
105         
106     }
107     // 使用者調用該方法擷取圖檔
108     public BufferedImage getImage() {
109         /**
110          * 随機生成字元,字元範圍0-9A-Za-z, 設定字型,字号,是否粗體 都是随機 字元的顔色
111          */
112         BufferedImage img = createImage();
113 
114         this.getLine(img);
115         // 擷取畫筆
116         Graphics g = img.getGraphics();
117         // 畫内容
118         for (int i = 0; i < 4; i++) {
119             g.setColor(this.randomColor());// 擷取随機顔色
120             g.setFont(this.randomFont());// 擷取随機字型
121             g.drawString(this.randomChar(), w / 4 * i, h - 5);// 擷取字元串随機内容
122         }
123         return img;
124     }
125     
126     //使用者調用該方法儲存圖檔到本地
127     public void saveImage(BufferedImage img,OutputStream ous){
128         
129         try {
130             ImageIO.write(img, "JPEG", ous);
131         } catch (FileNotFoundException e) {
132             e.printStackTrace();
133         } catch (IOException e) {
134             e.printStackTrace();
135         }
136     }
137 }      

接下來建立一個servlet:

1 package com.wang.verifySode;
 2 
 3 import java.awt.Color;
 4 import java.awt.Font;
 5 import java.awt.Graphics;
 6 import java.awt.image.BufferedImage;
 7 import java.io.FileOutputStream;
 8 import java.io.IOException;
 9 import java.io.PrintWriter;
10 
11 import javax.imageio.ImageIO;
12 import javax.servlet.ServletException;
13 import javax.servlet.http.HttpServlet;
14 import javax.servlet.http.HttpServletRequest;
15 import javax.servlet.http.HttpServletResponse;
16 
17 public class BServlet extends HttpServlet {
18 
19     public void doGet(HttpServletRequest request, HttpServletResponse response)
20             throws ServletException, IOException {
21         
22         VCode v=new VCode(70, 35);
23         BufferedImage img=v.getImage();
24         v.saveImage(img, response.getOutputStream());
25         
26     }
27 
28 }      

在你需要加驗證碼的地方,如注冊頁面中适當地方加入:

<img id="img" alt="" src="/tools/BServlet"><a href="javascript:changeNext()">看不清楚,換一張</a>      

這裡需要說一下,因為驗證碼有一個"看不清楚 換一張"的功能,是以需要加一個javascript函數,如下:

<script type="text/javascript">
    function changeNext(){
        var a=document.getElementById("img");
        a.src="/tools/BServlet?a="+new Date().getTime();
    }
</script>      

為了避免浏覽器的圖檔緩存問題而導緻點選後無法随機下一張圖檔,這裡在超連結後面加一個永不重複的參數,可以避免這個問題,見上面代碼.

配置項目,開浏覽器,運作,完美~