JavaWeb之验证码识别

举报
运气男孩 发表于 2021/11/26 14:51:46 2021/11/26
【摘要】 开发环境首先来介绍一下我此次使用的工具以及环境,没有的可以去官网自行下载使用。jdk:1.8开发工具:IntelliJ IDEA 2020.1 x64服务器:TomCat8.5效果图分析:实现这个效果,首页得有这个界面吧,在index.jsp里写就行就行,一个input输入框,一个image,一个a标签,再一个button提交按钮,再添加js的onclick事件;再来说说逻辑上的思路,我们平...

开发环境

首先来介绍一下我此次使用的工具以及环境,没有的可以去官网自行下载使用。

jdk:1.8

开发工具:IntelliJ IDEA 2020.1 x64

服务器:TomCat8.5

效果图

分析:实现这个效果,首页得有这个界面吧,在index.jsp里写就行就行,一个input输入框,一个image,一个a标签,再一个button提交按钮,再添加js的onclick事件;再来说说逻辑上的思路,我们平时登录应用程序,这个验证码肯定都是随机生成,所以这里我们也要随机生成,使用java的Random()生成,要将数字和字符混合在一起随其生成的验证码,同时还需要给它添加干扰线,防止非真人的机器识别。

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang=" en">

    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script type="text/javascript">

            function changeImg() {
                document.getElementById("validateCodeImg").src = "/generateCode?" + Math.random();
            }
        </script>
    </head>

    <body>
        <form action="/checkCode" method="post">
            验证码:<input type="text" name="validateCode" />
            <img alt="验证码看不清,换一张" src="/generateCode" id="validateCodeImg" onclick="changeImg()">
            <a href="javascript:void(0)" onclick="changeImg()">看不清,换一张</a>
            <br />
            <input type="submit" value="提交">
        </form>
    </body>

    </html>

我将整个项目依次分成9个步骤来写

1.在内存中生成一张图片

2.获取内存中的图片

3.设置图片背景

4.设置图片边框

5.设置干扰线

6.获取验证码内容

7.将验证码保存到session

8.设置浏览器以图片格式读取验证码

9.将验证码发送给浏览器

首先创建一个GenerateCode类,继承HttpServlet,定义两个私有变量:width,height 用来表示图片的宽高,重写doGet和doPost方法

 private  static  final  int WIDTH =120;//设置图片宽度
    private  static  final  int HEIGHT =30;//设置图片高度

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       this.doPost(req,resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1-9步
    }

1.在内存中生成一张图片

BufferedImage bufferedImage = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);

Image是一个抽象类,BufferedImage是其实现类,是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中(BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便地操作这个图片),提供获得绘图对象、图像缩放、选择图像平滑度等功能,通常用来做图片大小变换、图片变灰、设置透明不透明等。

BufferedImage.TYPE_INT_RGB : 表示一个图像,该图像具有整数像素的 8 位 RGB 颜色

2.获取内存中的图片

Graphics graphics = bufferedImage.getGraphics();

getGraphics()调用此方法相当于给了你一只画笔让你使用。得到画笔后你可以用它画图形,将获取到的图片画出来。

3.设置图片背景

setBackground(graphics);

这里是自定义了一个setBackground方法,设置一下验证码背景的颜色为白色,然后填充

 /**
     * 设置验证码背景
     * @param graphics
     */
    private void setBackground(Graphics graphics){
        graphics.setColor(Color.WHITE);//设置颜色

        graphics.fillRect(0,0,WIDTH,HEIGHT);//填充图片

    }

4.设置图片边框

 setBorder(graphics);

也是定义了一个setBorder方法,为graphics这个图片对象添加边框,也就是咱们的验证码图片添加一个边框

 /**
     * 设置边框
     * @param graphics
     */
    private void setBorder(Graphics graphics){
        graphics.setColor(Color.BLUE);

        //画边框
        graphics.drawRect(1,1,WIDTH-2,HEIGHT-2);
    }

5.设置干扰线

setRandomLine(graphics);

