zoukankan      html  css  js  c++  java
  • 基于慕课网-----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>
  • 相关阅读:
    rabbitmq使用
    redis
    IO模型与IO复用介绍
    事件驱动与异步IO使用
    协程
    进程
    线程、锁
    paramiko模块与 StringIO模块
    socketserver 编程
    随记
  • 原文地址:https://www.cnblogs.com/robotsh/p/14131008.html
Copyright © 2011-2022 走看看