欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)滑塊拼圖驗(yàn)證碼

 更新時間:2021年07月23日 10:55:34   作者:不寫B(tài)UG的瑾大大  
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)滑塊拼圖驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Java實(shí)現(xiàn)滑塊拼圖驗(yàn)證碼的具體代碼,供大家參考,具體內(nèi)容如下

1、后端隨機(jī)生成摳圖和帶有摳圖陰影的背景圖片,后臺保存隨機(jī)摳圖位置坐標(biāo)
2、前端實(shí)現(xiàn)滑動交互,將摳圖拼在摳圖陰影之上,獲取到用戶滑動距離值,比如以下示例

3、前端將用戶滑動距離值傳入后端,后端校驗(yàn)誤差是否在容許范圍內(nèi)。

這里單純校驗(yàn)用戶滑動距離是最基本的校驗(yàn),出于更高的安全考慮,可能還會考慮用戶滑動的整個軌跡,用戶在當(dāng)前頁面的訪問行為等。這些可以很復(fù)雜,甚至借助到用戶行為數(shù)據(jù)分析模型,最終的目標(biāo)都是增加非法的模擬和繞過的難度。這些有機(jī)會可以再歸納總結(jié)常用到的方法,本文重點(diǎn)集中在如何基于Java來一步步實(shí)現(xiàn)滑動驗(yàn)證碼的生成。

可以看到,滑動圖形驗(yàn)證碼,重要有兩個圖片組成,摳塊和帶有摳塊陰影的原圖,這里面有兩個重要特性保證被暴力破解的難度:摳塊的形狀隨機(jī)和摳塊所在原圖的位置隨機(jī)。這樣就可以在有限的圖集中制造出隨機(jī)的、無規(guī)律可尋的摳圖和原圖的配對。

用代碼如何從一張大圖中摳出一個有特定隨機(jī)形狀的小圖呢?

第一步,先確定一個摳出圖的輪廓,方便后續(xù)真正開始執(zhí)行圖片處理操作

圖片是有像素組成,每個像素點(diǎn)對應(yīng)一種顏色,顏色可以用RGB形式表示,外加一個透明度,把一張圖理解成一個平面圖形,左上角為原點(diǎn),向右x軸,向下y軸,一個坐標(biāo)值對應(yīng)該位置像素點(diǎn)的顏色,這樣就可以把一張圖轉(zhuǎn)換成一個二維數(shù)組?;谶@個考慮,輪廓也用二維數(shù)組來表示,輪廓內(nèi)元素值為1,輪廓外元素值對應(yīng)0。

這時候就要想這個輪廓形狀怎么生成了。有坐標(biāo)系、有矩形、有圓形,沒錯,用到數(shù)學(xué)的圖形函數(shù)。典型用到一個圓的函數(shù)方程和矩形的邊線的函數(shù),類似:

(x-a)²+(y-b)²=r²中,有三個參數(shù)a、b、r,即圓心坐標(biāo)為(a,b),半徑r。這些將摳圖放在上文描述的坐標(biāo)系上很容易就圖算出來具體的值。

示例代碼如下:

static int targetWidth = 55;//小圖長
static int targetHeight = 45;//小圖寬
static int circleR = 8;//半徑
static int r1 = 4;//距離點(diǎn)
 
    /**
     * @Createdate: 2019年1月24日上午10:52:42
     * @Title: getBlockData
     * @Description: 生成小圖輪廓
     * @author zhoujin
     * @return int[][]
     * @throws
     */
    private static int[][] getBlockData() {
        int[][] data = new int[targetWidth][targetHeight];
        double x2 = targetWidth -circleR; //47
 
        //隨機(jī)生成圓的位置
        double h1 = circleR + Math.random() * (targetWidth-3*circleR-r1);
        double po = Math.pow(circleR,2); //64
 
        double xbegin = targetWidth - circleR - r1;
        double ybegin = targetHeight- circleR - r1;
 
        //圓的標(biāo)準(zhǔn)方程 (x-a)²+(y-b)²=r²,標(biāo)識圓心(a,b),半徑為r的圓
        //計(jì)算需要的小圖輪廓,用二維數(shù)組來表示,二維數(shù)組有兩張值,0和1,其中0表示沒有顏色,1有顏色
        for (int i = 0; i < targetWidth; i++) {
            for (int j = 0; j < targetHeight; j++) {
                double d2 = Math.pow(j - 2,2) + Math.pow(i - h1,2);
                double d3 = Math.pow(i - x2,2) + Math.pow(j - h1,2);
                if ((j <= ybegin && d2 < po)||(i >= xbegin && d3 > po)) {
                        data[i][j] = 0;
                }  else {
                        data[i][j] = 1;
                }
            }
        }
        return data;
    }

