jpatchca生成圖片

JCaptcha 簡介

CAPTCHA 全稱 Completely Automated Public Turing Test to Tell Computers and Humans Apart哈打,最早作為卡內基梅隆大學的一個科研項目,用于生成一個人類容易通過而計算機難以通過的測試僵芹,目前廣泛應用于網(wǎng)絡應用档押,用于阻止機器人發(fā)布垃圾信息淫痰。JCaptcha 即為 Java 版本的 CAPTCHA 項目东揣,其是一個開源項目揽咕,支持生成圖形和聲音版的驗證碼,在生成聲音版的驗證碼時粟关,需要使用到 FreeTTS疮胖。目前,JCaptcha 官方網(wǎng)站顯示有 2.0 版本闷板,但二進制版只有 1.0 版可供下載澎灸,本文亦是基于 1.0 版本展開

一個簡單的圖形驗證碼

JCaptcha 提供了一定的可擴展能力,用于開發(fā)人員創(chuàng)建出復雜的圖形驗證碼遮晚。下面性昭,首先利用 JCaptcha 提供的 API 來快速開發(fā)一個簡單示例。本文的示例為 Web 應用县遣,可以運行在 Tomcat 和 WebSphere 上巩梢,除了準備 Web 服務器外,我們還需要準備好 JCaptcha 運行時所必須的 Jar 包艺玲。

準備所需的 Jar 包

JCaptcha 項目在實現(xiàn)中括蝠,還引用了 commons-collections 和 commons-logging 兩個開源項目,再加上 JCaptcha 本身的實現(xiàn)饭聚,我們共需要三個包忌警,具體信息如下:

jcaptcha-1.0-all.jar

commons-logging-1.1.1.jar

commons-collections-3.2.jar

創(chuàng)建生成圖形驗證碼的 Servlet

在示例 1 中,我們采用 Servlet 生成驗證碼圖片秒梳,并將這個圖片寫到 ServletOutputStream 中法绵,同時將 Servlet 的 response 的類型設置為 image/jpeg。在前臺頁面中酪碘,我們使用 img 標簽朋譬,并將 src 指向這個 Servlet,這樣我們就可以在頁面中顯示這個生成的驗證碼圖片兴垦。清單 1 是 Servlet 代碼片段徙赢。

清單 1. 生成圖形驗證碼代碼片段

?// set content type as jpeg

httpServletResponse.setHeader("Cache-Control", "no-store");

httpServletResponse.setHeader("Pragma", "no-cache");

httpServletResponse.setDateHeader("Expires", 0);

httpServletResponse.setContentType("image/jpeg");

// create the image using session ID

logger.fine("tring to get image captcha service");

BufferedImage bufferedImage? =????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? service.getImageChallengeForID(httpServletRequest.getSession(true).getId());

ServletOutputStream servletOutputStream =

???????????????????????????????????? httpServletResponse.getOutputStream();

// write the image to the servlet output stream

logger.fine("tring to output buffered image to servlet output stream");

ImageIO.write(bufferedImage, "jpg", servletOutputStream);

try {

???????????? servletOutputStream.flush();

????? } finally {

????????????? servletOutputStream.close();

}

清單 1 中的 service 對象,我們采用了一個 JCaptcha 的默認實現(xiàn)類 DefaultManageableImageCaptchaService探越,在代碼中狡赐,我們需要通過獲取 service 對象,根據(jù) Session ID 來生成驗證碼圖片钦幔。除了使用該默認實現(xiàn)類外枕屉,我們也可以通過實現(xiàn) ImageCaptchaService 接口來生成更為復雜的驗證碼圖片(參見示例 2)。清單 2 為獲取 service 對象的示例代碼鲤氢,JCaptcha 建議使用單例來生成 service 對象搀擂。

清單 2. 生成 ImageCaptchaService 對象

?public class SampleImageCaptchaService? {

private static ImageCaptchaService instance;

/**

* Get default manageable image captcha service

* @return ImageCaptchaService

*/

public static ImageCaptchaService getInstance() {

if (instance == null) {

??????????? instance = new DefaultManageableImageCaptchaService();

??????? }

return instance;

??? }

}

