欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于慕课网-----Java验证码的实现

程序员文章站 2022-05-19 19:17:16
...

1.最近学习了慕课网的Java验证码的实现,链接地址由于老师并没有给代码,一步一步跟着老师敲的,当然,也借鉴了其他同学的代码,最后成功的实现出来(用的是IDEA),其中代码大多和老师的一样,废话不多说,先看下最终演示效果,也附上github地址  https://github.com/Robotsh/Imooc

2.展示(浏览器好像用火狐显示不出来点击的“火”,这里浏览器用的Chrome,QQ浏览器也可以显示

基于慕课网-----Java验证码的实现

基于慕课网-----Java验证码的实现

3.目录结构

基于慕课网-----Java验证码的实现

4.LoginController的实现(这里我将不对代码进行过多的解释,有需要的可以到慕课网上学习,也可以和我互相交流学习)

package com.robot.controller;


import com.robot.entiy.ImageResult;
import com.robot.until.Cache;
import com.robot.until.Image;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;



@Controller
public class LoginController{
    @RequestMapping("/identify")
    public String identify(Model model, ServletResponse response,ServletRequest request) {
        try {

            ImageResult ir = Image.generateImage(request);
            model.addAttribute("file", ir.getName());
            model.addAttribute("tip", ir.getTip());
            Cache.put(ir.getUniqueKey(), ir);
            Cookie cookie = new Cookie("note", ir.getUniqueKey());
            ((HttpServletResponse) response).addCookie(cookie);
        } catch (IOException e) {

        }
        return "login";
    }

    @RequestMapping("/login")
    @ResponseBody
    public String login(String location, ServletRequest request, String userName, String password) {
        Cookie[] cookies = ((HttpServletRequest) request).getCookies();
        Cookie note = null;
        for (Cookie cookie : cookies) {
            if(cookie.getName().equals("note")){
                note = cookie;
                break;
            }
        }
        if (null == note) {
            return "ERROR";
        }
        ImageResult ir = Cache.get(note.getValue());
        Cache.remove(note.getName());
        if (null == location || "".equals(location)) {
            return "ERROR";
        }
        if (validate(location, ir)) {
            return "OK";
        }
        return "ERROR";
    }

    private boolean validate(String locationString, ImageResult imageResult) {

        String[] resultArray = locationString.split(";");
        int[][] array = new int[resultArray.length][2];
        for (int i = 0; i < resultArray.length; i++) {
            String[] temp = resultArray[i].split(",");
            array[i][0] = Integer.parseInt(temp[0]) + 150 - 10;
            array[i][1] = Integer.parseInt(temp[1]) + 300;
        }

        for (int i = 0; i < array.length; i++) {
            int location = location(array[i][1], array[i][0]);
            System.out.println("解析后的坐标序号:" + location);
            if (!imageResult.getKeySet().contains(location)) {
                return false;
            }
        }
        return true;
    }

    private static int location(int x, int y) {
        if (y >= 0 && y < 75) {
            return xLocation(x);
        } else if (y >= 75 && y <= 150) {
            return xLocation(x) + 4;
        } else {
            // 脏数据
            return -1;
        }
    }

    private static int xLocation(int x) {
        if (x >= 0 && x < 75) {
            return 0;
        } else if (x >= 75 && x < 150) {
            return 1;
        } else if (x >= 150 && x < 225) {
            return 2;
        } else if (x >= 225 && x <= 300) {
            return 3;
        } else {
            // 脏数据
            return -1;
        }
    }
}


5.实体类BufferedImageWarp的实现

package com.robot.entiy;

import java.awt.image.BufferedImage;

public class BufferedImageWarp {

    private boolean key;

    private BufferedImage bufferedImage;

    public BufferedImageWarp(boolean key, BufferedImage bufferedImage) {
        this.key = key;
        this.bufferedImage = bufferedImage;
    }

    public boolean isKey() {
        return key;
    }

    public void setKey(boolean key) {
        this.key = key;
    }

    public BufferedImage getBufferedImage() {
        return bufferedImage;
    }

    public void setBufferedImage(BufferedImage bufferedImage) {
        this.bufferedImage = bufferedImage;
    }
}

6.GenerateImageWarp的实现

package com.robot.entiy;


import java.util.List;

public class GenerateImageGroup {

    private ImageGroup keyGroup;
    private List<ImageGroup> groups;

    public GenerateImageGroup(ImageGroup keyGroup, List<ImageGroup> groups) {
        this.keyGroup = keyGroup;
        this.groups = groups;
    }

    public ImageGroup getKeyGroup() {
        return keyGroup;
    }

    public void setKeyGroup(ImageGroup keyGroup) {
        this.keyGroup = keyGroup;
    }

    public List<ImageGroup> getGroups() {
        return groups;
    }

    public void setGroups(List<ImageGroup> groups) {
        this.groups = groups;
    }
}

6.ImageGroup的实现

package com.robot.entiy;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class ImageGroup {

    private String name;

    private int count;

    private Set<String> images;

    public ImageGroup(String name,int count,String...imageNames){
        this.name=name;
        this.count=count;
        this.images=new HashSet<String>();
        this.images.addAll(Arrays.asList(imageNames));
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public Set<String> getImages() {
        return images;
    }

    public void setImages(Set<String> images) {
        this.images = images;
    }
}

7.ImageResult的实现

package com.robot.entiy;

import java.util.Set;

public class ImageResult {

    private String name;
    private Set<Integer> keySet;
    private String uniqueKey;
    private String tip;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Integer> getKeySet() {
        return keySet;
    }

    public void setKeySet(Set<Integer> keySet) {
        this.keySet = keySet;
    }

    public String getUniqueKey() {
        return uniqueKey;
    }

    public void setUniqueKey(String uniqueKey) {
        this.uniqueKey = uniqueKey;
    }

    public String getTip() {
        return tip;
    }

    public void setTip(String tip) {
        this.tip = tip;
    }
}

8.Cache的实现

package com.robot.until;


import com.robot.entiy.ImageResult;

import java.util.HashMap;
import java.util.Map;

public class Cache {
    private static Map<String, ImageResult> cache=new HashMap<String, ImageResult>();
    public static void put(String note,ImageResult ir){
        cache.put(note,ir);
    }
    public static ImageResult get(String note){
        return cache.get(note);

    }
    public static void remove(String note){
        cache.remove(note);
    }
}

9.Image的实现

package com.robot.until;



import com.robot.entiy.BufferedImageWarp;
import com.robot.entiy.GenerateImageGroup;
import com.robot.entiy.ImageGroup;
import com.robot.entiy.ImageResult;

import javax.imageio.ImageIO;
import javax.servlet.ServletRequest;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;


public class Image {

    private static Map<String, ImageGroup> imageGroupMap = new HashMap<String, ImageGroup>();
    private static Map<Integer, Map<String, ImageGroup>> countGroupMap = new HashMap<Integer, Map<String, ImageGroup>>();

    /**
     * 生成图片     * @throws IOException
     */
    public static ImageResult generateImage(ServletRequest request) throws IOException {
        initImage();
        GenerateImageGroup generateImageGroup = randImageGroups();
        List<BufferedImageWarp> imageWarps = new ArrayList<BufferedImageWarp>();
        String realPath = request.getServletContext().getRealPath("/assets/");

        for (ImageGroup group : generateImageGroup.getGroups()) {
            for (String imgName : group.getImages()) {
                imageWarps.add(new BufferedImageWarp(false, getBufferImage(realPath+File.separator+imgName)));
            }
        }
        for (String imgName : generateImageGroup.getKeyGroup().getImages()) {
            imageWarps.add(new BufferedImageWarp(true,getBufferImage(realPath+File.separator+imgName)));
        }

        return meregeImage(request,imageWarps, generateImageGroup.getKeyGroup().getName());

    }

    /**
     * 随机生成图片
     *
     * @return
     */
    public static GenerateImageGroup randImageGroups() {
        List<ImageGroup> result = new ArrayList<ImageGroup>();
        int num = random(0, imageGroupMap.size() - 1);
        //获取相关的需要选中的key
        String name = new ArrayList<String>(imageGroupMap.keySet()).get(num);
        ImageGroup keyGroup = imageGroupMap.get(name);

        Map<Integer, Map<String, ImageGroup>> thisCountGroup = new HashMap<Integer, Map<String, ImageGroup>>(countGroupMap);

        thisCountGroup.get(keyGroup.getCount()).remove(name);
        // 假设总量8个,每种名称图片只有2个或者4个,为了逻辑简单些
        int leftCount = 8 - keyGroup.getCount();
        if (leftCount == 4) {
            // 继续产生随机数
            if (new Random().nextInt() % 2 == 0) {
                //判断产生的随机数是否被二整除是则产生4个图片的组合
                List<ImageGroup> groups = new ArrayList<ImageGroup>(thisCountGroup.get(4).values());

                if (groups.size() > 1) {
                    num = random(0, groups.size() - 1);
                } else {
                    num = 0;
                }
                result.add(groups.get(num));
            } else {
                //为奇数的时候则是2个2个的组合
                List<ImageGroup> groups = new ArrayList<ImageGroup>(thisCountGroup.get(2).values());
                int num1 = random(0, groups.size() - 1);
                result.add(groups.get(num1));

                int num2 = random(0, groups.size() - 1, num1);
                result.add(groups.get(num2));
            }
        } else if (leftCount == 6) {
            if (new Random().nextInt() % 2 == 0) {
                //偶数2+4+2
                List<ImageGroup> groups1 = new ArrayList<ImageGroup>(thisCountGroup.get(4).values());
                int num1 = random(0, groups1.size() - 1);
                result.add(groups1.get(num1));

                List<ImageGroup> groups2 = new ArrayList<ImageGroup>(thisCountGroup.get(2).values());
                int num2 = random(0, groups2.size() - 1);
                result.add(groups2.get(num2));
            } else {
                List<ImageGroup> groups = new ArrayList<ImageGroup>(thisCountGroup.get(2).values());
                int num1 = random(0, groups.size() - 1);
                result.add(groups.get(num1));

                int num2 = random(0, groups.size() - 1, num1);
                result.add(groups.get(num2));

                int num3 = random(0, groups.size() - 1, num1, num2);
                result.add(groups.get(num3));
            }
        } else if (leftCount == 2) {
            List<ImageGroup> groups = new ArrayList<ImageGroup>(thisCountGroup.get(2).values());
            result.add(groups.get(random(0, groups.size() - 1)));
        }
        return new GenerateImageGroup(keyGroup, result);
    }


    private static BufferedImage getBufferImage(String fileUrl) throws IOException {
        //这个目录是你自己存放照片的目录,这里我存放在G盘下
        File f = new File(fileUrl);
        return ImageIO.read(f);
    }

    /**
     * 初始化图片
     */
    public static void initImage() {
        ImageGroup group1 = new ImageGroup("包包", 4, "baobao/1.jpg", "baobao/2.jpg", "baobao/3.jpg", "baobao/4.jpg");
        ImageGroup group2 = new ImageGroup("老虎", 4, "laohu/1.jpg", "laohu/2.jpg", "laohu/3.jpg", "laohu/4.jpg");
        ImageGroup group3 = new ImageGroup("糖葫芦", 4, "tanghulu/1.jpg", "tanghulu/2.jpg", "tanghulu/3.jpg", "tanghulu/4.jpg");
        ImageGroup group4 = new ImageGroup("小慕", 4, "xiaomu/1.jpg", "xiaomu/2.jpg", "xiaomu/3.jpg", "xiaomu/4.jpg");
        ImageGroup group5 = new ImageGroup("柚子", 4, "youzi/1.jpg", "youzi/2.jpg", "youzi/3.jpg", "youzi/4.jpg");
        ImageGroup group6 = new ImageGroup("订书机", 2, "dingshuji/1.jpg", "dingshuji/2.jpg");
        ImageGroup group7 = new ImageGroup("蘑菇", 2, "mogu/1.jpg", "mogu/2.jpg");
        ImageGroup group8 = new ImageGroup("磁铁", 2, "xitieshi/1.jpg", "xitieshi/2.jpg");
        ImageGroup group9 = new ImageGroup("土豆", 2, "tudou/1.jpg", "tudou/2.jpg");
        ImageGroup group10 = new ImageGroup("兔子", 2, "tuzi/1.jpg", "tuzi/2.jpg");
        ImageGroup group11 = new ImageGroup("仙人球", 2, "xianrenqiu/1.jpg", "xianrenqiu/2.jpg");

        initMap(group1, group2, group3, group4, group5, group6, group7, group8, group9, group10, group11);
    }

    /**
     * 初始化图     * @param groups
     */
    public static void initMap(ImageGroup... groups) {
        for (ImageGroup group : groups) {
            imageGroupMap.put(group.getName(), group);
            if (!countGroupMap.containsKey(group.getCount())) {
                countGroupMap.put(group.getCount(), new HashMap<String, ImageGroup>());
            }
            countGroupMap.get(group.getCount()).put(group.getName(), group);
        }
    }

    /**
     * 获取随机数
     */
    private static int random(int min, int max) {
        Random random = new Random();
        return random.nextInt(max - min + 1) + min;
    }

    private static int random(int min, int max, Integer... not) {
        int num = random(min, max);
        List<Integer> notList = Arrays.asList(not);
        while (notList.contains(num)) {
            num = random(min, max);
        }
        return num;
    }


    private static ImageResult meregeImage(ServletRequest request, List<BufferedImageWarp> imageWarps, String tip) throws IOException {
        Collections.shuffle(imageWarps);
        int width = 100;
        int height = 100;
        int totalWidth = width*4;

        BufferedImage destImage = new BufferedImage(totalWidth, 200, BufferedImage.TYPE_INT_BGR);
        int x1 = 0;
        int x2 = 0;
        int order = 0;
        List<Integer> keyOrderList = new ArrayList<Integer>();
        StringBuilder keysOrder = new StringBuilder();
        Set<Integer> keySet = new HashSet<Integer>();
        for (BufferedImageWarp image : imageWarps) {
            int[] rgb = image.getBufferedImage().getRGB(0, 0, width, height, null, 0, width);
            if (image.isKey()) {
                keyOrderList.add(order);
                int x = (order % 4) * 200;
                int y = order < 4 ? 0 : 200;
                keySet.add(order);
                keysOrder.append(order).append("(").append(x).append(",").append(y).append(")|");
            }
            if (order < 4) {
                destImage.setRGB(x1, 0, width, height, rgb, 0, width);
                x1 += width;
            } else {
                destImage.setRGB(x2, height, width, height, rgb, 0, width);
                x2 += width;
            }
            order++;
        }
        keysOrder.deleteCharAt(keysOrder.length() - 1);
        System.out.println("答案的位置:" + keysOrder);
        String fileName = UUID.randomUUID().toString().replaceAll("-", "");
        String fileUrl=request.getServletContext().getRealPath("assets/daan/")+File.separator+fileName+".jpg";
        saveImage(destImage, fileUrl, "jpeg");

        ImageResult ir = new ImageResult();
        ir.setName(fileName + ".jpg");
        ir.setKeySet(keySet);
        ir.setUniqueKey(fileName);
        ir.setTip(tip);
        return ir;
    }

    private static boolean saveImage(BufferedImage destImage, String fileUrl, String format) throws IOException {
        File file = new File(fileUrl);
        return ImageIO.write(destImage, format, file);
    }


}

11.web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-servlet.xml</param-value>
    </context-param>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.png</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpeg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.ico</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-servlet.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>



    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

 

 

 

相关标签: 图片验证码