第二步,有這個輪廓后就可以依據(jù)這個二維數(shù)組的值來判定摳圖并在原圖上摳圖位置處加陰影。

操作如下:

/**
     *
     * @Createdate: 2019年1月24日上午10:51:30
     * @Title: cutByTemplate
     * @Description: 有這個輪廓后就可以依據(jù)這個二維數(shù)組的值來判定摳圖并在原圖上摳圖位置處加陰影,
     * @author zhoujin
     * @param oriImage  原圖
     * @param targetImage  摳圖拼圖
     * @param templateImage 顏色
     * @param x
     * @param y void
     * @throws
     */
    private static void cutByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] templateImage, int x, int y){
        int[][] martrix = new int[3][3];
        int[] values = new int[9];
        //創(chuàng)建shape區(qū)域
        for (int i = 0; i < targetWidth; i++) {
            for (int j = 0; j < targetHeight; j++) {
                int rgb = templateImage[i][j];
                // 原圖中對應(yīng)位置變色處理
                int rgb_ori = oriImage.getRGB(x + i, y + j);
 
                if (rgb == 1) {
                    targetImage.setRGB(i, j, rgb_ori);
 
                    //摳圖區(qū)域高斯模糊
                    readPixel(oriImage, x + i, y + j, values);
                    fillMatrix(martrix, values);
                    oriImage.setRGB(x + i, y + j, avgMatrix(martrix));
                }else{
                    //這里把背景設(shè)為透明
                    targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
                }
            }
        }
    }
 
 
   private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
        int xStart = x - 1;
        int yStart = y - 1;
        int current = 0;
        for (int i = xStart; i < 3 + xStart; i++)
            for (int j = yStart; j < 3 + yStart; j++) {
                int tx = i;
                if (tx < 0) {
                    tx = -tx;
 
                } else if (tx >= img.getWidth()) {
                    tx = x;
                }
                int ty = j;
                if (ty < 0) {
                    ty = -ty;
                } else if (ty >= img.getHeight()) {
                    ty = y;
                }
                pixels[current++] = img.getRGB(tx, ty);
 
            }
    }
 
    private static void fillMatrix(int[][] matrix, int[] values) {
        int filled = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                x[j] = values[filled++];
            }
        }
    }
 
    private static int avgMatrix(int[][] matrix) {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                if (j == 1) {
                    continue;
                }
                Color c = new Color(x[j]);
                r += c.getRed();
                g += c.getGreen();
                b += c.getBlue();
            }
        }
        return new Color(r / 8, g / 8, b / 8).getRGB();
    }

經(jīng)過前面兩步后,就得到了摳圖和帶高斯模糊摳圖陰影的原圖。返回生成的摳圖和帶陰影的大圖base64碼及摳圖坐標(biāo)。