示例 1 提供了 2 個簡單的頁面西潘,一個用于顯示圖形驗證碼,另一個則在驗證成功后顯示成功信息哨颂。

清單 3 為用于顯示圖形驗證碼的頁面代碼片段喷市。

<form action = "CaptchaValidationServlet" method="post">

<table>

? <tr>

????? <td>請輸入你所看到的字符:</td>

????? <td><input type = "text"? name= "captcha_input" value="" />

? ? ? ? ? ? ? ? <%=request.getAttribute("ERROR") == null ? "" : request.getAttribute("ERROR")%>

????? </td>

? </tr>

<tr>

??? <td><input type = "submit" value = "提交"/ ></td>

</tr>

</table>

</form>


除了實現(xiàn)圖形驗證碼的生成和展示,我們還需要一個 Servlet 來驗證用戶的輸入咆蒿。用戶輸入驗證的代碼的核心东抹,是使用在生成圖片時所使用的 service 對象蚂子,調用 JCaptcha 的輸入驗證方法(本示例為 validateResponseForID 方法)沃测,來判斷用戶輸入是否正確,清單 4 為輸入驗證代碼片段食茎。

清單 4. 驗證用戶輸入

?validated = service.validateResponseForID(

request.getSession(true).getId(), userCaptchaResponse).booleanValue();

完成上述代碼工作后蒂破,我們還需要在 Web.xml 中設置好上面創(chuàng)建的兩個 Servlet,然后再部署到 Web 服務器上别渔,圖 1 是部署成功后的示例 1 首頁附迷。

Sample1Index.jpg

至此,我們完成了第一個示例哎媚,該示例采用了 JCaptcha 提供的默認實現(xiàn)喇伯,下面我們將通過擴展使用 JCaptcha,來生成一個更為復雜的圖形驗證碼拨与。

使用 JCaptcha 生成復雜圖形驗證碼

在實際項目中稻据,我們可能需要使用更為復雜的圖形驗證碼,比如买喧,加入帶干擾的圖形背景捻悯、更多的干擾點、自定義隨機字庫及圖形字體等等淤毛,下面將基于示例 2 介紹如何使用 JCaptcha 生成更為復雜的圖形驗證碼今缚。

自定義 ImageCaptchaService 的實現(xiàn)

正如介紹示例 1 時所提到的,我們可以通過實現(xiàn) ImageCaptchaService 接口來創(chuàng)建我們自己所需要的 service 對象低淡,清單 5 為示例 2 對接口 ImageCaptchaService 的實現(xiàn)姓言,我們可以在該實現(xiàn)中,使用自己開發(fā)的圖形驗證碼生成引擎(SampleListImageCaptchaEngine)來生成更為復雜的圖形驗證碼蔗蹋。

清單 5. 示例 2 中 ImageCaptchaService 的實現(xiàn)

?public class SampleImageCaptchaService extends

AbstractManageableImageCaptchaService implements ImageCaptchaService {

private static SampleImageCaptchaService instance;

public static SampleImageCaptchaService getInstance() {

if (instance == null) {

//use customized engine

ListImageCaptchaEngine engine = new SampleListImageCaptchaEngine();

instance = new SampleImageCaptchaService(

new FastHashMapCaptchaStore(), engine, 180, 100000, 75000);

?? }

? return instance;

?? }

public SampleImageCaptchaService(CaptchaStore captchaStore,

CaptchaEngine captchaEngine, int minGuarantedStorageDelayInSeconds,

int maxCaptchaStoreSize, int captchaStoreLoadBeforeGarbageCollection) {

super(captchaStore, captchaEngine, minGuarantedStorageDelayInSeconds,

maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection);

?? }

}

構建生成圖形驗證碼的 ImageCaptchaEngine

清單 5 中的 FastHashMapCaptchaStore 用于存放生成的驗證碼字符事期,F(xiàn)astHashMapCaptchaStore 基本可以滿足絕大多數(shù)項目需求,我們通常不需要創(chuàng)建自己的類來實現(xiàn)它的功能纸颜;SampleListImageCaptchaEngine 則是擴展的核心兽泣,該類是 ImageCaptchaEngine 的一個實現(xiàn),在該類中胁孙,我們可以設置隨機字庫唠倦、生成的字體和大小称鳞、字符數(shù)、背景圖片以及干擾點等等稠鼻。清單 6 為 SampleListImageCaptchaEngine 代碼片段冈止。

