Javaweb生成验证码实例操作以及kaptcha框架使用

验证码是网页中很常见的一个功能,基本所有实现都需验证码验证;

接下来就是如何实现基本的验证码的生成:

基本普通验证码

1.首先定义一个用来生成验证码的JAVA基本类:

package cn.java.code;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Random;

/*
    制作验证码工具类,进行验证码验证;
 */
public class CaptcahCode {
    /**
     * 验证码数据流生成
     * 后面进行生成一个图片;只需要获取名称前端调用即可
     * @param response
     * @return
     */
    public static String dramCodeImg(HttpServletResponse response){
        //进行随机数的生成,就是对随机生成的数进行一个拼接;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4; i++) {
            sb.append(randomCode());
        }
        String code =  sb.toString();

        //进行一个图片的编写;
        //1.定义图片的高度和宽度:
        int width = 300;
        int height = 150;
        //2.设置bufferImg对象,制作图片的宽度,长度以及色彩,这个是新内容需要加强学习
        BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);//需要传入图片的宽度,高度,类型等内容
        //3.获取Graphics2D绘制对象,绘制验证码
        Graphics2D gra = bi.createGraphics();//拿到内存对象
        //4.设置文字的颜色和大小
        Font font = new Font("微软雅黑",Font.PLAIN,30);
        //5.设置字体的颜色
        Color color = new Color(0,0,0);
        //设置字体,设置颜色
        gra.setFont(font);
        gra.setColor(color);
        //设置背景颜色
        gra.setBackground(new Color(226,226,240));
        //开始绘制对象
        gra.clearRect(0,0,width,height);
        //6.绘制形状,一般是矩形,这边也进行一个矩形绘制,拿到一个矩形对象
        //首先需要获取内容对象
        FontRenderContext context = gra.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(code,context);//数据内容的传输
        //7.计算文件的坐标和间距
        double x = (width - bounds.getWidth())/2;
        double y = (height - bounds.getHeight())/2;
        //y坐标比较特殊需要进行一个获取值
        double asscent = bounds.getY();
        double baseY = y -asscent;
        //进行内容的编辑
        gra.drawString(code,(int)x,(int)baseY);
        //8.结束编辑
        gra.dispose();
        //9.进行图片的保存,也是最一步
        try{
            ImageIO.write(bi, "jpg", response.getOutputStream());
            //10.刷新响应流
            response.flushBuffer();
        }catch(Exception ex)
        {
            ex.printStackTrace();
        }
        return  code;//进行验证码和验证码存储地方一个返回;
    }

    /**
     * 生成一个随机数,从a-z,1-9
     * @return
     */
    private static char randomCode(){
        //1.定义验证的需要的字母和数字
        String string = "QWERTYUIOPASDFGHJKLZXCVBNM123456789";
        //2.进行一个随机的抽取,需要使用random
        Random random = new Random();
        return string.charAt(random.nextInt(string.length()));
    }

    public static void main(String[] args) {
        System.out.println(dramCodeImg(null));//I8D15是可以随机生成;
    }
}

其中用了几个以前不常用的工具:

