Springboot 生成字符串,运算,滑动验证码

发布时间:2021-12-13
技术:springboot+kaptcha+session+字符串,运算,滑动验证码

概述

场景介绍 验证码,用于web网站。用户点击验证码图片后,生成验证码。提交后,用户输入验证码和Session验证码,进行校验。

详细

功能演示

一、目录结构

验证码.png

二、功能讲解

(1)字符串验证码

@Controller
public class CharVerificationCodeController {


    @RequestMapping(value = {"/"})
    public String index() {
        return "/index";
    }

     //--------------------------------------字符验证码开始--------------------------------------
    /**
     * 字符验证码Session
     */
    public static final String SESSION_CHAR_VERIFICATION_CODE = "session_char_verification_code";
    /**
     * 字符验证码图片
     */
    @RequestMapping(value = {"/charVerificationCode"})
    public void charVerificationCode(HttpServletRequest request, HttpServletResponse response) throws Exception{
        HashMap<String,Object> verificationCodeMap = CharVerificationCodeUtil.charVerificationCode();
        CommonUtil.validateCode(request,response,verificationCodeMap,SESSION_CHAR_VERIFICATION_CODE);
    }
    /**
     * 检查字符验证码是否正确
     * validateCode 前端输入的验证码
     */
    @RequestMapping("/checkCharVerificationCode")
    @ResponseBody
    public JSONResponse checkCharVerificationCode(HttpServletRequest request,@RequestParam("charVerificationCode")String charVerificationCode) {
        String sessionVerificationCode = (String)request.getSession().getAttribute(SESSION_CHAR_VERIFICATION_CODE);
        return JSONResponse.success(checkVerificationCodeMap(sessionVerificationCode,charVerificationCode));
    }
    //--------------------------------------字符验证码结束--------------------------------------

    private HashMap<String,Object> checkVerificationCodeMap(String sessionVerificationCode,String verificationCode){
        HashMap<String,Object> returnMap = new HashMap<>();
        if(sessionVerificationCode == null){
            returnMap.put("status",null);//验证码过期
        }else if(sessionVerificationCode.equals(verificationCode)){
            returnMap.put("status",true);//验证码正确
        }else if(!sessionVerificationCode.equals(verificationCode)){
            returnMap.put("status",false);//验证码不正确
        }
        return returnMap;
    }
}

(2)运算验证码

public class OperationVerificationCodeController {


    //--------------------------------------运算验证码开始--------------------------------------
    /**
     * 运算验证码Session
     */
    public static final String SESSION_OPERATION_VERIFICATION_CODE = "session_operation_verification_code";
    /**
     * 运算验证码图片
     */
    @RequestMapping(value = {"/operationVerificationCode"})
    public void operationVerificationCode(HttpServletRequest request, HttpServletResponse response) throws Exception{
        HashMap<String,Object> verificationCodeMap = OperationVerificationCodeUtil.operationVerificationCode();
        CommonUtil.validateCode(request,response,verificationCodeMap,SESSION_OPERATION_VERIFICATION_CODE);
    }
    /**
     * 检查运算验证码是否正确
     * validateCode 前端输入的验证码
     */
    @RequestMapping("/checkOperationVerificationCode")
    @ResponseBody
    public JSONResponse checkOperationVerificationCode(HttpServletRequest request,@RequestParam("operationVerificationCode")String operationVerificationCode) {
        String sessionVerificationCode = (String)request.getSession().getAttribute(SESSION_OPERATION_VERIFICATION_CODE);
        return JSONResponse.success(checkVerificationCodeMap(sessionVerificationCode,operationVerificationCode));
    }
    //--------------------------------------运算验证码结束--------------------------------------

    private HashMap<String,Object> checkVerificationCodeMap(String sessionVerificationCode,String verificationCode){
        HashMap<String,Object> returnMap = new HashMap<>();
        if(sessionVerificationCode == null){
            returnMap.put("status",null);//验证码过期
        }else if(sessionVerificationCode.equals(verificationCode)){
            returnMap.put("status",true);//验证码正确
        }else if(!sessionVerificationCode.equals(verificationCode)){
            returnMap.put("status",false);//验证码不正确
        }
        return returnMap;
    }
}

(3)滑动验证码

@Controller
public class SlideVerificationCodeController {

    //获取端口号
    @Value("${server.port}")
    private String serverPort;

    //--------------------------------------滑动验证码开始--------------------------------------
    /**
     * 滑动验证码Session
     */
    public static final String SESSION_SLIDE_VERIFICATION_CODE = "session_slide_verification_code";

