图形滑动验证码JAVA实现【前后端结合】

一、为什么要验证码?

        防暴力破解的课题一直是信息安全的重点,漏洞攻击更是开发者的噩梦。。。。

        如果没有经历过这个噩梦,请感受一下被信安部门支配的恐惧。(一大堆漏洞给扫出来,您修代码吧)

 

二、怎么实现的?

        前端:HTML+JS+CSS   开源组件:Layui

        后端:Java  后端框架:SpringBoot

        思路:

  • 后端随机读取一张图片,利用算法随机“抠图”,返回base64码值到前端 
  • 前端读取到base64,转码生成图片,底部搭配上“滑块”进行拼图匹配
  • 后端取到匹配的误差值,计算,返回前端验证,是否成功

 

手机模式看看效果:

图形滑动验证码JAVA实现【前后端结合】_第1张图片

三、代码示例

1、Java工具类:class VerifyImageUtil 

用于生成滑动验证码的两个要素

  •  根据原图片裁剪出
  •  裁剪块blockImage;
  •  与裁剪后的原图targetImage
  •  并返回左上角坐标(X,Y)
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Random;


public class VerifyImageUtil {

    /**
     * 源文件宽度
     */
    private static int ORI_WIDTH = 200;
    /**
     * 源文件高度
     */
    private static int ORI_HEIGHT = 116;
    /**
     * 模板图宽度
     */
    private static int CUT_WIDTH = 50;
    /**
     * 模板图高度
     */
    private static int CUT_HEIGHT = 50;
    /**
     * 抠图凸起圆心
     */
    private static int circleR = 5;
    /**
     * 抠图内部矩形填充大小
     */
    private static int RECTANGLE_PADDING = 8;
    /**
     * 抠图的边框宽度
     */
    private static int SLIDER_IMG_OUT_PADDING = 1;