清單 6. SampleListImageCaptchaEngine 代碼片段

?//create text parser

TextPaster randomPaster = new DecoratedRandomTextPaster(new Integer(8),

new Integer(10), new SingleColorGenerator(Color.BLACK),

new TextDecorator[] { new BaffleTextDecorator(new Integer(1), Color.WHITE) });

//create image captcha factory

ImageCaptchaFactory factory = new GimpyFactory(

new RandomWordGenerator("abcdefghijklmnopqrstuvwxyz"),

new ComposedWordToImage(new TwistedRandomFontGenerator(new Integer(34),

new Integer(40)), new FunkyBackgroundGenerator(new Integer(

260), new Integer(70)), randomPaster));

ImageCaptchaFactory characterFactory[] = { factory};

this.addFactories(characterFactory);

在清單 6 中,DecoratedRandomTextPaster 的第一個參數(shù)用于設置驗證碼最少字符數(shù)候齿,第二個參數(shù)為最多的字符數(shù)熙暴,第三個參數(shù) SingleColorGenerator 為字體顏色,這里為黑色慌盯,TextDecorator 為干擾設置周霉,這里是一個字符一個干擾點,并且干擾點為白色亚皂。

在 ImageCaptchaFactory 中俱箱,第一個參數(shù)設置了隨機字庫,這里為英文字母灭必,在第二個參數(shù)中狞谱,TwistedRandomFontGenerator 設置了生成的字符字體,最小 34禁漓,最大為 40跟衅,F(xiàn)unkyBackgroundGenerator 則用于生成干擾背景,除了設置字體大小外播歼,還需要設置生成的圖片大小伶跷,示例 2 為 260*70 像素。圖 2 為示例 2 的首頁截圖荚恶。

圖 2. 示例 2 的首頁

Sample2Index.jpg

可以說 ImageCaptchaEngine 的不同實現(xiàn)撩穿,決定了圖形驗證碼的不同樣式,JCaptcha 目前提供了多種 ImageCaptchaEngine 的實現(xiàn)谒撼,這些實現(xiàn)提供了多種不同的圖形驗證碼樣式食寡,當然,我們也可以自己實現(xiàn) TextPaster 及 TextDecorator 等廓潜,進而再繼承實現(xiàn) ImageCaptchaEngine抵皱,從而實現(xiàn)自己所期望的效果。圖 3 為 JCaptcha 官方網(wǎng)站提供的部分 ImageCaptchaEngine 的實現(xiàn)截圖辩蛋,更多樣式呻畸,請參見官方網(wǎng)站

圖 3. JCaptcha 官方圖形驗證碼示例

JCaptchaSample.jpg

開發(fā)聲音驗證碼

由于某些項目需要支持盲人使用悼院,而盲人無法看到圖形驗證碼伤为,這時,我們就需要同時提供聲音版的驗證碼。JCaptcha 同時支持聲音版驗證碼绞愚,但默認實現(xiàn)并不支持生成的聲音和圖形驗證碼中的字符一致叙甸,這里就需要通過一定的擴展定制,才能保證聲音和圖形驗證碼的內容一致位衩,下面首先介紹如何生成聲音驗證碼裆蒸,然后介紹如何擴展定制,才能保證聲音和圖形驗證碼的內容的一致糖驴。

FreeTTS

JCaptcha 使用了 FreeTTS 來開發(fā)聲音驗證碼僚祷,F(xiàn)reeTTS 是一個采用 Java 編寫的語音合成項目,它基于 Flite 項目編寫贮缕,F(xiàn)lite 項目是一個由卡內基梅隆大學開發(fā)的小型語音合成引擎辙谜,其又源于愛丁堡大學的 Festival 語音合成系統(tǒng)和卡內基梅隆大學的 FestVox 項目。本文的示例使用了 FreeTTS 1.2.2跷睦,該版本的有如下幾個方面的功能:

一個語音合成引擎

支持多種聲音

