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>













