Struts2中驗證碼的生成和使用
第一步生產字符串:
package com.yancode.demo;
import java.util.Arrays;
/
一步一步來,要生成驗證碼圖片,首先要有驗證碼,然后才能在畫在圖片上。為了能夠靈活控制驗證碼,
特別編寫了SecurityCode類,它向外提供隨機字符串。并且可以控制字符串的長度和難度。
SecurityCode類中提供的驗證碼分三個難度,易(全數字)、中(數字+小寫英文)、難(數字+大小寫英文)。
難度使用枚舉SecurityCodeLevle表示,避免使用1、2、3這樣沒有明確意義的數字來區分。
同時,還控制了能否出現重復的字符。為了能夠方便使用,方法設計為static。
*/
public class SecurityCode {
/**
- 驗證碼難度級別,Simple只包含數字,Medium包含數字和小寫英文,Hard包含數字和大小寫英文
/
public enum SecurityCodeLevel {Simple,Medium,Hard};
/**
產生默認驗證碼,4位中等難度
@return String 驗證碼
/
public static String getSecurityCode(){
return getSecurityCode(4,SecurityCodeLevel.Medium,false);
}
/
產生長度和難度任意的驗證碼
@param length 長度
@param level 難度級別
@param isCanRepeat 是否能夠出現重復的字符,如果為true,則可能出現 5578這樣包含兩個5,如果為false,則不可能出現這種情況
@return String 驗證碼
/
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;
//拋出運行時異常,這里的len為4
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],并將n減1
codes[r]=codes[n-1];
n--;
}
}
return String.valueOf(result);
}
}</span></p>
第二步,繪制圖片
package com.yancode.demo;
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 javax.imageio.ImageIO;
/ 第一步已經完成,有了上面SecurityCode類提供的驗證碼,就應該考慮怎么在圖片上寫字符串了。
在Java中操作圖片,需要使用BufferedImage類,它代表內存中的圖片。
寫字符串,就需要從圖片BufferedImage上得到繪圖圖面Graphics,然后在圖面上drawString。
為了使驗證碼有一定的干擾性,也繪制了一些噪點。調用Graphics類的drawRect繪制11大小的方塊就可以了。
特別說明一下,由于后面要與Strtus2結合使用,
而在Struts2中向前臺返回圖片數據使用的是數據流的形式。所以提供了從圖片向流的轉換方法
*/
public class SecurityImage {
/
生成驗證碼圖片
@param securityCode 驗證碼字符
@return BufferedImage 圖片
/
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 -5;
//圖片
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 7;i++){
int x = rand.nextInt(width);
int y = rand.nextInt(height);
g.setColor(new Color(rand.nextInt(255),
rand.nextInt(255),rand.nextInt(255)));
//繪制11大小的矩形
g.drawRect(x, y, 1, 1);
//g.setColor(Color.LIGHT_GRAY);
}
//繪制驗證碼
int codeY = height - 10;
//設置字體顏色和樣式
//g.setColor(new Color(19,148,246));
g.setFont(new Font("Georgia", Font.BOLD, fSize+2));
for(int i = 0; i < codeLength;i++){
g.setColor(new Color(rand.nextInt(255),
rand.nextInt(255),rand.nextInt(255)));
g.drawString(String.valueOf(securityCode.charAt(i)),
i 16 + 5, codeY);
}
//關閉資源
g.dispose();
return image;
}
/**
返回驗證碼圖片的流格式
@param securityCode 驗證碼
@return ByteArrayInputStream 圖片流
/
public static ByteArrayInputStream getImageAsInputStream(String securityCode){
BufferedImage image = createImage(securityCode);
return convertImageToStream(image);
}
/**
將BufferedImage轉換成ByteArrayInputStream
@param image 圖片
@return ByteArrayInputStream 流
/
private static ByteArrayInputStream convertImageToStream(BufferedImage image){
ByteArrayInputStream inputStream = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte [] bimage=null;
try {
ImageIO.write(image, "jpeg", bos);
bimage=bos.toByteArray();
inputStream = new ByteArrayInputStream(bimage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//JPEGImageEncoder
/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;*/
//返回輸入流
return inputStream;
}
}
</span></p>
第三步,生成驗證碼的action
package com.yancode.demo;
import java.io.ByteArrayInputStream;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class SecurityCodeImageAction extends ActionSupport {
//圖片流
private ByteArrayInputStream imageStream;
private String timestamp;//得到時間戳
public ByteArrayInputStream getImageStream() {
return imageStream;
}
public void setImageStream(ByteArrayInputStream imageStream) {
this.imageStream = imageStream;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
//System.out.println("時間戳timestamp:"+this.timestamp);
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
//如果開啟Hard模式,可以不區分大小寫
//String securityCode = SecurityCode.getSecurityCode(4,SecurityCodeLevel.Hard, false).toLowerCase();
//獲取默認難度和長度的驗證碼
String securityCode = SecurityCode.getSecurityCode();
imageStream = SecurityImage.getImageAsInputStream(securityCode);
System.out.println("code="+securityCode);
//放入session中
Map session=ActionContext.getContext().getSession();
session.put("SESSION_SECURITY_CODE", securityCode);
return SUCCESS;
}
}
第四步,在struts.xml文件中配置驗證碼的action
<!--驗證碼的action -->
<action name="SecurityCodeImageAction"
class="com.yancode.demo.SecurityCodeImageAction">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="bufferSize">2048</param>
</result>
</action>
第五步,在jsp中使用生成的驗證碼
<script type="text/javascript">
window.onload=function(){
document.getElementById("img").onclick=function(){
this.src="SecurityCodeImageAction?timestamp="+new Date().getTime();
};
};
</script>
<td>驗證碼:</td>
<td>
<input type="text" name="securityCode"/>
<img src="SecurityCodeImageAction" id="img" style="cursor:hand;" alt="看不清,換一張"/>
<span style="color:red;" id="simg">
<s:property value="#request.error2"></s:property>
</span>
<!-- <a href="javascript:;" onclick="document.getElementById('img').
src='checkcode?'+new Date().getTime();"><span style="font-size:12px;">看不清,換一張</span></a> -->
</td>
注意,生成驗證碼的時候使用了時間戳,目的是為了,區別不同的提交,生產不同驗證碼
來自:http://blog.csdn.net/j903829182/article/details/36695697