webutil-licenseImage 插件內置4種驗證碼樣式,支持用戶擴展.自定義樣式實現簡單驗證碼.
源碼脫管地址: http://code.google.com/p/licenseimage/
Jar包下載地址: http://files.cnblogs.com/dennisit/Java%E9%AA%8C%E8%AF%81%E7%A0%81%E6%8F%92%E4%BB%B6.rar
項目結構圖:

說明:
ResourceUtil類為獲取包內資源服務
LicenseImage用來生成驗證碼
思路: 通過獲取驗證碼圖片資源,創建BufferedImage圖片對象,然后獲取該對象的Graphics2D操作類,使用Graphics2D繪制背景圖,繪制隨機生成的字碼,繪制干擾線,將結果封裝成Map集合,map的key值用來做為session中判斷的依據,Map的key為BufferedImage對象,用於展示給前台輸出.
核心代碼如下:
ResourceUtil類
package org.pudp.util; import java.net.URL; import java.net.URLClassLoader; /** * 類說明: * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 * * org.pudp.util.Resource.java * */
public class ResourceUtil { /** * 獲取資源的URL路徑 * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 下午09:33:07 * * @param paramString * 驗證碼圖片所在的包的相對路徑 * @return * 驗證碼所在的URL */
public static URL getResourceUrl(String paramString){ return ((URLClassLoader)ResourceUtil.class.getClassLoader()).getResource(paramString); } /** * 獲取資源的串值路徑 * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 下午06:09:17 * * @param paramString * 驗證碼圖片所在的包的相對路徑 * @return * 驗證碼所在的串值地址 */
public static String getResourcePath(String paramString){ return Thread.currentThread().getContextClassLoader().getResource(paramString).getPath(); } }
生成驗證碼的核心類
package org.pudp.util.license; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Random; import javax.imageio.ImageIO; import org.pudp.util.ResourceUtil; /** * 類說明: 驗證碼工具 * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 * * org.pudp.util.license.LicenseImage.java * */
public class LicenseImage { public static final Integer TYPE1 = 1; //樣式一
public static final Integer TYPE2 = 2; //樣式二
public static final Integer TYPE3 = 3; //樣式三
public static final Integer TYPE4 = 4; //樣式四
public static final int DEF_NUM = 4; //驗證碼上的字符個數
public static final int DEF_LINES = 3; //干擾線條數
public static final int DEF_WIDTH = 150; //驗證碼圖片寬
public static final int DEF_HEIGHT = 50; //驗證碼圖片高
public static final int DEF_FONT_SIZE = 24; //驗證碼上字體大小
private int num; //驗證碼上的字符個數
private int width ; //驗證碼圖片寬
private int height ; //驗證碼圖片高
private int fontSize ; //驗證碼上字體大小
private int lines ; //干擾線條數
private static final String[] chars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" }; public LicenseImage(){ this(DEF_WIDTH, DEF_HEIGHT, DEF_FONT_SIZE, DEF_NUM, DEF_LINES); } /** * 自定義驗證碼的寬度與高度 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 */
public LicenseImage(int width,int height){ if(width<0 || height<0){ this.width = LicenseImage.DEF_WIDTH; this.height = LicenseImage.DEF_HEIGHT; }else{ this.width = width; this.height = height; } this.num = LicenseImage.DEF_NUM; this.fontSize = LicenseImage.DEF_FONT_SIZE; this.lines = LicenseImage.DEF_LINES; } /** * 自定義驗證碼的寬度和高度,以及字體大小 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 * @param fontSize * 驗證碼字體大小 */
public LicenseImage(int width,int height,int fontSize){ this(width, height); this.fontSize = fontSize; this.num = LicenseImage.DEF_NUM; this.lines = LicenseImage.DEF_LINES; } /** * 自定義驗證碼的寬度和高度,以及字體大小 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 * @param fontSize * 驗證碼字體大小 * * @param size * 驗證碼上字體個數 */
public LicenseImage(int width,int height,int fontSize,int num){ this(width, height,fontSize); if(num <0){ this.num = LicenseImage.DEF_NUM; }else{ this.num = num; } this.lines = LicenseImage.DEF_LINES; } /** * 自定義驗證碼的寬度和高度,以及字體大小 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 * @param fontSize * 驗證碼字體大小 * @param size * 驗證碼上字體個數 * * @param lines * 驗證碼上的干擾線條數目 */
public LicenseImage(int width,int height,int fontSize,int num,int lines){ this(width, height,fontSize,num); this.lines = lines; } /** * * 生成驗證碼,驗證碼圖片由用戶自己定義 * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 下午08:13:53 * * @param backgroundPath * 用戶自定義的驗證碼的背景圖片 * @return * 驗證碼生成后的封裝對象 */
public Map<String,BufferedImage> createImage(String backgroundPath){ //保存產生驗證碼真實值的串
StringBuffer buffer = new StringBuffer(); //自定義圖片對象
BufferedImage image = new BufferedImage(this.width,this.height,BufferedImage.TYPE_INT_RGB); Map<String,BufferedImage> map = new HashMap<String,BufferedImage>(); Graphics2D graphics = (Graphics2D) image.createGraphics(); graphics.setColor(Color.WHITE); // 初始化背景圖片
try { Image bgImage = ImageIO.read(ResourceUtil.getResourceUrl(backgroundPath)); graphics.drawImage(bgImage,0,0,this.width,this.height,null); } catch (IOException e) { e.printStackTrace(); } Random random = new Random(); //畫隨機字符
for(int i=0; i<this.num; i++){ //隨即獲取定義字符集中的一個元素
int rand = random.nextInt(chars.length); graphics.setColor(randomColor()); graphics.setFont(new Font("Times New Roman",Font.BOLD+Font.ITALIC,this.fontSize)); /** **隨機縮放文字並將文字旋轉指定角度* start*/ Graphics2D g2d_word = (Graphics2D) graphics; AffineTransform trans = new AffineTransform(); trans.rotate(random.nextInt(10) * 3.14 / 90, 13 * i + 8, 7); // 縮放文字
float scaleSize = random.nextFloat() +0.8f; if (scaleSize > 1f){ scaleSize = 1f; } trans.scale(scaleSize, scaleSize); g2d_word.setTransform(trans); /** **隨機縮放文字並將文字旋轉指定角度* end*/ graphics.drawString(chars[rand],(this.num*2)+(i)*this.width/this.num , this.height/2); buffer.append(chars[rand]); //將生成的字符串存入到buffer中,將來獲取時用於跟用戶輸入的值比較
} //畫干擾線
for(int i=1;i<=this.lines;i++){ graphics.setColor(randomColor()); graphics.drawLine(random.nextInt(this.width), random.nextInt(this.height), random.nextInt(this.width),random.nextInt(this.height)); if(i==this.lines){ Font font = new Font("Times New Roman",Font.PLAIN, this.fontSize-5); graphics.setFont(font); graphics.setColor(Color.GRAY); } } //畫一條折線
/* BasicStroke bs=new BasicStroke(2f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL); //創建一個供畫筆選擇線條粗細的對象 graphics.setStroke(bs); //改變線條的粗細 graphics.setColor(randomColor()); //設置當前顏色為預定義顏色中的深灰色 int[] xPoints=new int[3]; int[] yPoints=new int[3]; for(int j=0;j<3;j++){ xPoints[j]=random.nextInt(WIDTH - 1); yPoints[j]=random.nextInt(HEIGHT - 1); } graphics.drawPolyline(xPoints, yPoints,3); */ map.put(buffer.toString(), image); return map; } /** * * 使用系統默認樣式 * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 下午08:06:22 * * @param type * 工具內置的類型,用戶使用該類型即可用內置的樣式生成驗證碼 * @return * Map<驗證碼的值,驗證碼的圖片> */
public Map<String,BufferedImage> createImage(int type){ return createImage("org/pudp/util/license/resources/yzm"+type+".gif"); } /** * 隨即產生顏色 * * @author <a href='mailto:dennisit@163.com'>Cn.蘇若年(En.dennisit)</a> Copy Right since 2013-9-16 下午08:04:08 * * @return * <code>Color對象</code> */
public static Color randomColor(){ Random random = new Random(); Color color = new Color(random.nextInt(256),random.nextInt(256),random.nextInt(256)); return color; } }
實例應用
創建servlet類
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 禁止圖像緩存。
response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); //使用驗證碼工具生成驗證碼
LicenseImage licenseImage = new LicenseImage(); //使用驗證碼工具內置樣式
Map<String,BufferedImage> licenseImg = licenseImage.createImage(LicenseImage.TYPE1); //獲取map集合中的值
String key = (String)licenseImg.keySet().iterator().next(); //將驗證碼的key放入session中 //SessionUtil.session(request).setAttribute(CommonConstant.LicenseImageKey, key);
System.out.println("session中的驗證碼值為:" + key); //獲取map集合中的圖片對象
BufferedImage buffImg = licenseImg.get(key); ServletOutputStream out = response.getOutputStream(); ImageIO.write(buffImg, "jpeg", out); out.close(); }
內置樣式一效果圖
使用工具內置的樣式生成驗證碼代碼,licenseImage.createImage(int type)方法,傳遞系統內置的4種樣式即可生成驗證碼
//使用驗證碼工具生成驗證碼
LicenseImage licenseImage = new LicenseImage(); //使用驗證碼工具內置樣式
Map<String,BufferedImage> licenseImg = licenseImage.createImage(LicenseImage.TYPE1);
系統后台為我們打印出了session中存放的驗證碼的串值如下:
開發者自定義驗證碼,構造自定義參數說明如下
/** * 自定義驗證碼的寬度與高度 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 */
public LicenseImage(int width,int height){ this.width = width; this.height = height; this.num = LicenseImage.DEF_NUM; this.fontSize = LicenseImage.DEF_FONT_SIZE; this.lines = LicenseImage.DEF_LINES; } /** * 自定義驗證碼的寬度和高度,以及字體大小 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 * @param fontSize * 驗證碼字體大小 */
public LicenseImage(int width,int height,int fontSize){ this(width, height); this.fontSize = fontSize; this.num = LicenseImage.DEF_NUM; this.lines = LicenseImage.DEF_LINES; } /** * 自定義驗證碼的寬度和高度,以及字體大小 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 * @param fontSize * 驗證碼字體大小 * * @param size * 驗證碼上字體個數 */
public LicenseImage(int width,int height,int fontSize,int num){ this(width, height,fontSize); this.num = num; this.lines = LicenseImage.DEF_LINES; } /** * 自定義驗證碼的寬度和高度,以及字體大小 * @param width * 驗證碼的寬度 * @param height * 驗證碼的高度 * @param fontSize * 驗證碼字體大小 * @param size * 驗證碼上字體個數 * * @param lines * 驗證碼上的干擾線條數目 */
public LicenseImage(int width,int height,int fontSize,int num,int lines){ this(width, height,fontSize,num); this.lines = lines; }
自定義實例應用
//使用驗證碼工具提供的構造參數自定義相應的參數值
LicenseImage licenseImage = new LicenseImage(120,50,18,5,5); //指定自定義背景包內的相對路徑
Map<String,BufferedImage> licenseImg = licenseImage.createImage("definebk.png");
如果自定義圖片在com.define包下,傳遞的串值參數為
Map<String,BufferedImage> licenseImg = licenseImage.createImage("com/define/definebk.png");
自定義實例效果圖
內置幾種樣式:
應用說明,見jar包里邊的readme.txt文件