同理,调用封装好的setRandomLine方法,干扰线颜色为绿色

 /**
     * 设置干扰线
     * @param graphics 图片对象
     */
    private  void setRandomLine(Graphics graphics){
        //设置颜色
        graphics.setColor(Color.GREEN);

        //画干扰线
        for (int i = 0; i < 5; i++) {
            int x1 = new Random().nextInt(WIDTH);//0-120之间,不包括120
            int y1 = new Random().nextInt(HEIGHT);
            int x2 = new Random().nextInt(WIDTH);
            int y2 = new Random().nextInt(HEIGHT);
            graphics.drawLine(x1,y1,x2,y2);


        }


    }

6.获取验证码内容

String randomString =getRandomString((Graphics2D) graphics,"mixed");

用字符串来保存验证码内容,调用封装好的getRandomString方法传达验证码的类型,这里选择的是数字+字母混合,然后返回的是随机字符串,通过类型的判断也调用了setRandomString()返回验证码字符串

 /**
     * 获取随机字符串
     * @param graphics 图片对象
     * @param type 随机字符串类型
     * @return 随机字符串
     */
    private String getRandomString(Graphics graphics, String type) {
        //设置颜色
        graphics.setColor(Color.RED);

        //设置字体
        graphics.setFont(new Font("宋体",Font.BOLD,20));

        String number = "0123456789";
        String character = "ABCDEFGHIJKLMNOPQRSTUVWSXYZ";
        String mixed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWSXYZ";

        if("number".equals(type)){
            //生成纯数字验证码
            return setRandomString((Graphics2D) graphics,number);
        }else if("character".equals(type)){
            return setRandomString((Graphics2D) graphics,character);
        }else {
            return setRandomString((Graphics2D) graphics,mixed );
        }

    }


/**
     * 生成验证码字符串
     * @param graphics 图片对象
     * @param level 类型
     * @return 验证码字符串
     */
    private String setRandomString(Graphics2D graphics, String level) {
        //用于存储生成的随机字符串
        StringBuilder stringBuilder = new StringBuilder();

        int x =5;
        String ch = "";

        //生成随机单词
        for (int i = 0; i < 4; i++) {
            //设置旋转角度
           int degree= new Random().nextInt() % 30;

           //获取随机字母
            ch = level.charAt(new Random().nextInt(level.length())) +"";
            stringBuilder.append(ch);

            //设置正向旋转
            graphics.rotate(degree * Math.PI /180,x,20);
            graphics.drawString(ch,x,20);
            //设置反向旋转
            graphics.rotate(-degree * Math.PI /180,x,20);
            x += 30;


        }
        return stringBuilder.toString();
    }

7.将验证码保存到session

req.getSession().setAttribute("yunqinanhai",randomString);

8.设置浏览器以图片格式读取验证码

resp.setContentType("image/jpg");

9.将验证码发送给浏览器

ImageIO.write(bufferedImage,"jpg",resp.getOutputStream());

到这里验证码的生成和回传以及干扰线等都写完了,接下来要写一个验证类,用来验证用户输入的验证码是否正确?

创建一个CheckCode类,继承HttpServlet,重写doGet,doPost方法

在doPost方法里写验证程序,doGet里写this.doPost(req, resp);

为防止编码错误,这里将编码设置为UTF-8,通过index.jsp的输入框属性绑定,获取用户输入的验证码,创建一个字符串来获取session里的验证码数据,再通过equals判断是否正确

注意:由于验证码应该不区分大小写,所以这里不能使用equals()来判断两个验证码是否相等,要用equalsIgnoreCase()来判断

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        resp.setCharacterEncoding("UTF-8");
        //获取用户输入的验证码
        String validateCode = req.getParameter("validateCode");

        String yunqinanhai = (String) req.getSession().getAttribute("yunqinanhai");

        if(validateCode.equalsIgnoreCase(yunqinanhai)){
            resp.getWriter().println("验证码正确");
        }else{
            resp.getWriter().println("验证码错误");
        }
    }

最后,为了让index.jsp找到对应的java文件,需要添加映射路径:

@WebServlet("/generateCode")

@WebServlet("/checkCode")

到这里,这个项目基本完成了,现在run一下tomcat服务器,默认跳转index.jsp。端口号默认是8080

点击图片或者旁边的文字均可以换一张验证码

现在我们来验证是不是区分大小写了

不出所料,确实区分大小写了,此次关于验证码的生成与验证就到这里结束了。感恩能与大家在华为云遇见!希望能与大家一起在华为云社区共同成长。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。