Struts2顯示圖片驗證碼

本文分三個步驟介紹驗證碼圖片生成以及與Struts2結合使用。 

Step 1.隨機驗證碼

  一步一步來,要生成驗證碼圖片,首先要有驗證碼,然後才能在畫在圖片上。爲了能夠靈活控制驗證碼,特別編寫了SecurityCode類,它向 外提供隨機字符串。並且可以控制字符串的長度和難度。SecurityCode類中提供的驗證碼分三個難度,易(全數字)、中(數字+小寫英文)、難(數 字+大小寫英文)。難度使用枚舉SecurityCodeLevle表示,避免使用1、2、3這樣沒有明確意義的數字來區分。

  同時,還控制了能否出現重複的字符。爲了能夠方便使用,方法設計爲static。

  SecurityCode類:

import java.util.Arrays;

 

public class SecurityCode {

 

   

    public enum SecurityCodeLevel {

       Simple, Medium, Hard

    };

 

   

    public static String getSecurityCode() {

       return getSecurityCode(4, SecurityCodeLevel.Medium, false);

    }

 

   

    public static String getSecurityCode(int length, SecurityCodeLevel level,

           boolean isCanRepeat) {

       // 隨機抽取len個字符

       int len = length;

       // 字符集合(除去易混淆的數字0、數字1、字母l、字母o、字母O)

       char[] codes = { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',

              'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p',

              'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B',

              'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',

              'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

       // 根據不同的難度截取字符數組

       if (level == SecurityCodeLevel.Simple) {

           codes = Arrays.copyOfRange(codes, 0, 9);

       } else if (level == SecurityCodeLevel.Medium) {

           codes = Arrays.copyOfRange(codes, 0, 33);

       }

       // 字符集合長度

       int n = codes.length;

       // 拋出運行時異常

       if (len > n && isCanRepeat == false) {

          throw new RuntimeException(String.format("調用SecurityCode.getSecurityCode(%1$s,%2$s,%3$s)出現異常,當isCanRepeat%3$s時,傳入參數%1$s不能大於%4$s", len, level, isCanRepeat, n));

       }

 

       // 存放抽取出來的字符

       char[] result = new char[len];

 

       // 判斷能否出現重複的字符

       if (isCanRepeat) {

           for (int i = 0; i < result.length; i++) {

              // 索引 0 and n-1

              int r = (int) (Math.random() * n);

 

              // result中的第i個元素設置爲codes[r]存放的數值

              result[i] = codes[r];

           }

       } else {

           for (int i = 0; i < result.length; i++) {

              // 索引 0 and n-1

              int r = (int) (Math.random() * n);

 

              // result中的第i個元素設置爲codes[r]存放的數值

              result[i] = codes[r];

 

              // 必須確保不會再次抽取到那個字符,因爲所有抽取的字符必須不相同。

              // 因此,這裏用數組中的最後一個字符改寫codes[r],並將n1

              codes[r] = codes[n - 1];

              n--;

           }

       }

       return String.valueOf(result);

    }

}

複製代碼

 

Step 2.圖片

     第一步已經完成,有了上面SecurityCode類提供的驗證碼,就應該考慮怎麼在圖片上寫字符串了。在Java中操作圖片,需要使用 BufferedImage類,它代表內存中的圖片。寫字符串,就需要從圖片BufferedImage上得到繪圖圖面Graphics,然後在圖面上 drawString。

     爲了使驗證碼有一定的干擾性,也繪製了一些噪點。調用Graphics類的drawRect繪製1*1大小的方塊就可以了。

     特別說明一下,由於後面要與Strtus2結合使用,而在Struts2中向前臺返回圖片數據使用的是數據流的形式。所以提供了從圖片向流的轉換方法convertImageToStream。

     SecurityImage類:

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.util.Random;

import com.sun.image.codec.jpeg.ImageFormatException;

import com.sun.image.codec.jpeg.JPEGCodec;

import com.sun.image.codec.jpeg.JPEGImageEncoder;

 

public class SecurityImage {

 

   

    public static BufferedImage createImage(String securityCode) {

 

       // 驗證碼長度

       int codeLength = securityCode.length();

       // 字體大小

       int fSize = 15;

       int fWidth = fSize + 1;

       // 圖片寬度

       int width = codeLength * fWidth + 6;

       // 圖片高度

       int height = fSize * 2 + 1;

 

       // 圖片

       BufferedImage image = new BufferedImage(width, height,

              BufferedImage.TYPE_INT_RGB);

       Graphics g = image.createGraphics();

 

       // 設置背景色

       g.setColor(Color.WHITE);

       // 填充背景

       g.fillRect(0, 0, width, height);

 

       // 設置邊框顏色

       g.setColor(Color.LIGHT_GRAY);

       // 邊框字體樣式

       g.setFont(new Font("Arial", Font.BOLD, height - 2));

       // 繪製邊框

       g.drawRect(0, 0, width - 1, height - 1);

 

       // 繪製噪點

       Random rand = new Random();

       // 設置噪點顏色

       g.setColor(Color.LIGHT_GRAY);

       for (int i = 0; i < codeLength * 6; i++) {

           int x = rand.nextInt(width);

           int y = rand.nextInt(height);

           // 繪製1*1大小的矩形

           g.drawRect(x, y, 1, 1);

       }

 

       // 繪製驗證碼

       int codeY = height - 10;

       // 設置字體顏色和樣式

       g.setColor(new Color(19, 148, 246));

       g.setFont(new Font("Georgia", Font.BOLD, fSize));

       for (int i = 0; i < codeLength; i++) {

           g.drawString(String.valueOf(securityCode.charAt(i)), i * 16 + 5,

                  codeY);

       }

       // 關閉資源

       g.dispose();

 

       return image;

    }

 

   