1 個 8khz筷弦,多音位肋演,男性美國英語發(fā)音

1 個 16khz抑诸,多音位,男性美國英語發(fā)音

1 個 16khz 有限聲音域的男性美國英語發(fā)音

支持從 FestVox 導入聲音(僅支持美國英語)

一定程度上支持從 FestVox 中導入 CMU ARCTIC 聲音

支持 MBROLA 聲音(需另外下載該功能包)

1 個 16khz 女性美國英語發(fā)音

2 個 16khz 男性美國英語發(fā)音

部分支持 JSAPI 1.0

為了使用 FreeTTS爹殊,JCaptcha 還另外提供了一個 Jar 包用于和 FreeTTS 的集成蜕乡,所以在運行過程中,除了需要引入 FreeTTS 自帶的 Jar 包梗夸,還需要包括 JCaptcha 提供的和 FreeTTS 集成的包层玲,在示例 3 和 4 中,使用了如下的包:

jcaptcha-extension-sound-freetts-1.0.jar:用于和 FreeTTS 的集成

jcaptcha-1.0-all.jar: JCaptcha 核心包

freetts.jar:FreeTTS 核心包

en_us.jar:用于 FreeTTS

commons-logging-1.1.1.jar:用于 JCaptcha

commons-collections-3.2.jar:用于 JCaptcha

cmutimelex.jar:用于 FreeTTS

cmulex.jar:用于 FreeTTS

cmudict04.jar:用于 FreeTTS

cmu_us_kal.jar:用于 FreeTTS

cmu_time_awb.jar:用于 FreeTTS

構建生成聲音的 SoundCaptchaEngine

同 ImageCaptchaEngine 一樣反症,JCaptcha 同時提供了 SoundCaptchaEngine辛块,所以整個聲音驗證碼的核心是創(chuàng)建 SoundCaptchaEngine 的實現(xiàn),當然 JCaptcha 也提供了一些默認的實現(xiàn)铅碍,比如 DefaultSoundCaptchaEngine 以及 SpellerSoundCaptchaEngine 等等润绵,為了考慮能夠支持生成和圖形驗證碼相同的字符,示例 3 采用繼承抽象類 ListSoundCaptchaEngine 的方式胞谈,來創(chuàng)建自己的實現(xiàn) SampleListSoundCaptchaEngine尘盼。清單 7 為 SampleListSoundCaptchaEngine 代碼片段。

清單 7. SampleListSoundCaptchaEngine 代碼片段

public class SampleListSoundCaptchaEngine extends ListSoundCaptchaEngine {

private static String voiceName = "kevin16";

private static String voicePackage =

"com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory";

protected void buildInitialFactories() {

//create word generator

WordGenerator wordGenerator = new RandomWordGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

//create decorator

SpellerWordDecorator decorator = new SpellerWordDecorator(", ");

//create sound factory

SoundCaptchaFactory soundFactory[] = { new SpellerSoundFactory(

wordGenerator,

new FreeTTSWordToSound(new FreeTTSSoundConfigurator(voiceName,

voicePackage, 1.0f, 100, 100), 4, 10), decorator) };

this.setFactories(soundFactory);

?}

}

創(chuàng)建生成聲音驗證碼的 Servlet

同開發(fā)圖形驗證碼一樣烦绳,這里也需要創(chuàng)建 SoundCaptchaService 的實現(xiàn)卿捎,實現(xiàn)方式與 ImageCaptchaService 的實現(xiàn)類似,示例 3 的實現(xiàn)類為 SampleSoundCaptchaService径密,這里不做敘述午阵,讀者可以參見附帶的示例源代碼。

和 ImageCaptchaService 的實現(xiàn)不同的是享扔,這里不能采用單例的方式來獲取 SoundCaptchaService 的實現(xiàn)底桂,否則不能多次為同一 Session ID 生成多個聲音驗證碼文件括细。另外,在用戶不刷新頁面戚啥,而重復點擊聲音驗證碼圖標時奋单,我們需要提供同一段聲音,因此猫十,我們可以將 SoundCaptchaService 的實現(xiàn)對象以及所生成的字節(jié)碼流放入到 session 中览濒,清單 7 為 SoundCaptchaServlet 代碼片段。

