圖形驗證碼的java通用類

來源:互聯網
上載者:User

在應用程式中為防止系統被攻擊程式自動訪問,通常提供一個人眼容易識別,但程式很難識別的圖形,圖形內是隨機產生的一些字元。為防止被攻擊程式自動識別,字元通常會在位置和顏色上作隨機處理。

為便於使用,本人用 java實現了一個產生隨機字元圖片的通用類,封裝了產生過程的複雜性,能非常方便的使用。

實作類別類名為RandomGraphic,它由一個靜態Factory 方法createInstance(int charCount)來建立對象執行個體,charCount指定圖片中字元的個數,最多16個。

提供了兩個方法來產生隨機圖片,一個方法String drawNumber(String graphicFormat,OutputStream out) 產生的圖片中都是隨機數字,由0-9組成。

另一個方法String drawAlpha(String graphicFormat,OutputStream out)產生的圖片中都是隨機字母,由a-z組成,產生的字元個數在Factory 方法中指定。將數字和圖片分開是因為有些數字和字母人眼看上去很難區分,反而影響使用者輸入。

graphicFormat為產生圖片格式,取常量值GRAPHIC_JPEG 或 GRAPHIC_PNG

out用來輸出產生的圖片檔案內容,可以是一個檔案,或servlet中輸出到用戶端的流,以便於在頁面顯示。

下面給出原碼和在servlet中的範例程式碼。

package net;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 產生隨機數字或字母串,以映像方式顯示,用於人工識別,使程式很難識別。
 *  減小系統被程式自動攻擊的可能性。
 *  產生的圖形顏色由紅、黑、藍、紫4中隨機組合而成,數字或字母垂直方向位置在
 *  一定範圍內也是隨機的,減少被程式自動識別的幾率。
 *  由於數位0,1,2易和字母的o,l,z混淆,使人眼難以識別,因此不產生數字
 *  和字母的混合串。
 *  產生的串字母統一用小寫,串的最大長度為16。
 *
 * @version
 *  @Since
 * @See Also
 * @author lchen
 * Create Date 2005-12-16
 *
 */

public class RandomGraphic {
 //字元的高度和寬度,單位為像素
 private int wordHeight = 10;
 private int wordWidth = 15;
 //字元大小
 private int fontSize = 16;
 //最大字串個數
 private  static final int MAX_CHARCOUNT = 16;
 
 //垂直方向起始位置
 private final int initypos = 5;
 
 
 //要產生的字元個數,由Factory 方法得到
 private int charCount = 0;
 
 
 //顏色數組,繪製字串時隨機播放一個
 private static final Color[] CHAR_COLOR = {Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA};
 
 //隨機數產生器
 private Random r = new Random();
 
 /**
  * 產生映像的格式常量,JPEG格式,產生為檔案時副檔名為.jpg;
  * 輸出到頁面時需要設定MIME type 為image/jpeg
  */
 public static String GRAPHIC_JPEG = "JPEG";
 /**
  * 產生映像的格式常量,PNG格式,產生為檔案時副檔名為.png;
  * 輸出到頁面時需要設定MIME type 為image/png
  */
 public static String GRAPHIC_PNG = "PNG";
 
 
 
 //用Factory 方法建立對象
 protected RandomGraphic(int charCount){
  this.charCount = charCount;
 }
 
 
 /**
  * 建立對象的Factory 方法
  * @param charCount  要產生的字元個數,個數在1到16之間
  *
  * Return 返回RandomGraphic對象執行個體
  * @throws Exception  參數charCount錯誤時拋出
  */
 public static RandomGraphic createInstance(int charCount) throws Exception{
  if (charCount < 1 || charCount > MAX_CHARCOUNT){
   throw new Exception("Invalid parameter charCount,charCount should between in 1 and 16");
  }
  return new RandomGraphic(charCount);
 }
 
 
 /**
  * 隨機產生一個數字串,並以映像方式繪製,繪製結果輸出到流out中
  *
  * @param graphicFormat 設定產生的映像格式,值為GRAPHIC_JPEG或GRAPHIC_PNG
  * @param out  映像結果輸出資料流
  * @return   隨機產生的串的值
  * @throws IOException
  */
 public String drawNumber(String graphicFormat,OutputStream out) throws IOException{
//  隨機產生的串的值
  String charValue = "";
  charValue = randNumber();
  return draw(charValue,graphicFormat,out);
  
 }