    @RequestMapping("/slideVerificationCode")
    @ResponseBody
    /**
     * 滑动验证码图片
     */
    public JSONResponse slideVerificationCode(HttpServletRequest request){
        String localPath = "http://127.0.0.1:"+serverPort+"/img/slide.jpg";
        SlideVerificationCode slideCode = SlideVerificationCodeUtil.slideVerificationCode(localPath);
        HashMap<String,Object> returnMap = new HashMap<>();
        returnMap.put("originalImage",slideCode.getOriginalImage());
        returnMap.put("cutImage",slideCode.getCutImage());
        returnMap.put("yLocation",slideCode.getyLocation());
        System.out.println("------------"+"滑动验证码:xLocation:"+slideCode.getxLocation()+"------------");
        int xLocation = (Integer) (slideCode.getxLocation());
        request.getSession().setAttribute(SESSION_SLIDE_VERIFICATION_CODE, xLocation);
        return JSONResponse.success(returnMap);
    }

    /**
     * 检查滑动验证码是否正确
     * validateCode 前端输入的x坐标
     */
    @RequestMapping("/checkSlideVerificationSlideX")
    @ResponseBody
    public JSONResponse checkSlideVerificationSlideX(HttpServletRequest request,@RequestParam("slideVerificationCode")int slideX) {
        Integer sessionVerificationSlideX = (Integer) request.getSession().getAttribute(SESSION_SLIDE_VERIFICATION_CODE);
        return JSONResponse.success(checkSlideVerificationSlideXMap(sessionVerificationSlideX,slideX));
    }

    //--------------------------------------滑动验证码结束--------------------------------------
    private HashMap<String,Object> checkSlideVerificationSlideXMap(Integer sessionVerificationSlideX,int slideX){
        int threshold = 8; //8像素的误差
        HashMap<String,Object> returnMap = new HashMap<>();
        if(sessionVerificationSlideX == null){
            returnMap.put("status",null);//验证码过期
            return returnMap;
        }

        if((Math.abs(sessionVerificationSlideX - slideX) <= threshold) ){
            returnMap.put("status",true);//验证码正确
        }else{
            returnMap.put("status",false);//验证码不正确
        }
        return returnMap;
    }
}

(4)前端页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>SpringBoot 生成验证码</title>
    <link href="/css/slider.css" rel="stylesheet">
    <script type="text/javascript" src="/js/jquery/jquery-3.3.1.min.js"></script>
    <script src="/js/slider.js"></script>
    <script type='text/javascript'>

        //--------------------------------------字符验证码开始--------------------------------------
        //绑定事件,键松开检查验证码是否正确
        $(function () {
            $("#charVerificationCodeInput").keyup(function(){
                checkCharVerificationCode($(this).val());
            });
        });

        //更新字符串验证码图片
        function uploadCharVerificationCode() {
            $("#charVerificationCode").attr("src","/charVerificationCode?random="+new Date().getMilliseconds());
        }


        //检查字符串验证码
        function checkCharVerificationCode(charVerificationCode) {
            var error = $("#charVerificationCodeError");
            if(charVerificationCode != null && charVerificationCode != ""){
                $.ajax({
                    type: "POST",
                    async:false,
                    url: "/checkCharVerificationCode?charVerificationCode="+charVerificationCode,
                    success : function(jsonData) {
                        if(jsonData.code == 200) {
                            var data = jsonData.data;
                            var status = data.status;
                            if (status == true) {
                                error.html("恭喜你,字符串验证码正确!!!!!");
                            } else if(status == false){
                                error.html("字符串验证码错误,请重新输入");
                            }else{
                                error.html("字符串验证码过期,请重新输入");
                                uploadCharVerificationCode();
                            }
                        }else{
                            alert(jsonData.message);
                        }
                        return false;
                    },
                    error:function(XMLHttpRequest,textStatus,errorThrown){
                        alert("服务器错误!状态码:"+XMLHttpRequest.status);
                        // 状态
                        console.log(XMLHttpRequest.readyState);
                        // 错误信息
                        console.log(textStatus);
                        return false;
                    }
                });
            }else{
                error.html("请输入验证码!");
            }
        }
        //--------------------------------------字符验证码结束--------------------------------------



        //--------------------------------------运算验证码开始--------------------------------------
        //绑定事件,键松开检查验证码是否正确
        $(function () {
            $("#operationVerificationCodeInput").keyup(function(){
                checkOperationVerificationCode($(this).val());
            });
        });

        //更新运算验证码图片
        function uploadOperationVerificationCode() {
            $("#operationVerificationCode").attr("src","/operationVerificationCode?random="+new Date().getMilliseconds());
        }


        //检查运算验证码
        function checkOperationVerificationCode(operationVerificationCode) {
            var error = $("#operationVerificationCodeError");
            if(operationVerificationCode != null && operationVerificationCode != ""){
                $.ajax({
                    type: "POST",
                    async:false,
                    url: "/checkOperationVerificationCode?operationVerificationCode="+operationVerificationCode,
                    success : function(jsonData) {
                        if(jsonData.code == 200) {
                            var data = jsonData.data;
                            var status = data.status;
                            if (status == true) {
                                error.html("恭喜你,运算验证码正确!!!!!");
                            } else if(status == false){
                                error.html("运算验证码错误,请重新输入");
                            }else{
                                error.html("运算验证码过期,请重新输入");
                                uploadOperationVerificationCode();
                            }
                        }else{
                            alert(jsonData.message);
                        }
                        return false;
                    },
                    error:function(XMLHttpRequest,textStatus,errorThrown){
                        alert("服务器错误!状态码:"+XMLHttpRequest.status);
                        // 状态
                        console.log(XMLHttpRequest.readyState);
                        // 错误信息
                        console.log(textStatus);
                        return false;
                    }
                });
            }else{
                error.html("请输入验证码!");
            }
        }

        //--------------------------------------运算证码结束--------------------------------------

    </script>