BufferedImage//需要传入图片的宽度,高度,类型等内容
Graphics2D//获取Graphics2D绘制对象,绘制验证码
Font //设置文字的颜色和大小
Color //设置字体的颜色
FontRenderContext//首先需要获取内容对象
Rectangle2D //数据内容的传输
ImageIO.write(bi, "jpg", respo//进行图片的保存,也是最一步

然后就可以进行前端的调用
进验证码生成页面定义:

<%@ page import="cn.java.code.CaptcahCode" %><%
    //验证码使用的时候要记住清楚浏览器的缓存,不然会导致验证码不刷新;
    response.setHeader("pragma","no-cache");
    response.setHeader("cache-control","no-cache");
    response.setHeader("expires","0");

    //调用验证码生成工具
    String code = CaptcahCode.dramCodeImg(response);
    //最后将验证码生成路径存储在session中
    session.setAttribute("code",code);

    //3.关于解决getOutPutStream问题
    out.clear();
    out = pageContext.pushBody();
%>

之后进行数据的调用:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>验证码生成测试</title>
  </head>
  <body>
    <img src="code.jsp" alt="" id="code"/>
    <a href="javascript:void(0);" onclick="changerCode()">看不清楚?换一张验证码</a>
    <script type="application/javascript">
        function  changerCode() {
          //对图片进行重新发送请求,需要进行不同数据的发送
          document.getElementById("code").src = "code.jsp?d="+new Date().getTime();
        }
    </script>
  </body>
</html>

其中js中为了进行验证码的刷新进行操作;
实现效果:
在这里插入图片描述

算数验证码生成

关于算数验证码的随机生成:
接上面的代码,具体实现随机验证码Java:

/**
     * 算术表达式验证码生成;可以生成随机数,随机颜色等内容
     *
     * 干扰线的绘制,绘制验证码中的线条
     * @param response
     * @return
     */
    public static String drawImgVerificate(HttpServletResponse response)
    {
        int width = 300;
        int height = 150;
        //在内存中创建图片
        BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //创建图片上下文
        Graphics2D gp = bufferedImage.createGraphics();
        //生成随机对象,用于生成随机的算术表达式
        Random random = new Random();
        //设置背景颜色
        gp.setColor(setRandomColor(120,110));
        Font font = new Font("微软雅黑",Font.PLAIN,30);
        //设置字体
        gp.setFont(font);
        //开始绘制
        gp.fillRect(0,0,width,height);

        //干扰线的编写,绘制在图片中
        gp.setColor(setRandomColor(180,110));
        //随机生成100条随机线
        for (int i = 0; i < 100; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int x1 = random.nextInt(60);
            int y1 = random.nextInt(60);
            gp.drawLine(x,y,x1,y1);//对线条的绘制,利用两点生成一条直线
        }

        //进行算术验证码的生成
        int num1= (int)(Math.random()*100 + 1);
        int num2 = (int)(Math.random()*100 + 1);
        String fuhaoStr = "";
        int result = 0;//用来记录运行值
        //对随机符号的生成
        int fuhao = random.nextInt(3); //一般只生成3个,加减乘
        switch (fuhao)
        {
            case 0:fuhaoStr = "+";result = num1 + num2;break;
            case 1:fuhaoStr = "-";result = num1 - num2;break;
            case 2:fuhaoStr = "*";result = num1 * num2;break;
            default:break;
        }
        //拼接表达式,用户用图片显示
        String code = num1 + " " + fuhaoStr + " " + num2 + " = ?";
        //设置随机颜色
        gp.setColor(new Color(20+random.nextInt(110),20+random.nextInt(200),30+random.nextInt(150)));
        //计算图像内容
        FontRenderContext context = gp.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(code,context);//数据内容的传输
        //7.计算文件的坐标和间距
        double x = (width - bounds.getWidth())/2;
        double y = (height - bounds.getHeight())/2;
        //y坐标比较特殊需要进行一个获取值
        double asscent = bounds.getY();
        double baseY = y -asscent;
        //绘制表达式
        gp.drawString(code,(int)x,(int)baseY);
        //结束绘制
        gp.dispose();
        try {
            ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
            return  String.valueOf(result);//返回一个表达值;
        }catch (Exception ex){
            ex.printStackTrace();
            return  null;
        }
    }

    /**
     * 随机生成颜色;特定范围内随机
     * @param fc
     * @param bc
     * @return
     */
    private static Color setRandomColor(int fc,int bc){
        //利用随机数进行生成随机颜色,颜色rgb是0-255随机数
        Random random = new Random();
        if(fc > 255) fc = 255;
        if(bc > 255) bc = 255;
        int g = fc+random.nextInt(fc-bc);
        int r = fc+random.nextInt(fc-bc);
        int b = fc+random.nextInt(fc-bc);
        return new Color(r,g,b);
    }

添加了线条干扰和颜色随机的功能,这样子就可以很轻松的实现了;

//计算图像内容
        FontRenderContext context = gp.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(code,context);//数据内容的传输
        //7.计算文件的坐标和间距
        double x = (width - bounds.getWidth())/2;
        double y = (height - bounds.getHeight())/2;
        //y坐标比较特殊需要进行一个获取值
        double asscent = bounds.getY();
        double baseY = y -asscent;
        //绘制表达式
        gp.drawString(code,(int)x,(int)baseY);

在实现验证码居中过程中需要这个来辅助使用,前端调用和上面的步骤一样;
实现效果:点击字体可以实现更换操作
在这里插入图片描述

使用框架生成验证码,建议使用这种,使用kaptcha框架

详细看博客

这边对基本配置以及使用idea的一个讲解:
1.配web.xml内容,进行包的引用,配置内容也在这里面

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <servlet>
        <servlet-name>Kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<!--        宽度-->
        <init-param>
            <param-name>kaptcha.image.width</param-name>
            <param-value>200</param-value>
        </init-param>
<!--        验证码图高度-->
        <init-param>
            <param-name>kaptcha.image.height</param-name>
            <param-value>50</param-value>
        </init-param>
<!--        验证码长度-->
        <init-param>
            <param-name>kaptcha.textproducer.char.length</param-name>
            <param-value>5</param-value>
        </init-param>
<!--        干扰实列类-->
        <init-param>
            <param-name>kaptcha.noise.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.DefaultNoise</param-value>
        </init-param>
<!--        验证码边框-->
        <init-param>
            <param-name>kaptcha.border</param-name>
            <param-value>yes</param-value>
        </init-param>
<!--        字体间的间隔-->
        <init-param>
            <param-name>kaptcha.textproducer.char.space</param-name>
            <param-value>4</param-value>
        </init-param>
<!--        图片背景样式-->
        <init-param>
            <param-name>kaptcha.obscurificator.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.WaterRipple</param-value>
        </init-param>
<!--        背景实例化类-->
        <init-param>
            <param-name>kaptcha.background.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.DefaultBackground</param-value>
        </init-param>
<!--        详细需要去看谷歌实现:
            http://code.google.com/p/kaptcha/wiki/ConfigParameters
-->
    </servlet>
    <servlet-mapping>
        <servlet-name>Kaptcha</servlet-name>
        <url-pattern>/Kaptcha.jpg</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>cn.java.Servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
</web-app>

讲解使用过程中遇见的问题,以及解决:
在这里插入图片描述
jar包放置正确但是没有找到,问题解决:
在这里插入图片描述
需要进行一个仓库的添加,不然不可以使用,idea没有自动导包路径操作;
2.引用后也可能出现不可以使用,需要进行下面的配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
之后就可以使用了;
后端编写验证条件,后端编写的servlet处理需要配置web.xml路径才可以调用

package cn.java.Servlet;

import com.google.code.kaptcha.Constants;

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;
import java.io.PrintWriter;

@WebServlet(name = "LoginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        //获取浏览器输出流对象,可以直接给浏览器返回一个值
        PrintWriter out = response.getWriter();
        String code = request.getParameter("code");//获取输入框的值
        String seessionCode = (String)request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if(code != null && seessionCode != null)
        {
            //如果验证码比对正确返回一个成功值
            if(code.equalsIgnoreCase(seessionCode))
            {
                //忽略大小写验证
                out.print("success");
            }else{
                out.print("fail");
            }
        }else {
            out.print("fail");
        }
        System.out.println("sessionCode="+seessionCode);

        //使用过后需要进行关闭
        out.flush();
        out.close();
    }

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

    }
}

