说说如何在登录页实现生成验证码功能

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<Color> COLORS = new ArrayList(2);

    /**
     * 字体库
     */
    private static final java.util.List<Font> 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);
        }
    }
}
复制代码
  1. 在 COLORS 字符集中,我们可以指定验证码颜色,支持多种颜色。
  2. 在 FONTS 字体库中,我们可以指定验证码字体,支持多种字体。
  3. 为 DefaultWordRenderer 方法传入 COLORS 与 FONTS 参数,新建 DefaultWordRenderer 实例。
  4. 使用 Captcha.Builder() 创建 Captcha 实例。
  5. Captcha.Builder() 支持链式调用。它支持以下方法:
方法 说明
addText() 添加验证码字符。
addBackground() 添加背景色。
addNoise() 添加干扰线,在此我们添加了一段弯曲的线条作为干扰线。如果想要添加多个线条,那么可以多次调用 addNoise()。还支持直线干扰线(StraightLineNoiseProducer)。
gimp() 添加滤镜,在此我们使用了波浪纹效果 RippleGimpyRenderer。

3 配置 web.xml

在 web.xml 配置 servlet,让生成验证码功能成为服务,供前端调用:

<!-- 验证码-->
<servlet>
	<servlet-name>StickyCaptcha</servlet-name>
	<servlet-class>com.deniro.jail.web.sys.CustomCaptchaServlet</servlet-class>
	<init-param>
		<param-name>width</param-name>
		<param-value>75</param-value>
	</init-param>
	<init-param>
		<param-name>height</param-name>
		<param-value>24</param-value>
	</init-param>
</servlet>
<servlet-mapping>
	<servlet-name>StickyCaptcha</servlet-name>
	<url-pattern>/stickyImg</url-pattern>
</servlet-mapping>
复制代码

4 引入页面

在登录页中加入验证码输入框与验证码图片显示功能:

<input class="field" type="text" id="validateCode" name="validateCode"
	  value=""
	  placeholder="验证码">
<img id="codeImg" src="${contextPath}/stickyImg"
							 alt="" width="150" height="24"/>
复制代码

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哈哈~

猜你喜欢

转载自juejin.im/post/5b9c7bcbe51d450e597b2278
今日推荐