</head>
<body>
    <p>&nbsp;</p>
    <div>
        字符验证码: <img id="charVerificationCode" width="150" height="50"  style="cursor: pointer;" src="/charVerificationCode" onclick="uploadCharVerificationCode();">
        <p>
            验证码验证:<input type="text" id="charVerificationCodeInput"  />
        </p>
        <p id="charVerificationCodeError" style="color:red;font-weight:bold"></p>
    </div>

    <p>&nbsp;</p>
    <div>
        运算验证码: <img id="operationVerificationCode" width="185" height="50"  style="cursor: pointer;" src="/operationVerificationCode" onclick="uploadOperationVerificationCode();">
        <p>
            验证码验证:<input type="text" id="operationVerificationCodeInput"  />
        </p>
        <p id="operationVerificationCodeError" style="color:red;font-weight:bold"></p>
    </div>

    <p>&nbsp;</p>
    <div>
        滑动验证码:
        <div class="slide_img_content">
            <div class="slide_img">
                <img class="slide_refresh" src="/icon/refresh.png" onclick="uploadSlideVerificationCode();">
                <img id="cutImage" class="slide_img_mark" >
                <img id="originalImage">
            </div>

        </div>
        <div class="slider_clear">
            <div class="slider">
                <div class="slider_arror" style="cursor:pointer;" onselectstart="return false;">
                    <img style="margin-top: 5px;" id="arror_icon" src="/icon/right_arror.png" draggable="false" width="30px" height="30px">
                </div>
                <div class="slider_mask">
                </div>
                <span class="slider_tip" onselectstart="return false;">向右拖动滑块填充拼图</span>
            </div>
        </div>
        <p id="slideVerificationCodeError" style="color:red;font-weight:bold"></p>
    </div>

</body>
</html>

滑动js,slider.js

var sliderStart = false;
var x_slider,y_slider; // 鼠标最初位置
var original_image_with_slider = 300;//边界宽度 = 图片宽度 
var cut_image_width_slider = 50;//剪切图宽度
var yLocation; // 数据返回 x y

$(function(){
    uploadSlideVerificationCode();
});

function uploadSlideVerificationCode() {
    resetSlide();    //拼图验证码用---修改位置和重置颜色
    $.ajax({
            type: "POST",
            async:false,
            url: "/slideVerificationCode?random="+new Date().getMilliseconds(),
            success : function(jsonData) {
                if(jsonData.code == 200) {
                    var data = jsonData.data;
                    yLocation = data.yLocation;
                    initImgSlide(data.originalImage, data.cutImage, yLocation);
                    initMovementSlide();
                    $("#slideVerificationCodeError").html("");
                }else{
                    alert(jsonData.message);
                }
                return false;
            },
            error:function(XMLHttpRequest,textStatus,errorThrown){
                alert("服务器错误!状态码:"+XMLHttpRequest.status);
                // 状态
                console.log(XMLHttpRequest.readyState);
                // 错误信息
                console.log(textStatus);
                return false;
            }
        });
}