前端的调用,以及基本验证:

<%--
  Created by IntelliJ IDEA.
  User: XXXIERW
  Date: 2020/7/9
  Time: 15:23
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>kaptcha验证码生成框架使用</title>
    <script src="/js/jquerymin.min.js"></script>
</head>
<body>
    <form action="submit.action">
        <input type="text" name="kaptcha" value="" id="code"/>
        <img src="/Kaptcha.jpg" alt="图片加载失败" height="50px" width="100px" id="changeImg"/>
        <br/>
        <br/>
        <input type="button" value="登录" id="login"/>
        <br/>
        <h5 id="result"></h5>
    </form>
<%--利用jquery进行一个简单的后端交互--%>
<script>
    $(function () {
        $("#changeImg").on("click",function () {
            $(this).attr("src","/Kaptcha.jpg?d="+ new Date().getTime())//使用时间戳来改变状态
        });

        //进行登录验证
        $("#login").on("click",function () {
            var code = $("#code").val();
            //然后进行异步发送请求
            var params = {"code":code};
            $.post("/login",params,function (data) {
                //接收一个返回值
                if(data == "success") {
                    $("#result").html("验证码输入正确");
                }else{
                    $("#result").html( "验证码输入错误,请重新输入");
                    //获取焦点并且重新刷新验证码
                    $("#code").val("").focus();
                    //延时自动刷新
                    //setTimeout(function (){window.location.reload(),1500});
                }
            })
        })
    })
</script>
</body>
</html>

最后就可以实现如下效果:
在这里插入图片描述
在这里插入图片描述
使用框架会大大降低开发的复杂程度,也建议使用框架,但是导包出现的bug也是很多的,这边是我遇见的问题已经都写在上面了,所以更多东西还是需要不断发展;

下面是对kaptcha框架几个基本配置的讲解

Kaptcha是一个基于SimpleCaptcha的验证码开源项目。
官网地址:http://code.google.com/p/kaptcha/

kaptcha的使用比较方便,只需添加jar包依赖之后简单地配置就可以使用了。kaptcha所有配置都可以通过web.xml来完成,如果你的项目中使用了Spring MVC,那么则有另外的一种方式来实现。
一、简单的jsp-servlet项目
1.添加jar包依赖
如果你使用maven来统一管理jar包,则在工程的pom.xml中添加dependency
Xml代码  收藏代码
<!-- kaptcha -->
<dependency>
    <groupId>com.google.code.kaptcha</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>