    /**
     * 根据传入的路径生成指定验证码图片
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static VerifyImage getVerifyImage(String filePath) throws IOException {
        BufferedImage srcImage = ImageIO.read(new File(filePath));

        int locationX = CUT_WIDTH + new Random().nextInt(srcImage.getWidth() - CUT_WIDTH * 3);
        int locationY = CUT_HEIGHT + new Random().nextInt(srcImage.getHeight() - CUT_HEIGHT) / 2;
        BufferedImage markImage = new BufferedImage(CUT_WIDTH,CUT_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
        int[][] data = getBlockData();
        cutImgByTemplate(srcImage, markImage, data, locationX, locationY);
        return new VerifyImage(getImageBASE64(srcImage),getImageBASE64(markImage),locationX,locationY,srcImage.getWidth(),srcImage.getHeight());
    }


    /**
     * 生成随机滑块形状
     * 

* 0 透明像素 * 1 滑块像素 * 2 阴影像素 * @return int[][] */ private static int[][] getBlockData() { int[][] data = new int[CUT_WIDTH][CUT_HEIGHT]; Random random = new Random(); //(x-a)²+(y-b)²=r² //x中心位置左右5像素随机 double x1 = RECTANGLE_PADDING + (CUT_WIDTH - 2 * RECTANGLE_PADDING) / 2.0 - 5 + random.nextInt(10); //y 矩形上边界半径-1像素移动 double y1_top = RECTANGLE_PADDING - random.nextInt(3); double y1_bottom = CUT_HEIGHT - RECTANGLE_PADDING + random.nextInt(3); double y1 = random.nextInt(2) == 1 ? y1_top : y1_bottom; double x2_right = CUT_WIDTH - RECTANGLE_PADDING - circleR + random.nextInt(2 * circleR - 4); double x2_left = RECTANGLE_PADDING + circleR - 2 - random.nextInt(2 * circleR - 4); double x2 = random.nextInt(2) == 1 ? x2_right : x2_left; double y2 = RECTANGLE_PADDING + (CUT_HEIGHT - 2 * RECTANGLE_PADDING) / 2.0 - 4 + random.nextInt(10); double po = Math.pow(circleR, 2); for (int i = 0; i < CUT_WIDTH; i++) { for (int j = 0; j < CUT_HEIGHT; j++) { //矩形区域 boolean fill; if ((i >= RECTANGLE_PADDING && i < CUT_WIDTH - RECTANGLE_PADDING) && (j >= RECTANGLE_PADDING && j < CUT_HEIGHT - RECTANGLE_PADDING)) { data[i][j] = 1; fill = true; } else { data[i][j] = 0; fill = false; } //凸出区域 double d3 = Math.pow(i - x1, 2) + Math.pow(j - y1, 2); if (d3 < po) { data[i][j] = 1; } else { if (!fill) { data[i][j] = 0; } } //凹进区域 double d4 = Math.pow(i - x2, 2) + Math.pow(j - y2, 2); if (d4 < po) { data[i][j] = 0; } } } //边界阴影 for (int i = 0; i < CUT_WIDTH; i++) { for (int j = 0; j < CUT_HEIGHT; j++) { //四个正方形边角处理 for (int k = 1; k <= SLIDER_IMG_OUT_PADDING; k++) { //左上、右上 if (i >= RECTANGLE_PADDING - k && i < RECTANGLE_PADDING && ((j >= RECTANGLE_PADDING - k && j < RECTANGLE_PADDING) || (j >= CUT_HEIGHT - RECTANGLE_PADDING - k && j < CUT_HEIGHT - RECTANGLE_PADDING +1))) { data[i][j] = 2; } //左下、右下 if (i >= CUT_WIDTH - RECTANGLE_PADDING + k - 1 && i < CUT_WIDTH - RECTANGLE_PADDING + 1) { for (int n = 1; n <= SLIDER_IMG_OUT_PADDING; n++) { if (((j >= RECTANGLE_PADDING - n && j < RECTANGLE_PADDING) || (j >= CUT_HEIGHT - RECTANGLE_PADDING - n && j <= CUT_HEIGHT - RECTANGLE_PADDING ))) { data[i][j] = 2; } } } } if (data[i][j] == 1 && j - SLIDER_IMG_OUT_PADDING > 0 && data[i][j - SLIDER_IMG_OUT_PADDING] == 0) { data[i][j - SLIDER_IMG_OUT_PADDING] = 2; } if (data[i][j] == 1 && j + SLIDER_IMG_OUT_PADDING > 0 && j + SLIDER_IMG_OUT_PADDING < CUT_HEIGHT && data[i][j + SLIDER_IMG_OUT_PADDING] == 0) { data[i][j + SLIDER_IMG_OUT_PADDING] = 2; } if (data[i][j] == 1 && i - SLIDER_IMG_OUT_PADDING > 0 && data[i - SLIDER_IMG_OUT_PADDING][j] == 0) { data[i - SLIDER_IMG_OUT_PADDING][j] = 2; } if (data[i][j] == 1 && i + SLIDER_IMG_OUT_PADDING > 0 && i + SLIDER_IMG_OUT_PADDING < CUT_WIDTH && data[i + SLIDER_IMG_OUT_PADDING][j] == 0) { data[i + SLIDER_IMG_OUT_PADDING][j] = 2; } } } return data; } /** * 裁剪区块 * 根据生成的滑块形状,对原图和裁剪块进行变色处理 * @param oriImage 原图 * @param targetImage 裁剪图 * @param blockImage 滑块 * @param x 裁剪点x * @param y 裁剪点y */ private static void cutImgByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] blockImage, int x, int y) { for (int i = 0; i < CUT_WIDTH; i++) { for (int j = 0; j < CUT_HEIGHT; j++) { int _x = x + i; int _y = y + j; int rgbFlg = blockImage[i][j]; int rgb_ori = oriImage.getRGB(_x, _y); // 原图中对应位置变色处理 if (rgbFlg == 1) { //抠图上复制对应颜色值 targetImage.setRGB(i,j, rgb_ori); //原图对应位置颜色变化 oriImage.setRGB(_x, _y, Color.LIGHT_GRAY.getRGB()); } else if (rgbFlg == 2) { targetImage.setRGB(i, j, Color.WHITE.getRGB()); oriImage.setRGB(_x, _y, Color.GRAY.getRGB()); }else if(rgbFlg == 0){ //int alpha = 0; targetImage.setRGB(i, j, rgb_ori & 0x00ffffff); } } } } /** * 随机获取一张图片对象 * @param path * @return * @throws IOException */ public static BufferedImage getRandomImage(String path) throws IOException { File files = new File(path); File[] fileList = files.listFiles(); List fileNameList = new ArrayList<>(); if (fileList!=null && fileList.length!=0){ for (File tempFile:fileList){ if (tempFile.isFile() && tempFile.getName().endsWith(".jpg")){ fileNameList.add(tempFile.getAbsolutePath().trim()); } } } Random random = new Random(); File imageFile = new File(fileNameList.get(random.nextInt(fileNameList.size()))); return ImageIO.read(imageFile); } /** * 将IMG输出为文件 * @param image * @param file * @throws Exception */ public static void writeImg(BufferedImage image, String file) throws Exception { byte[] imagedata = null; ByteArrayOutputStream bao=new ByteArrayOutputStream(); ImageIO.write(image,"png",bao); imagedata = bao.toByteArray(); FileOutputStream out = new FileOutputStream(new File(file)); out.write(imagedata); out.close(); } /** * 将图片转换为BASE64 * @param image * @return * @throws IOException */ public static String getImageBASE64(BufferedImage image) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageIO.write(image,"png",out); //转成byte数组 byte[] bytes = out.toByteArray(); BASE64Encoder encoder = new BASE64Encoder(); //生成BASE64编码 //String showBase64 = encoder.encode(bytes); String showBase64 = Base64.getEncoder().encodeToString(bytes); // System.out.println("showBase64:\n"+showBase64+"\n"); return showBase64; } /** * 将BASE64字符串转换为图片 * @param base64String * @return */ public static BufferedImage base64StringToImage(String base64String) { try { BASE64Decoder decoder=new BASE64Decoder(); byte[] bytes1 = decoder.decodeBuffer(base64String); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1); return ImageIO.read(byteArrayInputStream); } catch (IOException e) { e.printStackTrace(); } return null; } }

 

 

2、JavaController:class VerifyController

生成验证码的调用接口:/check/getImgSwipe

校验误差值的调用接口:/check/rstImgSwipe

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;


import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;


@Controller
@RequestMapping(value = "/check")
public class UserController extends BaseController {

	//获取滑动验证码的图片
	@RequestMapping(value="/getImgSwipe",method=RequestMethod.GET)
	@ResponseBody
	public PageData getImgSwipe() {
		PageData pd = new PageData();
		String path = "";
		int index = 0;
		Random ran = new Random();
		HttpSession session = this.getCurrentSession();
		try {
			session.setAttribute("imgSwipeSuccess","false");
			//随机获取verifyImages文件夹下的某一张图片
			String url = this.getClass().getResource("/").toString().substring(5);
			String resources = "static/images/verifyImages";
			path = url + resources;
			File file = new File(path);
			File [] files = file.listFiles();

			index = ran.nextInt(files.length-1);	//随机下标
			System.out.println(files[index].getPath());

			VerifyImage img = VerifyImageUtil.getVerifyImage(files[index].getPath());
			pd.put("SrcImage",img.getSrcImage());
			pd.put("CutImage",img.getCutImage());
//			pd.put("XPosition",img.getXPosition());
			pd.put("YPosition",img.getYPosition());
			pd.put("SrcImageWidth",img.getSrcImageWidth());
			pd.put("SrcImageHeight",img.getSrcImageHeight());
			session.setAttribute("XPosition",img.getXPosition());

		}catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return pd;
	}

	//返回前端滑动验证码参数
	@RequestMapping(value="/rstImgSwipe",method=RequestMethod.POST)
	@ResponseBody
	public PageData rstImgSwipe() {
		PageData pd = this.getPageData();
		Float moveEnd_X =  Float.valueOf(pd.getString("moveEnd_X")) ;
		Float wbili = Float.valueOf(pd.getString("wbili"));
		HttpSession session = this.getCurrentSession();
		Integer XPosition = Integer.parseInt(session.getAttribute("XPosition").toString());

		Float xResult = XPosition * wbili;
		System.out.println("mx:"+moveEnd_X+"\nmp:"+XPosition+"\nwbili:"+wbili+"\nxRst:"+xResult);
		PageData pd1 = new PageData();
		if(Math.abs(xResult-moveEnd_X)<10){	//设置误差像素

			pd1.put("success",true);
			session.setAttribute("imgSwipeSuccess","ture");
			return pd1;
		}else {
			pd1.put("success",false);
			session.setAttribute("imgSwipeSuccess","false");
			return pd1;
		}
	}
}

 

 

3、check_verify.js

document.write('');

layui.use(['layer', 'form', 'element'], function () {
    window.layer = layui.layer;
    window.form = layui.form;
    window.element = layui.element;
});

var imgBase64 = ''
// 登陆前清空Session
sessionStorage.clear();
//图形验证码获取func
function VerifyImg(){
	$.ajax({
	    url: "/check/getImg",
	    data: {},
	    cache:false,
            type: "GET",
	    success: function (data) {
            console.log(data)
            imgBase64 = data["img"];
            console.log(imgBase64);
            document.getElementById("img").setAttribute("src","data:image/png;base64,"+imgBase64);
            return imgBase64;
		},
	    error: function(){
	    	alert("error");
	    }
	});	
}



/*图形验证码获取与弹出*/
function layerVerifyCodeImg(userPhone){
    // console.log(imgBase64);
    layer.open({
        id: 3,
        offset: 'auto',
        height:'200px',
        type: 1,
        title: '图形验证',

        content:
        '
' +'
' +'
' , //btn: ['确认'], btnAlign: 'c', //按钮居中 success:function(){ $.ajax({ url: "/check/getImgSwipe", data: {}, cache:false, type: "GET", // async:false, success: function (data) { console.log(data) var SrcImage = "data:image/jpg;base64,"+data.SrcImage var CutImage = "data:image/jpg;base64,"+data.CutImage var YPosition = data.YPosition var SrcImageWidth = data.SrcImageWidth; var SrcImageHeight = data.SrcImageHeight; //console.log(imgBase64); imgVer({ el:'$("#imgVer")', width:'220', height:'116', SrcImage:SrcImage, CutImage:CutImage, YPosition:YPosition, SrcImageWidth:SrcImageWidth, SrcImageHeight:SrcImageHeight, userPhone:userPhone, success:function () { //验证成功可自定义后续逻辑 }, error:function () { //alert('错误什么都不执行') } }); }, error: function(){ alert("error"); } }); } }) } var InterValObj; //timer变量,控制时间 var count = 60; //间隔函数,1秒执行 var curCount = 0;//当前剩余秒数 /*短信验证码弹出层 */ function layerVerifyCode(phoneNumber) { var phoneNumberDecode = phoneNumber; // console.log(phoneNumberDecode); var fillNum; //判断是11位手机号码 if(checkLegal(phoneNumberDecode)){ fillNum = phoneNumberDecode; }else{ fillNum=''; } console.log(fillNum); layer.open({ id: 2, type: 1, title: '请输入验证码', area: ['auto', 'auto'], content: '
' + '
' + '' + '
' + '' + '
' +'
' +'
' + '' + '
' + '' + ''//验证码input + button发送 调用sendMessage() + '
' + '
' + '
' , btn: ['确认'], btnAlign: 'c', //按钮居中 btn1: function (index, layero) { chcek_confirm(); } }) //限制反复点击弹窗的按钮可用 if(curCount > 0){ $("#btnSendCode").attr("disabled", "true"); console.log('disabled'); }else if(curCount == 0){ console.log('enabled'); }else{ console.log('error'); } } /*发送验证码 */ function sendMessage() { if(curCount == 0){ curCount = count; //设置button效果,开始计时,防止关闭重置 } $("#btnSendCode").attr("disabled", "true"); $("#btnSendCode").val(curCount + "s"); InterValObj = window.setInterval(SetRemainTime, 1000); //启动计时器,1秒执行一次 var userPhone = $("#user_phone_verify").val(); /*向后台发送处理数据*/ console.log(userPhone); $.ajax({ url: "/code/sendCode", data: { MOBILE_NUMBER: encode(userPhone) }, type: "POST", cache: false, success: function (data) { if (decode(data).success) { layer.msg(decode(data).data); } else { layer.msg(decode(data).errorMessage); } } }) } /*timer处理函数*/ function SetRemainTime() { if (curCount == 0) { window.clearInterval(InterValObj);//停止计时器 $("#btnSendCode").removeAttr("disabled");//启用按钮 $("#btnSendCode").val("重新获取"); } else { curCount--; $("#btnSendCode").val(curCount + "s"); } } function chcek_confirm () { var phoneNumber = document.getElementById('user_phone_verify'); if (phoneNumber.value.length != 11) { layer.alert("手机号不足11位"); } else if (!checkLegal(phoneNumber.value)) { layer.alert("手机号输入不正确"); } else { checkVerifyCode(phoneNumber.value,$("#user_verify").val()); } }

4.img_ver.js


function detectmob() {
    if (navigator.userAgent.match(/Android/i)
        || navigator.userAgent.match(/webOS/i)
        || navigator.userAgent.match(/iPhone/i)
        || navigator.userAgent.match(/iPad/i)
        || navigator.userAgent.match(/iPod/i)
        || navigator.userAgent.match(/BlackBerry/i)
        || navigator.userAgent.match(/Windows Phone/i)
    ) {
        return true;
    }
    else {
        return false;
    }
}
var userPhone
function imgVer(Config) {
    userPhone = Config.userPhone
    var el = eval(Config.el);
    var w = Config.width;
    var h = Config.height;
    var SrcImage = Config.SrcImage
    var CutImage = Config.CutImage
    var YPosition = Config.YPosition
    // var imgLibrary = Config.img;
    var SrcImageHeight = Config.SrcImageHeight;
    var SrcImageWidth = Config.SrcImageWidth;
    var wbili = w / SrcImageWidth;
    var hbili = h / SrcImageHeight;
    console.log(wbili + '\n' + hbili);

    var PL_Size = 48;
    var padding = 20;
    var MinN_X = padding + PL_Size;
    var MaxN_X = w - padding - PL_Size - PL_Size / 6;
    var MaxN_Y = padding;
    var MinN_Y = h - padding - PL_Size - PL_Size / 6;

    function RandomNum(Min, Max) {
        var Range = Max - Min;
        var Rand = Math.random();
        if (Math.round(Rand * Range) == 0) {
            return Min + 1;
        } else if (Math.round(Rand * Max) == Max) {
            return Max - 1;
        } else {
            var num = Min + Math.round(Rand * Range) - 1;
            return num;
        }
    }
    var imgSrc = SrcImage;
    var X = '1';
    var Y = '1';


    console.log('PrintLocation');
    console.log("X:" + X + "\n" + "Y:" + Y);
    var left_Num = 0;
    var html = '
'; html += '
'; html += '
'; html += ''; html += ''; html += '
'; html += '
'; html += ''; html += ''; html += '
'; html += '

'; html += '
'; html += '
'; html += '
'; html += '
'; html += '
'; //设置触摸区域,防止左滑返回 html += '
'; html += '

按住左边滑块,拖动完成上方拼图

'; html += '
'; html += '
'; html += '
'; el.html(html); var c_l = document.getElementById("puzzleLost"); //var c_s = document.getElementById("puzzleShadow"); var ctx_l = c_l.getContext("2d"); //var ctx_s = c_s.getContext("2d"); var img = new Image(); img.src = CutImage; img.onload = function () { // ctx_l.drawImage(img, 0, YPosition); ctx_l.drawImage(img, 0, YPosition * hbili, 50 * wbili, 50 * hbili); } var moveStart = ''; if (detectmob()) { //Mobile端 document.getElementsByClassName('slider-btn')[0].addEventListener("touchstart", function (e) { e = e || window.event; $(this).css({ "background-position": "0 -216px" }); moveStart = e.touches[0].pageX; }, false); var moveEnd; document.addEventListener("touchmove", function (e) { e = e || window.event; var moveX = e.touches[0].pageX; var d = moveX - moveStart; if (moveStart == '') { } else { if (d < 0 || d > (w - 2 * padding)) { } else { $(".slider-btn").css({ "left": d + 'px', "transition": "inherit" }); $("#puzzleLost").css({ "left": d + 'px', "transition": "inherit" }); $("#puzzleShadow").css({ "left": d + 'px', "transition": "inherit" }); } } moveEnd = moveX }, false); document.addEventListener("touchend", function (e) { e = e || window.event; var moveEnd_X = moveEnd - moveStart; if (moveStart == '') { } else { CheckResult_VerifyButton(moveEnd_X,wbili,Config); } setTimeout(function () { $(".slider-btn").css({ "left": '0', "transition": "left 0.5s" }); $("#puzzleLost").css({ "left": '0', "transition": "left 0.5s" }); $("#puzzleShadow").css({ "left": '0', "transition": "left 0.5s" }); }, 1000); $(".slider-btn").css({ "background-position": "0 -84px" }); moveStart = ''; Refresh_VerifyButton(); // console.log("mobile-refresh"); //mobile刷新 }, false) } else { //PC端 $(".slider-btn").mousedown(function (e) { e = e || window.event; $(this).css({ "background-position": "0 -216px" }); moveStart = e.pageX; }); var moveEnd; onmousemove = function (e) { e = e || window.event; var moveX = e.pageX; var d = moveX - moveStart; if (moveStart == '') { } else { if (d < 0 || d > (w - 2 * padding)) { } else { $(".slider-btn").css({ "left": d + 'px', "transition": "inherit" }); $("#puzzleLost").css({ "left": d + 'px', "transition": "inherit" }); $("#puzzleShadow").css({ "left": d + 'px', "transition": "inherit" }); } } moveEnd = moveX }; onmouseup = function (e) { e = e || window.event; var moveEnd_X = e.pageX - moveStart; if (moveStart == '') { } else { CheckResult_VerifyButton(moveEnd_X,wbili,Config); } setTimeout(function () { $(".slider-btn").css({ "left": '0', "transition": "left 0.5s" }); $("#puzzleLost").css({ "left": '0', "transition": "left 0.5s" }); $("#puzzleShadow").css({ "left": '0', "transition": "left 0.5s" }); }, 1000); $(".slider-btn").css({ "background-position": "0 -84px" }); moveStart = ''; Refresh_VerifyButton(); // console.log("pc-refresh"); } } } function CheckResult_VerifyButton(moveEnd_X,wbili,Config) { $.ajax({ url: "/check/rstImgSwipe", data: { moveEnd_X: encode(moveEnd_X), wbili: encode(wbili) }, type: "POST", cache: false, success: function (data) { // var dataDecode = decode(data); if (data.success) { // console.log(data); $(".ver-tips").html('验证通过'); $(".ver-tips").addClass("slider-tips"); $(".puzzle-lost-box").addClass("hidden"); $("#puzzleBox").addClass("hidden"); setTimeout(function () { $(".ver-tips").removeClass("slider-tips"); imgVer(Config); }, 2000); Config.success(); } else { // console.log(data); $(".ver-tips").html('验证失败:拖动滑块将悬浮图像正确拼合'); $(".ver-tips").addClass("slider-tips"); setTimeout(function () { $(".ver-tips").removeClass("slider-tips"); }, 2000); // Config.error(); } } }) } function Refresh_VerifyButton() { $(".re-btn a").unbind('click').click(function () { // imgVer(Config); $.ajax({ url: "/check/getImgSwipe", data: {}, cache: false, type: "GET", success: function (data) { console.log(data) var SrcImage = "data:image/jpg;base64," + data.SrcImage var CutImage = "data:image/jpg;base64," + data.CutImage var YPosition = data.YPosition var SrcImageWidth = data.SrcImageWidth; var SrcImageHeight = data.SrcImageHeight; imgVer({ el: '$("#imgVer")', width: '220', height: '116', SrcImage: SrcImage, CutImage: CutImage, YPosition: YPosition, SrcImageWidth: SrcImageWidth, SrcImageHeight: SrcImageHeight, userPhone: userPhone, success: function () { //验证成功可自定义后续逻辑 } }); }, error: function () { alert("error"); } }); }) }

5.页面





    
    xxxxxxx
    
    
    
    
    

    
    
    
    
    
    
    
    
    

    
    
    
    

    
    
    
    







    

6.checkStyle.css

 

.slider-btn{position:absolute;width:44px;height:44px;left:0;top:-7px;z-index:12;cursor:pointer;background-image:url(../images/checkSprite.png);background-position:0 -84px;transition:inherit}
.ver-tips{position:absolute;left:0;bottom:-22px;background:rgba(255,255,255,.9);height:22px;line-height:22px;font-size:12px;width:100%;margin:0;text-align:left;padding:0 8px;transition:all .4s}
.slider-tips{bottom:0}
.ver-tips i{display:inline-block;width:22px;height:22px;vertical-align:top;background-image:url(../images/checkSprite.png);background-position:-4px -1229px}
.ver-tips span{display:inline-block;vertical-align:top;line-height:22px;color:#455}
.active-tips{display:block}
.hidden{display:none}
.re-btn{position:absolute;left:0;bottom:0;height:28px;padding:0 16px}
.re-btn a{display:inline-block;width:14px;height:14px;margin:7px 0;background-image:url(../images/checkSprite.png);background-position:0 -1179px;cursor:pointer}
.re-btn a:hover{background-position:0 -1193px}

css里的图片checkSprite.png

图形滑动验证码JAVA实现【前后端结合】_第2张图片

你可能感兴趣的:(Java笔记)