清單 8. SoundCaptchaServlet 代碼片段

?httpServletResponse.setContentType("audio/x-wav");

SoundCaptchaService service = null;

if ( httpServletRequest.getSession().getAttribute("soundService") != null) {

service = (SoundCaptchaService) httpServletRequest

.getSession().getAttribute("soundService");

?? } else {

???? service = new SampleSoundCaptchaService();

????? }

// get AudioInputStream using session

ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();

//get from the session if already existed, otherwise, create new one

if (httpServletRequest.getSession().getAttribute("stream") == null) {

AudioInputStream audioInputStream = service.getSoundChallengeForID(

httpServletRequest.getSession().getId(), httpServletRequest.getLocale());

AudioSystem.write(audioInputStream, javax.sound.sampled.AudioFileFormat.Type.WAVE,

byteOutputStream);

?? } else {

byteOutputStream =

(ByteArrayOutputStream)httpServletRequest.getSession().getAttribute("stream");

?? }

// output to servlet

ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream();

servletOutputStream.write(byteOutputStream.toByteArray());

// save the service object to session, will use it for validation

// purpose

httpServletRequest.getSession().setAttribute("soundService", service);

httpServletRequest.getSession().setAttribute("stream", byteOutputStream);

// output to servlet response stream

try {

servletOutputStream.flush();

?? } finally {

servletOutputStream.close();

? }

創(chuàng)建 Web 頁面和驗證代碼

為了方便用戶使用拖云,我們需要在頁面上放置一個圖標贷笛,當焦點落在圖標上(考慮到盲人可能使用鍵盤 Tab 鍵來切換焦點),觸發(fā) onFocus 事件來調用 JavaScript 方法顯示 embed 標簽宙项,從而調用上面生成聲音驗證碼的 Servlet乏苦。圖 4 為示例 3 首頁截圖。

圖 4. 示例 3 運行頁面截圖

Sample3Index.jpg

當聲音驗證碼圖標在已經獲取焦點尤筐,并朗讀后汇荐,用戶可能多次重復讓該圖標獲取焦點以便多次收聽,這時盆繁,JavaScript 方法會被多次觸發(fā)掀淘,如果不做處理,其將多次請求 Servlet油昂,以致生成不同的聲音文件革娄,本示例采用了前一個小節(jié)所介紹的緩存 SoundCaptchaService 對象和字節(jié)碼流的方法來解決這個問題,以保證多次能收聽到同一段聲音冕碟。當然拦惋,也可以采用在 URL 后面加一個隨機 token 的方式,來判斷是否重復提交安寺。清單 8 為示例 3 首頁代碼片段厕妖。

清單 9. 示例 3 index.jsp 代碼片段

<%request.getSession().removeAttribute("soundService");

request.getSession().removeAttribute("stream");

%>

<html>

<head>

<script type = "text/javascript">

functionplaySoundCaptcha() {

varwavURL ='<%= request.getContextPath() %>'+'/SoundCaptchaServlet';

varembedAudioPlayer ="";

varwavArea = document.getElementById("wavArea");

wavArea.innerHTML = embedAudioPlayer;

}

</script>

</head>

<form action="CaptchaValidationServlet" method="post">

<table>

<tr>

? ? <td colspan="2"><iimgsrc="ImageCaptchaServlet"/></td>

</tr>

<tr>

<td>請輸入您所看到的字符 :</td>

<td><input type="text"name="captcha_input"value=""/><a href="#" onFocus="playSoundCaptcha()"><img src="image/wheelchair.jpg" height="18px" width="18px" ></a><%=request.getAttribute("ERROR") == null ? "" :request? .getAttribute("ERROR")%></td>

</tr>

<tr>

? <td><input type="submit"value="提交"/></td>

</tr>

<div id="wavArea"style="display:none"></div>

</table>

</form>

可以看到,我們采用了不在頁面顯示的 embed 標簽來調用 Servlet 以獲取聲音流我衬,然后自動播放叹放。在每次頁面刷新的時候,還需要將 Session 中的 SoundCaptchaService 的實現(xiàn)對象以及音頻流刪除挠羔,以便頁面刷新時井仰,重新生成新的聲音驗證碼。

