說說如何在登入頁實現生成驗證碼功能

deniro發表於2019-02-25

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

相關文章