???? 在web系統(tǒng)中,驗(yàn)證碼的應(yīng)用基本上隨處可見.驗(yàn)證碼可以防止他人惡意攻擊和垃圾注冊(cè),可以說(shuō)已成了web開發(fā)中必不可少的環(huán)節(jié).遺憾的是,驗(yàn)證碼在jsp,jsf的組件庫(kù), 至少是一些標(biāo)準(zhǔn)的組件庫(kù)中并沒有出現(xiàn).本文分別介紹如何在jsp和jsf中使用驗(yàn)證碼和我的一些小經(jīng)驗(yàn),呵呵.
???? 在jsp中,我們使用apache的taglibs-image(http://jakarta.apache.org/taglibs/sandbox/doc/image-doc/intro.html),可以簡(jiǎn)便的配置自己的驗(yàn)證碼.而由于在jsf中,無(wú)法和其他jsp標(biāo)簽庫(kù)混用(至少不能和上述標(biāo)簽庫(kù)混用),我們則用Java2D自己繪制驗(yàn)證碼圖.
?
1. 在jsp中使用taglibs-image部署驗(yàn)證碼
??? taglibs-image可以通過標(biāo)簽自動(dòng)將一段文字和背景圖片生成新的圖片,文字的布局,顏色,字體等等都可以自我定制,因此拿來(lái)做驗(yàn)證碼是非常的簡(jiǎn)單
???
<%
@?page?contentType
=
"
text/html;?charset=iso-8859-1
"
?language
=
"
java
"
?
import
=
"
java.sql.*
"
?errorPage
=
""
?
%>
<%
@?taglib?uri
=
"
http://jakarta.apache.org/taglibs/image-1.0
"
?prefix
=
"
img
"
?
%>
<
html
>
<
head
>
<
title
>
Image?Tag?examples
</
title
>
<
meta?http
-
equiv
=
"
Content-Type
"
?content
=
"
text/html;?charset=iso-8859-1
"
>
</
head
>
<
body
>
td
?
<%
??
int
?num?
=
?(
int
)?java.lang.Math.round(java.lang.Math.random()?
*
?
8999
);
??String?sRand?
=
?
""
?
+
?(
1000
?
+
num);
??session.setAttribute(
"
userInfo.authcode
"
,sRand);
?
%>
<
img:image?src
=
"
/images/code.gif
"
?refresh
=
"
true
"
>
??
<
img:text?text
=
"
<%=sRand.substring(0,1)%>
"
?x
=
"
18%
"
?
????????y
=
"
25%
"
?
????????font
=
"
Arial
"
?
????????bold
=
"
true
"
?
????????size
=
"
16
"
?
????????
/>
??
<
img:text?text
=
"
<%=sRand.substring(1,2)%>
"
?x
=
"
36%
"
?
????????y
=
"
15%
"
?
????????font
=
"
Times?New?Roman
"
?
????????bold
=
"
true
"
?
????????size
=
"
20
"
?
????????
/>
??
<
img:text?text
=
"
<%=sRand.substring(2,3)%>
"
?x
=
"
60%
"
?
????????y
=
"
20%
"
?
????????font
=
"
Arial
"
?
????????bold
=
"
true
"
?
????????size
=
"
18
"
?
????????
/>
??
<
img:text?text
=
"
<%=sRand.substring(3,4)%>
"
?x
=
"
77%
"
?
????????y
=
"
30%
"
?
????????font
=
"
Times?New?Roman
"
?
????????bold
=
"
true
"
?
????????size
=
"
14
"
?
????????
/>
</
img:image
>
</
body
>
</
html
>
?? 其中最開始百分號(hào)內(nèi)的java代碼是為了生成驗(yàn)證碼,然后保存在session中.同時(shí)驗(yàn)證碼和背景圖片生成新的驗(yàn)證圖.用戶根據(jù)此圖輸入驗(yàn)證碼.在服務(wù)器方,只用把用戶提交表單中的驗(yàn)證碼內(nèi)容取出和session中保存的驗(yàn)證碼對(duì)比,就可以判斷正確性咯
?????????????

2.JSF
?? jsf中無(wú)法使用上述標(biāo)簽(會(huì)無(wú)法渲染出來(lái)), 因此,我們自己實(shí)現(xiàn)一個(gè)生成驗(yàn)證圖的類,再通過jsf的<h:graphicImage>標(biāo)簽得以顯示.
? 生成驗(yàn)證碼的java類如下:
package?org.myibm.beans;

import?java.awt.Color;
import?java.awt.Font;
import?java.awt.Graphics;
import?java.awt.image.BufferedImage;
import?java.io.File;
import?java.io.IOException;
import?java.util.Random;

import?javax.imageio.ImageIO;


/**?*//**
?*?用來(lái)自動(dòng)生成驗(yàn)證圖和驗(yàn)證碼,驗(yàn)證圖是背景圖加上干擾點(diǎn)加上驗(yàn)證碼
?*?
?*?@author?td
?*?
?*/

public?final?class?CodeImageGenerator?
{
????private?final?static?int?DEF_WIDTH?=?60;

????private?final?static?int?DEF_HEIGHT?=?20;

????private?final?static?String?BASE_PATH?=?"validate-images";


????/**?*//**
?????*?驗(yàn)證碼
?????*/
????private?String?code?=?"";


????/**?*//**
?????*?驗(yàn)證圖的地址
?????*/
????private?String?path;

????private?int?width;

????private?int?height;

????private?BufferedImage?image;


????/**?*//**
?????*?驗(yàn)證圖對(duì)應(yīng)的File對(duì)象
?????*/
????private?File?target;


????public?CodeImageGenerator()?
{
????????this(DEF_WIDTH,?DEF_HEIGHT);
????}


????public?CodeImageGenerator(int?width,?int?height)?
{
????????this.width?=?width;
????????this.height?=?height;
????????generateCodeImage();
????}


????/**?*//**
?????*?生成驗(yàn)證碼和驗(yàn)證圖
?????*
?????*/

????private?void?generateCodeImage()?
{
????????//?create?the?image
????????image?=?new?BufferedImage(width,?height,?BufferedImage.TYPE_INT_RGB);
????????Graphics?g?=?image.getGraphics();
????????//?set?the?background?color
????????g.setColor(new?Color(0xDCDCDC));
????????g.fillRect(0,?0,?width,?height);
????????//?draw?the?border
????????g.setColor(Color.black);
????????g.drawRect(0,?0,?width?-?1,?height?-?1);
????????//?set?the?font
????????g.setFont(new?Font("Times?New?Roman",?Font.PLAIN,?18));
????????//?create?a?random?instance?to?generate?the?codes
????????Random?random?=?new?Random();
????????//?make?some?confusion

????????for?(int?i?=?0;?i?<?50;?i++)?
{
????????????int?x?=?random.nextInt(width);
????????????int?y?=?random.nextInt(height);
????????????g.drawOval(x,?y,?0,?0);
????????}?//?generate?a?random?code

????????for?(int?i?=?0;?i?<?4;?i++)?
{
????????????String?rand?=?String.valueOf(random.nextInt(10));
????????????code?+=?rand;
????????????g.drawString(rand,?13?*?i?+?6,?16);
????????}
????????g.dispose();

????????try?
{
????????????File?dir?=?new?File("K:/Tomcat?5.5/webapps/nirvana/validate-images");
????????????String?s?=?new?Double(Math.random()?*?995596390219L).toString();
????????????File?imgFile?=?new?File(dir,?s?+?".jpeg");
????????????if?(!imgFile.exists())
????????????????imgFile.createNewFile();
????????????target?=?imgFile;
????????????ImageIO.write(image,?"JPEG",?imgFile);
????????????path?=?"/"?+?BASE_PATH?+?"/"?+?s?+?".jpeg";
????????????System.err.println(path);

????????}?catch?(IOException?e)?
{
????????????//?TODO?Auto-generated?catch?block
????????????e.printStackTrace();
????????}
????}


????public?BufferedImage?getImage()?
{
????????return?image;
????}


????public?String?getCode()?
{
????????if?(code?==?null)
????????????code?=?"";
????????return?code;
????}


????public?static?void?main(String[]?args)?throws?Exception?
{
????????//?File?imgFile?=?new?File("codeImage.jpeg");
????????//?CodeImageGenerator?cig?=?new?CodeImageGenerator();
????????//?ImageIO.write(cig.getImage(),?"JPEG",?imgFile);
????}


????public?String?getPath()?
{
????????return?path;
????}


????public?void?setPath(String?path)?
{
????????this.path?=?path;
????}


????/**?*//**
?????*?當(dāng)這個(gè)對(duì)象被回收時(shí),同時(shí)銷毀其對(duì)應(yīng)的驗(yàn)證圖
?????*/
????@Override

????protected?void?finalize()?throws?Throwable?
{
????????//?TODO?Auto-generated?method?stub
????????//?System.err.println("finalize");
????????if?(target.exists())
????????????target.delete();
????????super.finalize();
????}


????public?File?getTarget()?
{
????????return?target;
????}


????public?void?setTarget(File?target)?
{
????????this.target?=?target;
????}
}

要說(shuō)明幾點(diǎn)的事,這個(gè)類會(huì)把生成的驗(yàn)證圖放在制定文件夾下,未免得文件越來(lái)越多,應(yīng)該當(dāng)驗(yàn)證圖不再使用時(shí)將之刪除.所以此類重寫了Object的finalize()方法,當(dāng)此類被垃圾回收器回收時(shí),同時(shí)也刪除其對(duì)應(yīng)的驗(yàn)證圖.
這樣,就可以利用java的垃圾回收器輕松為我們刪除不用的文件.
另外,在頁(yè)面對(duì)應(yīng)的managed-bean中,我們還要添加如何得到驗(yàn)證碼和驗(yàn)證圖的方法
private?CodeImageGenerator?validator;
????
????private?String?validate_code;
????

????public?CodeImageGenerator?getValidator()?
{

????????if(validator!=null)
{
????????????validator.getTarget().delete();
????????????validator=null;
????????}
????????validator=new?CodeImageGenerator();
????????System.out.println(validator.getCode());
????????return?validator;
????}


????public?void?setValidator(CodeImageGenerator?validator)?
{
????????this.validator?=?validator;
????}其中validate-code對(duì)應(yīng)用戶輸入的驗(yàn)證碼信息
因?yàn)槊看嗡⑿马?yè)面都需要得到不同的驗(yàn)證碼,所以在getValidator()方法時(shí),每次需要返回一個(gè)新的CodeImageGenerator.同時(shí),你可能等不及垃圾回收器幫你刪除文件,因此,可以在這里同時(shí)刪除老的驗(yàn)證圖.
另外,在注冊(cè)時(shí)我們還需要做一下判斷:

public?String?register()?
{
????????//?System.out.println("haha");

????????if(!validator.getCode().equals(validate_code))
{
????????????FacesMessage?message?=?new?FacesMessage(
????????????????????FacesMessage.SEVERITY_ERROR,?"驗(yàn)證碼錯(cuò)誤",
????????????????????"驗(yàn)證碼錯(cuò)誤");
????????????FacesContext.getCurrentInstance().addMessage(null,?message);
????????????FacesContext?fcg?=?FacesContext.getCurrentInstance();
????????????((LoginBean)?fcg.getApplication().getVariableResolver()
????????????????????.resolveVariable(fcg,?"loginBean")).setReg(true);
????????????System.out.println(validator.getCode());
????????????System.out.println(validate_code);
????????????return?null;
????????}



..
}最后,我們需要在頁(yè)面中添加對(duì)應(yīng)的標(biāo)簽
????????????????????????<h:outputText?value="驗(yàn)證碼(*):"?styleClass="label"></h:outputText>
????????????????????????<h:message?for="vcode"?styleClass="error"></h:message>

????????????????????????<h:inputText?id="vcode"?required="true"?value="#{myPageBean.validate_code}"></h:inputText>
????????????????????????<h:graphicImage?value="#{myPageBean.validator.path}"></h:graphicImage>

這樣, 我們就在jsf中實(shí)現(xiàn)了自己的驗(yàn)證碼部署^_^