后臺用來驗證用戶輸入的邏輯和圖形版的驗證方式相似破加,這里不做介紹俱恶,具體參見示例源代碼。需要注意的是,由于示例 3 生成的聲音驗證碼中的字符和圖形版的字符并不一致合是,在后臺驗證的邏輯中了罪,只需要用戶輸入等于聲音驗證碼或圖形驗證碼的字符,即可認為用戶輸入正確聪全。下面將介紹如何才能使聲音版和圖形版中的字符保持一致泊藕。

使聲音驗證碼和圖形驗證碼字符一致

JCaptcha 并沒有提供很直觀的方式,來保證聲音驗證碼和圖形驗證碼中的字符一致难礼,這就需要我們了解 JCaptcha 的實現(xiàn)娃圆,并能夠通過繼承的方式來擴展定制 JCaptcha,從而實現(xiàn)聲音和圖形驗證碼字符的一致蛾茉。

由于圖形驗證碼會先于聲音驗證碼生成讼呢,所以,我們第一步就是需要獲取圖形驗證碼所生成的字符串谦炬,然后是利用所獲取的字符串來生成聲音驗證碼悦屏。

獲取圖形驗證碼隨機數(shù)

在以上示例中,雖然我們在實現(xiàn) ImageCaptchaEngine 和 SoundCaptchaEngine 的時候键思,可以設置隨機數(shù)生成類础爬,比如 RandomWordGenerator 等,但是即使聲音版和圖形版采用同一個隨機數(shù)生成對象稚机,也不能保證會生成同一個字符幕帆,因為它們僅僅是設定一個隨機字庫获搏,而字符則是每次隨機生成赖条。因而,我們并不能通過使用同樣的隨機數(shù)生成對象來生成同樣的隨機數(shù)常熙,只能通過考慮使用圖形版生成的字符來生成聲音驗證碼纬乍,才能保持兩者的一致。

在創(chuàng)建 ImageCaptchaEngine 的實現(xiàn)時裸卫,我們需要提供一個 ImageCaptchaFactory仿贬,實際上,我們可以通過使用繼承實現(xiàn) JCaptcha 已有 ImageCaptchaFactory 的實現(xiàn)墓贿,來獲取生成的隨機數(shù)茧泪。清單 9 是示例 4 中繼承了 GimpyFactory 的代碼片段。

清單 9. SampleGimpyFactory 代碼片段

?public class SampleGimpyFactory extends GimpyFactory {

……

public ImageCaptcha getImageCaptcha(Locale locale) {

//length

Integer wordLength = getRandomLength();

String word = getWordGenerator().getWord(wordLength, locale);

if (this.wordBridge != null) {

this.wordBridge.setGeneratedWord(word);

? }

BufferedImage image = null;

try {

image = getWordToImage().getImage(word);

} catch (Throwable e) {

throw new CaptchaException(e);

?? }

ImageCaptcha captcha =

new SampleGimpy(CaptchaQuestionHelper.getQuestion(locale, BUNDLE_QUESTION_KEY),

image, word);

return captcha;

?? }

}

可以發(fā)現(xiàn)聋袋,通過使用上面的 SampleGimpyFactory 即可獲取圖形驗證碼的隨機數(shù)队伟,所以我們可以將清單 6 中的 GimpyFactory 替換為 SampleGimpyFactory。

在獲取了生成的隨機數(shù)后幽勒,還需考慮如何將該隨機數(shù)傳遞給生成聲音驗證碼的代碼嗜侮。考慮到我們在生成驗證碼時,都是基于同一個 Session ID 生成锈颗,那么我們就可以將生成的隨機數(shù)放到 map 中,而 key 是 Session ID,那么承二,在生成驗證碼字符后瘟芝,我們就可以用 Session ID 取出該字符串,并放到 Session 中覆醇,然后绅喉,在生成聲音驗證碼的代碼中,就可以從 Session 中獲取隨機數(shù)叫乌。但是柴罐,并不是所有代碼都可以很方便的獲取到 ID,所以憨奸,我們還需要對示例 2 的代碼進行改造革屠,以便能夠根據(jù) ID 保存隨機數(shù)。清單 10 為改造后的清單 5 中的類 SampleImageCaptchaService 的代碼片段排宰。