//图片显示使用base64时的前缀,src=base64PrefixPathSlide + imgBase64Value
var base64PrefixPathSlide="data:image/png;base64,";
// 拼图验证码用---初始化图片
function initImgSlide(originalImage, cutImage, yLocation){
    $('#originalImage').prop('src', base64PrefixPathSlide+originalImage);
    $('#cutImage').prop('src', base64PrefixPathSlide+cutImage);
    $('.slide_img_mark').css('margin-top', yLocation);
}

// 拼图验证码用---设置回调
function initMovementSlide(){
    $('.slider_arror')[0].addEventListener('mousedown', sliderPush);
    window.addEventListener('mousemove', sliderDrug);
    window.addEventListener('mouseup', sliderEnd);
}

// 拼图验证码用---按下滑动按钮回调方法
function sliderPush(e){
    sliderStart = true
    x_slider = e.clientX || e.touches[0].clientX;
    y_slider = e.clientY || e.touches[0].clientY;
    $('.slider_tip').hide();
    $('.slider_mask').css('background-color', '#deee97');
    $('#arror_icon').prop('src', '/icon/right_arror.png');
}

// 拼图验证码用---开始滑动回调方法, 改变arror位置和mask大小
function sliderDrug(e){
    if (!sliderStart)
        return false;

    // 获取鼠标移动位置
    var eventX = e.clientX || e.touches[0].clientX;
    var eventY = e.clientY || e.touches[0].clientY;
    var moveX = eventX - x_slider;
    var moveY = eventY - y_slider;

    // 确保边界
    if(moveX < 0|| moveX + parseInt(cut_image_width_slider) > original_image_with_slider){
         return false;
    }

    // 改变slider_arror的位置和mask大小
    $('.slider_arror').css('margin-left', moveX);
    $('.slider_arror').css('cursor', 'pointer');
    $('.slider_mask').css('width', moveX);
    $('.slide_img_mark').css('margin-left', moveX);
}

// 拼图验证码用---结束时进行判断回调方法
function sliderEnd(e){
    if (!sliderStart)
        return false;

    sliderStart = false;
    var finalX = $('.slide_img_mark').css('margin-left');
    finalX = finalX.toString().slice(0, -2);
    
     var error = $("#slideVerificationCodeError");
      $.ajax({
          type: "POST",
          async:false,
          url: "/checkSlideVerificationSlideX?slideVerificationCode="+finalX,
          success : function(jsonData) {
              if(jsonData.code == 200) {
                  var data = jsonData.data;
                  var status = data.status;
                  if (status == true) {
                      error.html("恭喜你,滑动验证码正确!!!!!");
                      successSlide();
                  } else if(status == false){
                      error.html("滑动验证码错误,请重新滑动");
                      failedSlide();
                  }else{
                      error.html("滑动验证码过期,请重新滑动");
                      failedSlide();
                  }
              }else{
                  alert(jsonData.message);
              }
              return false;
          },
          error:function(XMLHttpRequest,textStatus,errorThrown){
              alert("服务器错误!状态码:"+XMLHttpRequest.status);
              // 状态
              console.log(XMLHttpRequest.readyState);
              // 错误信息
              console.log(textStatus);
              return false;
          }
      });

}

// 拼图验证码用---验证成功回调方法
function successSlide(){
    $('#arror_icon').prop('src', '/icon/green_correct.png');
    $('.slider_mask').css('background-color', '#79e77e');
}

// 拼图验证码用---失败重置
function failedSlide(){
    $('#arror_icon').prop('src', '/icon/red_error.png');
    $('.slider_mask').css('background-color', '#e73c4a');

    setTimeout(resetSlide, 1000)
}

// 拼图验证码用---修改位置和重置颜色
function resetSlide(){
    $('.slider_mask').css('background-color', '#deee97');

    $('.slider_arror').css('margin-left', 0);
    $('.slider_arror').css('cursor','pointer');
    $('.slider_mask').css('width', 0);
    $('.slide_img_mark').css('margin-left', 0);

    $('#arror_icon').prop('src', '/icon/right_arror.png');
    $('.slider_tip').show()
}

三、运行

访问链接:http://127.0.0.1:8080

image.png

image.png

image.png

吐槽环节:百度的搜java 验证码,太坑爹了,各种各样复杂,非常不通用,还有一些不能运行的。忍不了忍不了,自己整合一个,最后找到google kaptcha 工具 vary good !!!

谢谢大家观看~


本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码