在web系统中,验证码的应用基本上随处可见.验证码可以防止他人恶意攻击和垃圾注册,可以说已成了web开发中必不可少的环节.遗憾的是,验证码在jsp,jsf的组件库, 至少是一些标准的组件库中并没有出现.本文分别介绍如何在jsp和jsf中使用验证码和我的一些小经验,呵呵.
在jsp中,我们使用apache的taglibs-image(http://jakarta.apache.org/taglibs/sandbox/doc/image-doc/intro.html),可以简便的配置自己的验证码.而由于在jsf中,无法和其他jsp标签库混用(至少不能和上述标签库混用),我们则用Java2D自己绘制验证码图.
1. 在jsp中使用taglibs-image部署验证码
taglibs-image可以通过标签自动将一段文字和背景图片生成新的图片,文字的布局,颜色,字体等等都可以自我定制,因此拿来做验证码是非常的简单
<%
@ 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
>
其中最开始百分号内的java代码是为了生成验证码,然后保存在session中.同时验证码和背景图片生成新的验证图.用户根据此图输入验证码.在服务器方,只用把用户提交表单中的验证码内容取出和session中保存的验证码对比,就可以判断正确性咯
2.JSF
jsf中无法使用上述标签(会无法渲染出来), 因此,我们自己实现一个生成验证图的类,再通过jsf的<h:graphicImage>标签得以显示.
生成验证码的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;
/** *//**
* 用来自动生成验证图和验证码,验证图是背景图加上干扰点加上验证码
*
* @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";
/** *//**
* 验证码
*/
private String code = "";
/** *//**
* 验证图的地址
*/
private String path;
private int width;
private int height;
private BufferedImage image;
/** *//**
* 验证图对应的File对象
*/
private File target;
public CodeImageGenerator() {
this(DEF_WIDTH, DEF_HEIGHT);
}
public CodeImageGenerator(int width, int height) {
this.width = width;
this.height = height;
generateCodeImage();
}
/** *//**
* 生成验证码和验证图
*
*/
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;
}
/** *//**
* 当这个对象被回收时,同时销毁其对应的验证图
*/
@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;
}
}
要说明几点的事,这个类会把生成的验证图放在制定文件夹下,未免得文件越来越多,应该当验证图不再使用时将之删除.所以此类重写了Object的finalize()方法,当此类被垃圾回收器回收时,同时也删除其对应的验证图.
这样,就可以利用java的垃圾回收器轻松为我们删除不用的文件.
另外,在页面对应的managed-bean中,我们还要添加如何得到验证码和验证图的方法
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对应用户输入的验证码信息
因为每次刷新页面都需要得到不同的验证码,所以在getValidator()方法时,每次需要返回一个新的CodeImageGenerator.同时,你可能等不及垃圾回收器帮你删除文件,因此,可以在这里同时删除老的验证图.
另外,在注册时我们还需要做一下判断:
public String register() {
// System.out.println("haha");
if(!validator.getCode().equals(validate_code)){
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR, "验证码错误",
"验证码错误");
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;
}
..
} 最后,我们需要在页面中添加对应的标签
<h:outputText value="验证码(*):" 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中实现了自己的验证码部署^_^