清單 10. SampleImageCaptchaService 代碼片段

?public class SampleImageCaptchaService extends

AbstractManageableImageCaptchaService implements ImageCaptchaService {

… ..

@Override

public BufferedImage getImageChallengeForID(String ID)

throws CaptchaServiceException {

BufferedImage image=? super.getImageChallengeForID(ID);

String generatedWord = ((SampleListImageCaptchaEngine) engine).getWordBridge()

.getGeneratedWord();

WordMap.getWordsMap().put(ID, generatedWord);

return image;

? }

}

如清單 10 所示似芝,我們將生成的隨機數(shù)放到了一個 map 中,而 key 則是 ID板甘,這里也就是 SessionID党瓮,然后我們就可以在 ImageCaptchaServlet 獲取并將該隨機數(shù)放到 Session 中,如清單 11 所示盐类。接下來便是如何利用該字符生成聲音驗證碼寞奸。

清單 11. ImageCaptchaServlet 代碼片段

httpServletRequest.getSession().setAttribute(

"generatedWord",

WordMap.getWordsMap().get(httpServletRequest.getSession(true)

.getId()));

利用指定字符生成聲音驗證碼

為了能夠使用指定的字符串生成驗證碼,我們需要對示例 3 中的代碼做一定的修改在跳。這里枪萄,示例 4 通過繼承 SpellerSoundFactory 實現(xiàn)了一個擴展的 SoundCaptchaFactory,清單 12 為代碼片段猫妙。

清單 12. SampleSpellerSoundFactory 代碼片段

?public class SampleSpellerSoundFactory extends SpellerSoundFactory {

private String word;

……

@Override

public SoundCaptcha getSoundCaptcha() {

return getSoundCaptcha(Locale.getDefault());

?? }

@Override

public SoundCaptcha getSoundCaptcha(Locale locale) {

String soundWord = "";

if (this.word != null && !this.word.equals("")) {

soundWord = this.word;

?? } else {

soundWord = this.wordGenerator.getWord(getRandomLength(), locale);

?? }

AudioInputStream sound = this.word2Sound.getSound(wordDecorator

.decorateWord(soundWord), locale);

SoundCaptcha soundCaptcha = new SpellerSound(getQuestion(locale),

sound, word);

return soundCaptcha;

? }

}

根據(jù)清單 11 中的代碼瓷翻,如果字符串能夠正確的傳進來,這個 SampleSpellerSoundFactory 將可以根據(jù)該字符串生成聲音驗證碼割坠。

相應的齐帚,清單 7 中的 SampleListSoundCaptchaEngine 需要做如清單 13 所示的修改。

清單 13. SampleListSoundCaptchaEngine 代碼

?public class SampleListSoundCaptchaEngine extends ListSoundCaptchaEngine {

private String word;

private static String voiceName = "kevin16";

private static String voicePackage =

"com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory";

protected void buildInitialFactories() {

WordGenerator wordGenerator = new RandomWordGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

SpellerWordDecorator decorator = new SpellerWordDecorator(", ");

SoundCaptchaFactory soundFactory[] = { new SampleSpellerSoundFactory(

wordGenerator,

new FreeTTSWordToSound(new FreeTTSSoundConfigurator(voiceName,

voicePackage, 1.0f, 100, 100), 4, 10), decorator, word) };

this.setFactories(soundFactory);

??? }

public SampleListSoundCaptchaEngine(String word) {

this.word = word;

buildInitialFactories();

? }

}

需要注意的是彼哼,我們一定要有如清單 13 所示的帶參數(shù)的夠找函數(shù)对妄,否則初始化時,該類會首先調用父類的構造函數(shù)沪羔,其父類會直接調用 buildInitialFactories 函數(shù)饥伊,而此時字符串還沒有傳遞給父類象浑。

接下來需要修改 SampleSoundCaptchaService,在該類中使用 SampleListSoundCaptchaEngine 并傳入隨機數(shù)參數(shù)琅豆。

清單 14. SampleSoundCaptchaService 代碼片段

?public class SampleSoundCaptchaService extends