    public static ByteArrayInputStream getImageAsInputStream(String securityCode) {

 

       BufferedImage image = createImage(securityCode);

       return convertImageToStream(image);

    }

 

   

    private static ByteArrayInputStream convertImageToStream(BufferedImage image) {

 

       ByteArrayInputStream inputStream = null;

       ByteArrayOutputStream bos = new ByteArrayOutputStream();

       JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(bos);

       try {

           jpeg.encode(image);

           byte[] bts = bos.toByteArray();

           inputStream = new ByteArrayInputStream(bts);

       } catch (ImageFormatException e) {

           e.printStackTrace();

       } catch (IOException e) {

           e.printStackTrace();

       }

       return inputStream;

    }

}

 

Step 3.驗證碼與Struts 2結合

  1)Action

  有了上面兩步操作作爲鋪墊,含有驗證碼的圖片就不成問題了,下面就可以使用Struts2的Action向前臺返回圖片數據了。

      SecurityCodeImageAction類:

import java.io.ByteArrayInputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

import com.struts2.utils.SecurityCode;

import com.struts2.utils.SecurityImage;

public class ValidCodeAction extends ActionSupport {

   

    private static final long serialVersionUID = 5633780176793520460L;

       //圖片流

    private ByteArrayInputStream imageStream;

    @Override

    public String execute() throws Exception {

       // TODO Auto-generated method stub

       try {

           HttpServletRequest request = ServletActionContext.getRequest();

            String securityCode = SecurityCode.getSecurityCode();

            imageStream = SecurityImage.getImageAsInputStream(securityCode);

            //放入session

            //session.put("securityCode", securityCode);

            System.out.println("securityCode = " + securityCode);

            request.getSession().setAttribute("securityCode", securityCode);

       } catch (Exception e) {

           e.printStackTrace();

       }

       return SUCCESS;

    }

    public ByteArrayInputStream getImageStream() {

       return imageStream;

    }

    public void setImageStream(ByteArrayInputStream imageStream) {

       this.imageStream = imageStream;

    }

}

  2)Struts.xml

   在 Struts.xml配置文件中,需要配置SecurityCodeImageAction,由於現在返回的是流,就不應該再使用普通的方式了,應該在result上加上type="stream"。

  同時這一項的值,應該與SecurityCodeImageAction中的圖片流名稱一致。

    Struts.xml:

1 <</span>action name="SecurityCodeImageAction" class="securityCodeImageAction"> 2 <</span>resultname="success" type="stream"> 3 <</span>param name="contentType">image/jpeg</</span>param> 4<</span>param name="inputName">imageStream</</span>param> 5 <</span>paramname="bufferSize">2048</</span>param> 6 </</span>result> 7 </</span>action>

 

  3)前臺JSP

  定義一個img元素,將src指向SecurityCodeImageAction就可以了,瀏覽器向Action發送請求,服務器將圖片流返回,圖片就能夠顯示了。

1 <</span>img src="SecurityCodeImageAction" id="Verify" style="cursor:hand;" alt="看不清,換一張"/>

  4)JS

      驗證碼一般都有點擊刷新的功能,這個也容易實現,點擊圖片,重新給圖片的src賦值。但是這時,瀏覽器會有緩存問題,如果瀏覽器發現src中的url不 變,就認爲圖片沒有改變,就會使用緩存中的圖片,而不是重新向服務器請求。解決辦法是在url後面加上一個時間戳,每次點擊時,時間戳都不一樣,瀏覽器就 認爲是新的圖片,然後就發送請求了。

     jQuery:

1 $(function () { 2 //點擊圖片更換驗證碼 3 $("#Verify").click(function(){ 4$(this).attr("src","SecurityCodeImageAction?timestamp="+new Date().getTime()); 5 }); 6 });

   

      JavaScript: 

1 window.οnlοad=function(){ 2 var verifyObj = document.getElementByIdx_x("Verify"); 3verifyObj.οnclick=function(){ 4 this.src="SecurityCodeImageAction?timestamp="+newDate().getTime(); 5 }; 6 }

 

  5)效果

     生成的驗證碼圖片如下所示,淺藍色的字體,淺灰色的噪點。

   

                圖:驗證碼

 

   結束: 經過上面的三個步驟,Struts2 結合驗證碼的例子就介紹完了。


自己總結:

關於驗證碼顯示的原理:

一:驗證碼顯示
1. 後臺產生一個已經生成好的驗證碼圖片使用BufferImage對象可以實現
     這一部分當產生驗證碼圖片的時候就會將產生的隨機數進行保存到Session中
2. 將產生的驗證碼圖片對象進行返回,當然在返回的時候我們是通過Stream流的方式進行返回的
3. 頁面使用image標籤,指定src爲返回驗證碼圖片的的Action就行了
4. 點擊刷新驗證碼,其實就是用請求的一遍返回驗證碼圖片的Action,由於緩存的原因,要再請求的地址下進行加一個隨機數,這樣就會是進行新的請求了

二:驗證碼後臺驗證
1. 將用於輸入的驗證碼,和Session中保存的驗證碼的隨機數進行對比,即可判斷驗證碼是否正確了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章