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>