 /**
  * 隨機產生一個字母串,並以映像方式繪製,繪製結果輸出到流out中
  *
  * @param graphicFormat 設定產生的映像格式,值為GRAPHIC_JPEG或GRAPHIC_PNG
  * @param out  映像結果輸出資料流
  * @return   隨機產生的串的值
  * @throws IOException
  */
 public String drawAlpha(String graphicFormat,OutputStream out) throws IOException{
//  隨機產生的串的值
  String charValue = "";
  charValue = randAlpha();
  return draw(charValue,graphicFormat,out);
  
 }

 
 
 
 
 /**
  * 以映像方式繪製字串,繪製結果輸出到流out中
  * @param charValue  要繪製的字串
  * @param graphicFormat 設定產生的映像格式,值為GRAPHIC_JPEG或GRAPHIC_PNG
  * @param out  映像結果輸出資料流
  * @return   隨機產生的串的值
  * @throws IOException
  */
 protected String draw(String charValue,String graphicFormat,OutputStream out) throws IOException{
  
  //計算映像的寬度和高度
  int w = (charCount+2) * wordWidth;
  int h = wordHeight * 3;

  //建立記憶體配置圖像區
  BufferedImage bi = new BufferedImage(w,h,BufferedImage.TYPE_3BYTE_BGR);
  Graphics2D g = bi.createGraphics();
  
  //設定背景色
  Color backColor = Color.WHITE;
  g.setBackground(backColor);
  g.fillRect(0,0,w,h);
  
  //設定font
  g.setFont(new Font(null,Font.BOLD,fontSize));
  //繪製charValue,每個字元顏色隨機
  for(int i = 0; i < charCount; i++){
   String c = charValue.substring(i,i+1);
   Color color =  CHAR_COLOR[randomInt(0,CHAR_COLOR.length)];
   g.setColor(color);
   int xpos = (i+1) * wordWidth;
   //垂直方向上隨機
   int ypos = randomInt(initypos+wordHeight,initypos+wordHeight*2);
   g.drawString(c,xpos,ypos);
  }
  g.dispose();
  bi.flush();
  // 輸出到流
  ImageIO.write(bi,graphicFormat,out);
  
  return charValue;
 }
 
 
 
 
 protected String randNumber(){
  String charValue = "";
  //產生隨機數字串
  for (int i = 0; i < charCount; i++){
   charValue += String.valueOf(randomInt(0,10));
  }
  return charValue;
 }
 
 
 private String randAlpha(){
  String charValue = "";
  //產生隨機字母串
  for (int i = 0; i < charCount; i++){
   char c = (char) (randomInt(0,26)+'a');
   charValue += String.valueOf(c);
  }
  return charValue;
 }
 
 
 
 /**
  * 返回[from,to)之間的一個隨機整數
  *
  * @param from 起始值
  * @param to 結束值
  * @return  [from,to)之間的一個隨機整數
  */
 protected int randomInt(int from,int to){
  //Random r = new Random();
  return from+r.nextInt(to-from);
 }
 
 
 
 /**
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
 
  System.out.println(RandomGraphic.createInstance(5).drawAlpha(RandomGraphic.GRAPHIC_PNG,new FileOutputStream("c:/myimg.png")));

  
 }
 
}

RandomGraphic類原代碼結束

在servlet中使用該類,將圖片輸出到用戶端,在頁面上就可顯示隨機圖片

package net;

import java.io.IOException;

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

public class RandImage extends HttpServlet {

 public RandImage() {
  super();
 
 }

 
 
 protected void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException,ServletException{

//設定輸出內容為映像,格式為jpeg
  res.setContentType("image/jpg");
  try {
//將內容輸出到響應用戶端對象的輸出資料流中,產生的圖片中包含6個字元

   String v = RandomGraphic.createInstance(6).drawAlpha(RandomGraphic.GRAPHIC_JPEG,res.getOutputStream());
//將字串的值保留在session中,便於和使用者手工輸入的驗證碼比較,比較部分不是本文討論重點,故略

   req.getSession().setAttribute("rv",v);
  } catch (Exception e) {
  
   e.printStackTrace();
  }
 
 }

 
}

需要在web.xml中配置該servlet

 <servlet>
   <servlet-name>RandImage</servlet-name>
   <servlet-class>net.RandImage</servlet-class>
  </servlet>
  
  <servlet-mapping>
   <servlet-name>RandImage</servlet-name>
   <url-pattern>/RandImage</url-pattern>
  </servlet-mapping>

然後在一個頁面中用下面的代碼來顯示圖片

<html>
<body>

驗證碼: <image src="RandImage" />

</body>
</html>

要增加圖片的識別難度,還可以在draw方法中對圖象進行一定程度變形迴旋轉處理,或者在圖片中添加隨機幹擾線條,但要保證用人眼能比較容易識別。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.