account-captcha需要提供的服務是生成隨機的驗證碼主鍵,然後用戶可以使用這個主鍵要求服務生成一個驗證碼圖片,這個圖片對應的值應該是隨機的,最後用戶用肉眼讀取圖片的值,並將驗證碼的主鍵與這個值交給服務進行驗證。這一服務對應的接口可以定義,如代碼清單10-3所示。
代碼清單10-3 AccountCaptchaService.java
很顯然,generateCaptchaKey()用來生成隨機的驗證碼主鍵,generateCaptchaImage()用來生成驗證碼圖片,而validateCaptcha()用來驗證用戶反饋的主鍵和值。
該接口定義了額外的getPreDefinedTexts()和setPreDefinedTexts()方法,通過這一組方法,用戶可以預定義驗證碼圖片的內容,同時也提高了可測試性。如果AccountCaptchaService永遠生成隨機的驗證碼圖片,那麼沒有人工的參與就很難測試該功能。現在,服務允許傳入一個文本列表,這樣就可以基於這些文本生成驗證碼,那麼我們也就能控制驗證碼圖片的內容了。
為了能夠生成隨機的驗證碼主鍵,引入一個RandomGenerator類,見代碼清單10-4。
代碼清單10-4 RandomGenerator.java
RandomGenerator類提供了一個靜態且線程安全的getRandomString()方法。該方法生成一個長度為8的字符串,每個字符都是隨機地從所有數字和字母中挑選,這裡主要是使用了java.util.Random類,其nextInt(int n)方法會返回一個大於等於0且小於n的整數。代碼中的字段range包含了所有的數字與字母,將其長度傳給nextInt()方法後就能獲得一個隨機的下標,再調用range.charAt()就可以隨機取得一個其包含的字符了。
現在看AccountCaptchaService的實現類AccountCaptchaServiceImpl。首先需要初始化驗證碼圖片生成器,見代碼清單10-5。
代碼清單10-5 AccountCaptchaServiceImpl.java的afterPropertySet()方法
AccountCaptchaServiceImpl實現了SpringFramework的InitializingBean接口,該接口定義了一個方法afterPropertiesSet(),該方法會被SpringFramework初始化對象的時候調用。該代碼清單中使用該方法初始化驗證碼生成器producer,並且為producer提供了默認的配置。
接著AccountCaptchaServiceImpl需要實現generateCaptchaKey()方法,見代碼清單10-6。
代碼清單10-6 AccountCaptchaServiceImpl.java的generateCaptchaKey()方法
上述代碼清單中的generateCaptchaKey()首先生成一個隨機的驗證碼主鍵,每個主鍵將和一個驗證碼字符串相關聯,然後這組關聯會被存儲到captchaMap中以備將來驗證。主鍵的目的僅僅是標識驗證碼圖片,其本身沒有實際的意義。代碼清單中的getCaptchaText()用來生成驗證碼字符串,當preDefinedTexts不存在或者為空的時候,就是用驗證碼圖片生成器producer創建一個隨機的字符串,當preDefinedTexts不為空的時候,就順序地循環該字符串列表讀取值。preDefinedTexts有其對應的一組get和set方法,這樣就能讓用戶預定義驗證碼字符串的值。
有了驗證碼圖片的主鍵,AccountCaptchaServiceImpl就需要實現generateCaptchaImage()方法來生成驗證碼圖片,見代碼清單10-7。
代碼清單10-7 AccountCaptchaServiceImpl.java的generateCaptchaImage()方法
為了生成驗證碼圖片,就必須先得到驗證碼字符串的值,代碼清單中通過使用主鍵來查詢captchaMap獲得該值,如果值不存在,就拋出異常。有了驗證碼字符串的值之後,generateCaptchaImage()方法就能通過producer來生成一個BufferedImage,隨後的代碼將這個圖片對像轉換成jpg格式的字節數組並返回。有了該字節數組,用戶就能隨意地將其保存成文件,或者在網頁上顯示。
最後是簡單的驗證過程,見代碼清單10-8。
代碼清單10-8 AccountCaptchaServiceImpl.java的validateCaptcha()方法
用戶得到了驗證碼圖片以及主鍵後,就會識別圖片中所包含的字符串信息,然後將此驗證碼的值與主鍵一起反饋給validateCaptcha()方法以進行驗證。validateCaptcha()通過主鍵找到正確的驗證碼值,然後與用戶提供的值進行比對,如果成功,則返回true。
當然,還需要一個SpringFramework的配置文件,它在資源目錄src/main/resources/下,名為account-captcha.xml,見代碼清單10-9。
代碼清單10-9 account-captcha.xml
這是一個最簡單的SpringFramework配置,它定義了一個id為accountCaptchaService的bean,其實現為剛才討論的AccountCaptchaServiceImpl。