← 返回首页
Servlet基础教程(二十二)
发表时间:2020-04-10 01:23:23
讲解Servlet 实现验证码

验证码存在的意义:不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了验证码技术。所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息,输入表单提交网站验证,验证成功后才能使用某项功能。

1.实现步骤

1)前端静态页面代码(validate.html)

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>验证码案例</h1>
<hr>

<form action="checkVerifyCode" method="get">
    <!--src为图片生成的Servlet,onclick实现函数变换img的src-->
    <img src="verifyCodeImg" alt="Loading" onclick="changeCode()" id="verifyCode" title="看不清楚,换一张" style="cursor: pointer;">
    <!--用户输入-->
    <input type="text" name="randomCode" id="userCode"><br><br>
    <input type="submit" value="提交验证"><br><br>
</form>

<script>
    function changeCode() {
        let codeImg=document.getElementById("verifyCode");
        //这里URL后追加随机数,使程序每次访问的都是不同的资源,防止浏览器缓存,即产生不同的验证码
        codeImg.src="verifyCodeImg?d="+Math.random();
    }
</script>
</body>
</html>

2)编写VerifyCodeImgServlet,用来生成验证码图片的Servlet.

package com.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet(name = "VerifyCodeImgServlet",value="/verifyCodeImg",loadOnStartup = 1)
public class VerifyCodeImgServlet extends HttpServlet {
    private static final int WIDTH = 100;//设置验证码图片宽度
    private static final int HEIGHT = 30;//设置验证码图片高度
    private static final int LENGTH = 4;//设置验证码长度
    public static final int LINECOUNT=20;//干扰线的数目

    //验证码的字符库
    private static final String str="0123456789"+
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
            "abcdefghijklmnopqrstuvwxyz";

    //通过随机数取字符库中的字符组合成4位验证码
    private static Random random=new Random();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置数据类型为图片
        resp.setContentType("image/jpeg");

        //设置不进行缓存
        resp.setHeader("pragma", "no-cache");
        resp.setHeader("cache-control", "no-cache");
        resp.setHeader("expires", "0");



        //获取画笔
        BufferedImage image=new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_3BYTE_BGR);
        Graphics g=image.getGraphics();

        //设置背景颜色并绘制矩形背景
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        //验证码的绘制
        String code=drawChar(g);
        System.out.println("验证码:"+code);


        //随机线的绘制
        for (int i=0;i<LINECOUNT;i++){
            drawLine(g);
        }

        //在session中存入当前的code码,便于验证
        req.getSession().setAttribute("code",code);

        //绘制图片
        g.dispose();

        //将图片输出到response中
        ImageIO.write(image, "JPEG", resp.getOutputStream());
    }


    //获取不同颜色
    public  Color getColor(){
        return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
    }

    //获取字体样式
    public Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 20);
    }

    //绘制字符
    public String drawChar(Graphics g){
        String code="";
        g.setFont(getFont());
        for (int i=0;i<LENGTH;i++){
            char c=str.charAt(random.nextInt(str.length()));
            g.setColor(getColor());
            g.drawString(c+"", 20* i + 10, 20);
            code=code+c;
        }
        return code;
    }

    //绘制随机线
    public  void drawLine(Graphics g) {
        int x = random.nextInt(WIDTH);
        int y = random.nextInt(HEIGHT);
        int xl = random.nextInt(13);
        int yl = random.nextInt(15);
        g.setColor(getColor());
        g.drawLine(x, y, x + xl, y + yl);
    }
}

3)编写CheckVerifyCodeServlet,用来验证用户输入的验证码是否正确。

package com.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "CheckVerifyCodeServlet",value="/checkVerifyCode")
public class CheckVerifyCodeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //返回的信息提示
        String messageShow="";

        //用户输入的验证码
        String userCode = request.getParameter("randomCode");

        //VerifyCodeImg存在session中的验证码
        String rightCode=null;
        Object code = request.getSession().getAttribute("code");
        if(code!=null){
            rightCode=(String) code;
        }

        //用户输入和生成验证码的比较,并生成不同的信息提示
        if(userCode.equalsIgnoreCase(rightCode)){
            System.out.println("验证成功!!!");
        }else{
            System.out.println("验证失败!!!");
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

4)测试

输入:XU2D

控制台输出效果:

验证成功!!!

2.servlet实现的验证码执行流程分析

当然验证码的实现技术除了后端技术实现外也可以使用前端技术实现。项目开发时通常使用第三方的验证码组件实现。