1 引入验证码组件
打开 simplecaptcha 官网,下载相应的 jar 包。示例中用的是 nl.captcha.simplecaptcha-1.2.1.jar。
2 自定义验证码服务
2.1 字符生成器
因为某些字符相似容易导致用户误输,比如 i 与 1、z 与 2,所以我们自己定制了字符生成器:
public class CustomTextProducer implements TextProducer {
private static final Random RAND = new SecureRandom();
/**
* 默认长度
*/
private static final int DEFAULT_LENGTH = 4;
/**
* 字符集
*/
private static final char[] DEFAULT_CHARS = new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'k', 'm', 'n', 'p', 'r', 'w', 'x', 'y', '2', '3', '4', '5', '6', '7', '8'};
private final int _length;
private final char[] _srcChars;
public CustomTextProducer() {
this(DEFAULT_LENGTH, DEFAULT_CHARS);
}
public CustomTextProducer(int length, char[] srcChars) {
this._length = length;
this._srcChars = copyOf(srcChars, srcChars.length);
}
public String getText() {
String capText = "";
for (int i = 0; i < this._length; ++i) {
capText = capText + this._srcChars[RAND.nextInt(this._srcChars.length)];
}
return capText;
}
private static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
}
在 DEFAULT_CHARS 中我们定义了验证码字符集。
2.2 验证码 Servlet
参考组件源代码,我们写了定制的验证码 Servlet:
public class CustomCaptchaServlet extends HttpServlet {
static Logger logger = Logger.getLogger(CustomCaptchaServlet.class);
private static final long serialVersionUID = 1L;
private static int _width = 300;
private static int _height = 50;
/**
* 颜色库
*/
private static final java.util.List COLORS = new ArrayList(2);
/**
* 字体库
*/
private static final java.util.List FONTS = new ArrayList(3);
static {
COLORS.add(new Color(24, 78, 190));
FONTS.add(new Font("Geneva", 2, 48));
}
public CustomCaptchaServlet() {
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
if (this.getInitParameter("captcha-height") != null) {
_height = Integer.valueOf(this.getInitParameter("captcha-height")).intValue();
}
if (this.getInitParameter("captcha-width") != null) {
_width = Integer.valueOf(this.getInitParameter("captcha-width")).intValue();
}
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
DefaultWordRenderer wordRenderer = new DefaultWordRenderer(COLORS, FONTS);
//定义验证码
Captcha captcha = (new Captcha.Builder(_width, _height)).addText(new
CustomTextProducer(), wordRenderer)
.addBackground(new FlatColorBackgroundProducer(new Color(255, 255, 255)))
.addNoise(new
CurvedLineNoiseProducer(COLORS.get(0), 3.0F)).gimp
(new
RippleGimpyRenderer())
.build();
//生成图片
CaptchaServletUtil.writeImage(resp, captcha.getImage());
//写入 Session
req.getSession().setAttribute("simpleCaptcha", captcha);
} catch (Exception e) {
logger.error("自定义验证码生成规则", e);
}
}
}
- 在 COLORS 字符集中,我们可以指定验证码颜色,支持多种颜色。
- 在 FONTS 字体库中,我们可以指定验证码字体,支持多种字体。
- 为 DefaultWordRenderer 方法传入 COLORS 与 FONTS 参数,新建 DefaultWordRenderer 实例。
- 使用 Captcha.Builder() 创建 Captcha 实例。
- Captcha.Builder() 支持链式调用。它支持以下方法:
方法 | 说明 |
---|---|
addText() | 添加验证码字符。 |
addBackground() | 添加背景色。 |
addNoise() | 添加干扰线,在此我们添加了一段弯曲的线条作为干扰线。如果想要添加多个线条,那么可以多次调用 addNoise()。还支持直线干扰线(StraightLineNoiseProducer)。 |
gimp() | 添加滤镜,在此我们使用了波浪纹效果 RippleGimpyRenderer。 |
3 配置 web.xml
在 web.xml 配置 servlet,让生成验证码功能成为服务,供前端调用:
StickyCaptcha
com.deniro.jail.web.sys.CustomCaptchaServlet
width
75
height
24
StickyCaptcha
/stickyImg
4 引入页面
在登录页中加入验证码输入框与验证码图片显示功能:
5 加入验证逻辑
//检查验证码是否正确
Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
if (validateCode == null || !captcha.isCorrect(validateCode)) {
return fail("验证码不正确!");
}
从 Session 中取出验证码对象,判断前端传过来的验证码字符是否正确。
6 效果
7 锦上添花
当鼠标移动到验证码图片时,自动弹出友好提示,当用户点击验证码时,更换图片。
这里的提示用的是 Opentip 组件。
初始化验证码:
initValidateCode: function () {
var that = this;
var $codeImg = $("#codeImg");
var codeImgTip = new Opentip($codeImg, {showOn: null, style: 'dark'});//验证码图片提示
$codeImg.click(function () {//点击验证码更新图片
that.changeValidateCode($(this));
//$(this).attr("src", that.context_path + '/stickyImg?' + Math.floor(Math.random() * 100));
codeImgTip.hide();
}).mouseover(function () {//出现提示
$codeImg.addClass("onElement");
codeImgTip.setContent("看不清,换一张");
codeImgTip.show();
}).mouseout(function () {//隐藏提示
$codeImg.removeClass("onElement");
codeImgTip.hide();
});
}
改变验证码:
/**
* 改变验证码
* @param $codeImg 验证码对象
*/
changeValidateCode: function ($codeImg) {
$codeImg.attr("src", this.context_path + '/stickyImg?' + Math.floor(Math.random() * 100));
}
8 其它效果
8.1 阴影效果
new DropShadowGimpyRenderer()
8.2 鱼眼效果
Captcha captcha = (new Captcha.Builder(_width, _height)).addText(new
CustomTextProducer(), wordRenderer)
.addBackground(new FlatColorBackgroundProducer(new Color(255, 255, 255)))
.gimp
(new
FishEyeGimpyRenderer())
.build();
因为鱼眼效果本身已经很复杂咯,所以这里去除了干扰线。
8.3 复杂波浪效果
图片字符像水波一样变形甚至发生部分重影现象,所以用这个滤镜时,要注意字符集只使用一些简单的字符。
new ShearGimpyRenderer()
8.4 抓取效果
图片字符像被猫抓过了一样,所以用这个滤镜时,也要注意字符集的使用。
new StretchGimpyRenderer()
8.5 多条干扰线
Captcha captcha = (new Captcha.Builder(_width, _height)).addText(new
CustomTextProducer(), wordRenderer)
.addBackground(new FlatColorBackgroundProducer(new Color(255, 255, 255)))
.addNoise(new
CurvedLineNoiseProducer(COLORS.get(0), 3.0F))
.addNoise(new
CurvedLineNoiseProducer(COLORS.get(0), 3.0F))
.gimp
(new
RippleGimpyRenderer())
.build();
是不是很酷呀 O(∩_∩)O哈哈~