AbstractManageableSoundCaptchaService implements SoundCaptchaService {

public SampleSoundCaptchaService(String word) {

super(new FastHashMapCaptchaStore(),

new SampleListSoundCaptchaEngine(word), 180, 100000, 75000);

? ? }

……

? }

最后愉豺,我們只需要修改 SoundCaptchaServlet,先依據(jù) Session ID 獲取生成的隨機數(shù)茫因,然后調用清單 14 的 SampleSoundCaptchaService 生成聲音驗證碼蚪拦,如清單 15 所示。

清單 15. SoundCaptchaServlet 代碼片段

?String word = "";

if (httpServletRequest? .getSession().getAttribute("generatedWord") != null) {

word = (String)httpServletRequest.getSession().getAttribute("generatedWord");

logger.info("Get generated word from the session, word=" + word);

??? }

service = new SampleSoundCaptchaService(word);

至于后臺驗證邏輯冻押,可以不做修改驰贷,也可以刪除原先用于驗證聲音驗證碼的代碼。至此洛巢,聲音驗證碼的字符將與圖形驗證碼的字符保持一致括袒。

總結

Jpatchca生成驗證碼感覺不好使,對圖的參數(shù)控制不好稿茉,可能導致圖很高锹锰,但是文字卻根本沒占滿,如果文字設置大了漓库,會拋出異常恃慧,說文字太高了。

其二渺蒿,Jpatchca不支持集群環(huán)境痢士,默認的驗證碼不是保存在session中,如果想做個性化的處理很麻煩茂装。其實我想要的就是一個聲稱圖片的流就ok了怠蹂,剩下的事情就交給程序員自己實現(xiàn)吧。



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末训唱,一起剝皮案震驚了整個濱河市褥蚯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌况增,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件训挡,死亡現(xiàn)場離奇詭異澳骤,居然都是意外死亡,警方通過查閱死者的電腦和手機澜薄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門为肮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肤京,你說我怎么就攤上這事颊艳∶┨兀” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵棋枕,是天一觀的道長白修。 經常有香客問我,道長重斑,這世上最難降的妖魔是什么兵睛? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮窥浪,結果婚禮上祖很,老公的妹妹穿的比我還像新娘。我一直安慰自己漾脂,他們只是感情好假颇,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骨稿,像睡著了一般拆融。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上啊终,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天镜豹,我揣著相機與錄音,去河邊找鬼蓝牲。 笑死趟脂,一個胖子當著我的面吹牛,可吹牛的內容都是我干的例衍。 我是一名探鬼主播昔期,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼佛玄!你這毒婦竟也來了硼一?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤梦抢,失蹤者是張志新(化名)和其女友劉穎般贼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奥吩,經...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡哼蛆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了霞赫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腮介。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖端衰,靈堂內的尸體忽然破棺而出叠洗,到底是詐尸還是另有隱情甘改,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布灭抑,位于F島的核電站十艾,受9級特大地震影響,放射性物質發(fā)生泄漏名挥。R本人自食惡果不足惜疟羹,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望禀倔。 院中可真熱鬧榄融,春花似錦、人聲如沸救湖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鞋既。三九已至力九,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邑闺,已是汗流浹背跌前。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陡舅,地道東北人抵乓。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像靶衍,于是被迫代替她去往敵國和親灾炭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理颅眶,服務發(fā)現(xiàn)蜈出,斷路器,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,754評論 25 707
  • 有一個故事 講的是 16歲的少女 踏上未知的異鄉(xiāng) 把夢想遺落在故鄉(xiāng) 她的背包里 滿滿的是失望和迷茫 陌生的城市 她...
    鴻鵠是只鳥閱讀 132評論 0 1
  • 最近要考英語四級了涛酗,可聽力真的是小白铡原。不過,幸虧看了一個公開課煤杀,就是學聽力時眷蜈,先學小學的,把小學的學完再說沈自。
    qsmxgrw閱讀 110評論 0 0
  • SNS社區(qū)類網(wǎng)站根據(jù)功能可以分為3類: 1、基于搜索互式知識問答享平臺(:百度酪夷、新浪問榴啸、知乎、Quora) 2晚岭、 ...
    Jelly妮閱讀 6,432評論 0 1