/**
     * @Description: 讀取本地圖片,生成拼圖驗(yàn)證碼
     * @author zhoujin
     * @return Map<String,Object>  返回生成的摳圖和帶摳圖陰影的大圖 base64碼及摳圖坐標(biāo)
     */
    public static Map<String,Object> createImage(File file, Map<String,Object> resultMap){
        try {
            BufferedImage oriImage = ImageIO.read(file);
            Random random = new Random();
            //X軸距離右端targetWidth  Y軸距離底部targetHeight以上
            int widthRandom = random.nextInt(oriImage.getWidth()-  2*targetWidth) + targetWidth;
            int heightRandom = random.nextInt(oriImage.getHeight()- targetHeight);
            logger.info("原圖大小{} x {},隨機(jī)生成的坐標(biāo) X,Y 為({},{})",oriImage.getWidth(),oriImage.getHeight(),widthRandom,heightRandom);
 
            BufferedImage targetImage= new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_4BYTE_ABGR);
            cutByTemplate(oriImage,targetImage,getBlockData(),widthRandom,heightRandom);
 
            resultMap.put("bigImage", getImageBASE64(oriImage));//大圖
            resultMap.put("smallImage", getImageBASE64(targetImage));//小圖
            resultMap.put("xWidth",widthRandom);
            resultMap.put("yHeight",heightRandom);
        } catch (Exception e) {
            logger.info("創(chuàng)建圖形驗(yàn)證碼異常",e);
        } finally{
            return resultMap;
        }
    }
 
 
    /**
     * @Description: 讀取網(wǎng)絡(luò)圖片,生成拼圖驗(yàn)證碼
     * @author zhoujin
     * @return Map<String,Object>  返回生成的摳圖和帶摳圖陰影的大圖 base64碼及摳圖坐標(biāo)
     */
    public static Map<String,Object> createImage(String imgUrl, Map<String,Object> resultMap){
        try {
            //通過URL 讀取圖片
            URL url = new URL(imgUrl);
            BufferedImage bufferedImage = ImageIO.read(url.openStream());
            Random rand = new Random();
            int widthRandom = rand.nextInt(bufferedImage.getWidth()-  targetWidth - 100 + 1 ) + 100;
            int heightRandom = rand.nextInt(bufferedImage.getHeight()- targetHeight + 1 );
            logger.info("原圖大小{} x {},隨機(jī)生成的坐標(biāo) X,Y 為({},{})",bufferedImage.getWidth(),bufferedImage.getHeight(),widthRandom,heightRandom);
 
            BufferedImage target= new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_4BYTE_ABGR);
            cutByTemplate(bufferedImage,target,getBlockData(),widthRandom,heightRandom);
            resultMap.put("bigImage", getImageBASE64(bufferedImage));//大圖
            resultMap.put("smallImage", getImageBASE64(target));//小圖
            resultMap.put("xWidth",widthRandom);
            resultMap.put("yHeight",heightRandom);
        } catch (Exception e) {
            logger.info("創(chuàng)建圖形驗(yàn)證碼異常",e);
        } finally{
            return resultMap;
        }
    }
 
 
    /**
     * @Title: getImageBASE64
     * @Description: 圖片轉(zhuǎn)BASE64
     * @author zhoujin
     * @param image
     * @return
     * @throws IOException String
     */
    public static String getImageBASE64(BufferedImage image) throws IOException {
        byte[] imagedata = null;
        ByteArrayOutputStream bao=new ByteArrayOutputStream();
        ImageIO.write(image,"png",bao);
        imagedata=bao.toByteArray();
        BASE64Encoder encoder = new BASE64Encoder();
        String BASE64IMAGE=encoder.encodeBuffer(imagedata).trim();
        BASE64IMAGE = BASE64IMAGE.replaceAll("\r|\n", "");  //刪除 \r\n
        return BASE64IMAGE;
    }

控制層代碼實(shí)現(xiàn)及校驗(yàn)驗(yàn)證碼:

/**
     * @param @return 參數(shù)說明
     * @return BaseRestResult 返回類型
     * @Description: 生成滑塊拼圖驗(yàn)證碼
     */
    @RequestMapping(value = "/getImageVerifyCode.do", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
    public BaseRestResult getImageVerifyCode() {
        Map<String, Object> resultMap = new HashMap<>();
        //讀取本地路徑下的圖片,隨機(jī)選一條
        File file = new File(this.getClass().getResource("/image").getPath());
        File[] files = file.listFiles();
        int n = new Random().nextInt(files.length);
        File imageUrl = files[n];
        ImageUtil.createImage(imageUrl, resultMap);
 
        //讀取網(wǎng)絡(luò)圖片
        //ImageUtil.createImage("/7986d66f29bfeb6015aaaec33d33fcd1d875ca16316f-2bMHNG_fw658",resultMap);
        session.setAttribute("xWidth", resultMap.get("xWidth"));
        resultMap.remove("xWidth");
        resultMap.put("errcode", 0);
        resultMap.put("errmsg", "success");
        return new BaseRestResult(resultMap);
    }
 
 
    /**
     * 校驗(yàn)滑塊拼圖驗(yàn)證碼
     *
     * @param moveLength 移動距離
     * @return BaseRestResult 返回類型
     * @Description: 生成圖形驗(yàn)證碼
     */
    @RequestMapping(value = "/verifyImageCode.do", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
    public BaseRestResult verifyImageCode(@RequestParam(value = "moveLength") String moveLength) {
        Double dMoveLength = Double.valueOf(moveLength);
        Map<String, Object> resultMap = new HashMap<>();
        try {
            Integer xWidth = (Integer) session.getAttribute("xWidth");
            if (xWidth == null) {
                resultMap.put("errcode", 1);
                resultMap.put("errmsg", "驗(yàn)證過期,請重試");
                return new BaseRestResult(resultMap);
            }
            if (Math.abs(xWidth - dMoveLength) > 10) {
                resultMap.put("errcode", 1);
                resultMap.put("errmsg", "驗(yàn)證不通過");
            } else {
                resultMap.put("errcode", 0);
                resultMap.put("errmsg", "驗(yàn)證通過");
            }
        } catch (Exception e) {
            throw new EsServiceException(e.getMessage());
        } finally {
            session.removeAttribute("xWidth");
        }
        return new BaseRestResult(resultMap);
}

前端顯示圖片代碼:

<img src="data:image/png;base64,+返回的base64圖片碼" alt="摳圖">
<img src="data:image/png;base64,+返回的base64圖片碼" alt="帶摳圖陰影的原圖">

至此后臺java實(shí)現(xiàn)滑塊驗(yàn)證碼關(guān)鍵代碼完成!

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解JAVA中priorityqueue的具體使用

    詳解JAVA中priorityqueue的具體使用

    這篇文章主要介紹了詳解JAVA中priorityqueue的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java中的@Repeatable注解的作用詳解

    Java中的@Repeatable注解的作用詳解

    這篇文章主要介紹了Java中的@Repeatable注解的作用詳解,@Repeatable注解是用來標(biāo)注一個注解在同一個地方可重復(fù)使用的一個注解,使被他注釋的注解可以在同一個地方重復(fù)使用,需要的朋友可以參考下
    2024-01-01
  • Java List集合方法及遍歷過程代碼解析

    Java List集合方法及遍歷過程代碼解析

    這篇文章主要介紹了Java List集合方法及遍歷過程代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • MyBatis一次執(zhí)行多條SQL語句的操作

    MyBatis一次執(zhí)行多條SQL語句的操作

    這篇文章主要介紹了MyBatis一次執(zhí)行多條SQL語句的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Java實(shí)例化類詳解

    Java實(shí)例化類詳解

    學(xué)習(xí)JAVA這門面向?qū)ο蟮恼Z言,實(shí)質(zhì)就是不斷地創(chuàng)建類,并把類實(shí)例化為對象并調(diào)用方法。對于初學(xué)JAVA的人總搞清楚對象是如何實(shí)例化的,假如類之間存在繼承關(guān)系,那就更糊涂了。下面我們通過兩個例題來說明對象的實(shí)例化過程。
    2016-03-03
  • Java實(shí)現(xiàn)向數(shù)組里添加元素

    Java實(shí)現(xiàn)向數(shù)組里添加元素

    這篇文章主要介紹了Java實(shí)現(xiàn)向數(shù)組里添加元素方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 詳解Java中Quartz的簡單使用

    詳解Java中Quartz的簡單使用

    Quartz?是一個開源的作業(yè)調(diào)度框架,它完全由?Java?寫成,并設(shè)計(jì)用于?J2SE?和?J2EE?應(yīng)用中。這篇文章主要通過示例和大家講講Quartz的簡單使用,需要的可以參考一下
    2023-04-04
  • 詳解spring Boot Cli的配置和使用

    詳解spring Boot Cli的配置和使用

    本篇文章主要介紹了詳解spring Boot Cli的配置和使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • RocketMQ?NameServer架構(gòu)設(shè)計(jì)啟動流程

    RocketMQ?NameServer架構(gòu)設(shè)計(jì)啟動流程

    這篇文章主要為大家介紹了RocketMQ?NameServer架構(gòu)設(shè)計(jì)啟動流程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • 在MyBatisPlus中使用@TableField完成字段自動填充的操作

    在MyBatisPlus中使用@TableField完成字段自動填充的操作

    這篇文章主要介紹了在MyBatisPlus中使用@TableField完成字段自動填充的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02

最新評論