如果是非maven管理的项目,则直接在官网下载kaptcha的jar包,然后添加到项目lib库中,下载地址:http://code.google.com/p/kaptcha/downloads/list


2.配置web.xml
上面说了,kaptcha都是在web.xml中配置,我们必须在web.xml中配置kaptcha的servlet,具体如下:
Xml代码  收藏代码
<servlet>
    <servlet-name>Kaptcha</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Kaptcha</servlet-name>
    <url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
其中servlet的url-pattern可以自定义。

kaptcha所有的参数都有默认的配置,如果我们不显示配置的话,会采取默认的配置。
如果要显示配置kaptcha,在配置kaptcha对应的Servlet时,在init-param增加响应的参数配置即可。示例如下:
Xml代码  收藏代码
<servlet>
    <servlet-name>Kaptcha</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
    <init-param>
        <param-name>kaptcha.image.width</param-name>
        <param-value>200</param-value>
        <description>Width in pixels of the kaptcha image.</description>
    </init-param>
    <init-param>
        <param-name>kaptcha.image.height</param-name>
        <param-value>50</param-value>
        <description>Height in pixels of the kaptcha image.</description>
    </init-param>
    <init-param>
        <param-name>kaptcha.textproducer.char.length</param-name>
        <param-value>4</param-value>
        <description>The number of characters to display.</description>
    </init-param>
    <init-param>
        <param-name>kaptcha.noise.impl</param-name>
        <param-value>com.google.code.kaptcha.impl.NoNoise</param-value>
        <description>The noise producer.</description>
    </init-param>
</servlet>
具体的配置参数参见:http://code.google.com/p/kaptcha/wiki/ConfigParameters

Constant	描述	默认值
kaptcha.border	图片边框,合法值:yes , no	yes
kaptcha.border.color	边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue.	black
kaptcha.border.thickness	边框厚度,合法值:>0	1
kaptcha.image.width	图片宽	200
kaptcha.image.height	图片高	50
kaptcha.producer.impl	图片实现类	com.google.code.kaptcha.impl.DefaultKaptcha
kaptcha.textproducer.impl	文本实现类	com.google.code.kaptcha.text.impl.DefaultTextCreator
kaptcha.textproducer.char.string	文本集合,验证码值从此集合中获取	abcde2345678gfynmnpwx
kaptcha.textproducer.char.length	验证码长度	5
kaptcha.textproducer.font.names	字体	Arial, Courier
kaptcha.textproducer.font.size	字体大小	40px
kaptcha.textproducer.font.color	字体颜色,合法值: r,g,b  或者 white,black,blue.	black
kaptcha.textproducer.char.space	文字间隔	2
kaptcha.noise.impl	干扰实现类	com.google.code.kaptcha.impl.DefaultNoise
kaptcha.noise.color	干扰颜色,合法值: r,g,b 或者 white,black,blue.	black


kaptcha.obscurificator.impl	图片样式:
水纹com.google.code.kaptcha.impl.WaterRipple
鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
阴影com.google.code.kaptcha.impl.ShadowGimpy


com.google.code.kaptcha.impl.WaterRipple
kaptcha.background.impl	背景实现类	com.google.code.kaptcha.impl.DefaultBackground
kaptcha.background.clear.from	背景颜色渐变,开始颜色	light grey
kaptcha.background.clear.to	背景颜色渐变,结束颜色	white
kaptcha.word.impl	文字渲染器
com.google.code.kaptcha.text.impl.DefaultWordRenderer
kaptcha.session.key	session key	KAPTCHA_SESSION_KEY
kaptcha.session.date	session date	KAPTCHA_SESSION_DATE

3.页面调用
Html代码  收藏代码
<form action="submit.action">
    <input type="text" name="kaptcha" value="" /><img src="kaptcha.jpg" />
</form>
4.在submit的action方法中进行验证码校验
Java代码  收藏代码
//从session中取出servlet生成的验证码text值
String kaptchaExpected = (String)request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
//获取用户页面输入的验证码
String kaptchaReceived = request.getParameter("kaptcha");
//校验验证码是否正确
if (kaptchaReceived == null || !kaptchaReceived.equalsIgnoreCase(kaptchaExpected)){
    setError("kaptcha", "Invalid validation code.");
}
注:确保JDK设置了 -Djava.awt.headless=true
5.实现页面验证码刷新
Html代码  收藏代码
<img src="kaptcha.jpg" width="200" id="kaptchaImage" title="看不清,点击换一张" />
<script type="text/javascript">
    $(function() {
        $('#kaptchaImage').click(function() {$(this).attr('src','kaptcha.jpg?' + Math.floor(Math.random() * 100));});
    });
</script>
<br /><small>看不清,点击换一张</small>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值