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

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

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

3.目录结构

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>

猜你喜欢

转载自blog.csdn.net/robot_sh/article/details/81870579