前两天买了张火车票,使人egg碎的验证已无力吐槽,试了几次都让我开始怀疑我的IQ是否是合适再从事程序猿的这个”神圣的职业“了。今天分享的是1段比较传统而不失实用的验证,验证的意义想必大家都已知晓。
好了,语言总是苍白无力。直入真题来看代码的实现的吧。
操作环境:
jboss eap 6.2
tomcat也能够,比较懒直接用的jboss。大家有兴趣也能够试试,支持的服务更多,性能更加稳定些。
servlet
麻雀虽小,5脏俱全,做了小例子足以。
JCaptcha
jcaptcha是1个开源的验证码生成控件。1般用于生产图片类验证码,但也支持声音的验证。
JCaptcha的官方网站:http://jcaptcha.sourceforge.net/
另外还有对应的开源社区:http://www.oschina.net/p/jcaptcha/
这里使用的是 jcaptcha⑴.0-all.jar ,好像有点老,但是自己maven的nexus里面正好有。
主要分为几个步骤
1.BackgroundGenerator生成图片。包括图片的背风景,大小等样式。
2.生成文字、运算符。包括文字的格式,字体的种类,字体的最小最大样式。
3.利用JCaptcha的1个工具类WordToImage生成带文字的图片。
4.最后则是验证的进程
package com.tgb.cfl;
import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;
public class BfferImageCss {
private static DefaultManageableImageCaptchaService instance=null;
public static int result;
/**
* 单例模式的类用于生成图片
* @return
*/
public static ImageCaptchaService getInstance() {
VerifImage vi= new VerifImage();
result=vi.getResult();
if(instance==null){
instance = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), vi, 180, 100000, 75000);
}else{
instance.setCaptchaEngine(vi);
}
return instance;
}
}
2、设置图片样式、字体情势、操作符情势
package com.tgb.cfl;
import java.awt.*;
import java.util.Random;
import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.FunkyBackgroundGenerator;
import com.octo.captcha.component.image.color.ColorGenerator;
import com.octo.captcha.component.image.color.RandomRangeColorGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.word.wordgenerator.DummyWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;
public class VerifImage extends ListImageCaptchaEngine {
static{
System.setProperty("java.awt.headless", "true");
}
//壹 贰 叁 肆 伍 陆 柒 捌 玖
private final static String[] nods={"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
//1,2,3,4,5,6,7,8,9
private final static String[] nohs={"零","1","2","3","4","5","6","7","8","9"};
//0 1 2 3 4 5 6 7 8 9
private final static String[] noss={"0","1","2","3","4","5","6","7","8","9"};
// 寄存加减乘运算符
private final static char[] arr = {'+', '-', '×'};
//汉字加减乘运算符
private final static char[] arrh={'加','减','乘'};
private StringBuffer sb=null;
private Random random=null;
private int result;
public int getResult(){
return result;
}
@Override
protected void buildInitialFactories() {
random = new Random();
sb=new StringBuffer();
//获得1个随机boolean
boolean bool=random.nextBoolean();
//掉用生成运算模式方法
this.model(bool);
int len=sb.toString().length();
WordGenerator wgen=new DummyWordGenerator(sb.toString());
//设置字体色彩
RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(new int[]{0, 60}, new int[]{0, 60}, new int[]{0, 60});
// 文字显示的个数
TextPaster textPaster = new RandomTextPaster(len, len, cgen, true);
//设置图片背景色彩
ColorGenerator colorGenerator = new RandomRangeColorGenerator(new int[]{200, 200}, new int[]{200, 200}, new int[]{200, 200});
// 图片的大小
BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator(90, 28,colorGenerator);
// 字体魄式
Font[] fontsList = new Font[]{new Font("宋体", 0, 10)};
// 文字的大小
FontGenerator fontGenerator = new RandomFontGenerator(18, 20, fontsList);
//将文字写入到图片中
WordToImage wordToImage = new ComposedWordToImage(fontGenerator, backgroundGenerator, textPaster);
this.addFactory(new GimpyFactory(wgen, wordToImage));
}
private void model(boolean bool){
// 生成随机整数num1
int num1 = getRandomNum();
// 生成随机整数num2
int num2 = getRandomNum();
//随机产生运算方式
int operate = random.nextInt(3);
switch (operate) {
case 0:
this.result = num1 + num2;
break;
case 1:
this.result = num1 - num2;
break;
case 2:
this.result = num1 * num2;
break;
}
try{
//随机生成运算表达试
if(bool){
this.getRes(operate,num1,num2);
}else{
int r=random.nextInt(3);
sb.append(getNos(r,num1)+" ");
r=random.nextInt(2);
sb.append(getOperate(r,operate)+" ");
r=random.nextInt(3);
sb.append(getNos(r,num2));
sb.append(" = ?");
}
}catch (Exception e){
e.printStackTrace();
}
}
//生成运算表达试
private void getRes(int operate,int num1,int num2){
int r=random.nextInt(2);
switch (r){
case 0:
r=random.nextInt(3);
sb.append(getNos(r,num1)+" ");
r=random.nextInt(2);
sb.append(getOperate(r,operate)+" ");
sb.append("?");
sb.append(" = "+this.result);
this.result=num2;
break;
case 1:
sb.append("? ");
r=random.nextInt(2);
sb.append(getOperate(r,operate)+" ");
r=random.nextInt(3);
sb.append(getNos(r,num2));
sb.append(" = "+this.result);
this.result=num1;
break;
}
}
//获得运算数字
private String getNos(int random,int num) {
switch (random){
case 0:
return nods[num];
case 1:
return nohs[num];
case 2:
return noss[num];
}
return null;
}
//获得运算符
private String getOperate(int random,int num){
switch (random){
case 0:
return String.valueOf(arr[num]);
case 1:
return String.valueOf(arrh[num]);
}
return null;
}
//获得0~9随机数
private int getRandomNum(){
int num = random.nextInt(10);
while (num == 0) {
num = random.nextInt(10);
}
return num;
}
}
这里主要是为了构成用于计算结果的文字和图片和1些样式的设定。
3、测实验证码
servlet
package com.tgb.cfl;
import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* 用于生产验证码图片的class
* @author cfl
* @date 2015年4月30日
*
*/
public class VerificationCode extends HttpServlet {
private static final long serialVersionUID = -11L;
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte[] b = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
//获得session对象
HttpSession session=request.getSession();
//获得本次会话的sessionID
String captchaId = session.getId();
//生成图片
BufferedImage challenge = BfferImageCss.getInstance().getImageChallengeForID(captchaId, request.getLocale());
//将结果保存到session
session.setAttribute(captchaId+"_vccode",BfferImageCss.result);
//加密
JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(baos);
jpegEncoder.encode(challenge);
} catch (IllegalArgumentException e) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
} catch (CaptchaServiceException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
b = baos.toByteArray();
//设置相应的参数,用于显示图片
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream sos = response.getOutputStream();
sos.write(b);
sos.flush();
sos.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
这里是1个简单的servlet用于,虽然是1个简单的servlet,但是也足够完成所需功能。
好了,最后附上效果图1张