转载请注明出处:http://blog.csdn.net/qq_26525215

本文源自【大学之旅_谙忆的博客】

说明

GIF验证码相对于JPG图片验证码来说,要更难破解一些,加大了破解的代价。
从昨天到现在,写了一个小小的GIF验证码项目(中文成语)。
当然,你可以自己修改成字母数字的。我只是单纯的觉得中文验证码的破解代价更高一点~

我在这里生成GIF图片的类,用到了国外牛人的三个类,也就是:
AnimatedGifEncoder
LZWEncoder
和NeuQuant,这三个类。

没办法,谁让自己还没有那个本事写出这样的类呢,只能用别人的,不过挺好用飞,大家可以搜索一下这3个类,一下就能搜出源码的。
在这里,我就不贴出这三个类的源码了,需要的,可以在本文最后的项目链接拿整个项目,其中有所有源代码。

本来一开始是写的字母和数字生成的GIF验证码,后来还是改成了汉字成语验证码。

在这里,我并没有用数据库来存储成语,因为重点不在哪里,所以就只是建立了一个静态块来先写入成语。
(如果是实际开发,我可能会这样做:
以便于管理员在后台可以添加成语到验证码成语库,以及可以刷新验证码到成语库中,所以,可以在一个请求方法中操作成语。
如果用来Redis,基本上也是一样,实现同步就行。)

GIF验证码类

package cn.hncu.utils;import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;/*** Created with IntelliJ IDEA.* User: 陈浩翔.* Date: 2017/3/6.* Time: 下午 8:23.* Explain:Gif验证码类*/
public class GifCaptcha {private Font font = new Font("宋体", Font.BOLD, 20); // 字体private int width = 160; // 验证码显示长度private int height = 40; // 验证码显示高度private String word = ""; // 当前的字符串private int delay = 100; // 帧延迟 (默认100)private int quality = 10;//量化器取样间隔 - 默认是10msprivate int repeat = 0; // 帧循环次数private int minColor =0;//设置随机颜色时,最小的取色范围private int maxColor = 255;//设置随机颜色时,最大的取色范围private int right = 0; //设置字符最右边的相对位置---相对原始位置 ,默认为0private static java.util.List<String> words = new ArrayList<String>();// 所有成语//这里应该去数据库中读取成语,然后存储在内存中//在实际开发中,应该是可以在后台中添加成语,以及刷新成语到内存中去!利用访问某个方法来实现static {words.add("一唱一和");words.add("一呼百应");words.add("一干二净");words.add("一举两得");words.add("一落千丈");words.add("两面三刀");words.add("六神无主");words.add("千辛万苦");words.add("万无一失");words.add("拔刀相助");words.add("过时黄花");words.add("地动山摇");words.add("不可多得");words.add("沧海一粟");words.add("水泄不通");words.add("不可计数");}/*** 空参构造函数*/public GifCaptcha() {}/*** 可以设置验证码宽度,高度的构造函数* @param width -验证码宽度* @param height -验证码高度*/public GifCaptcha(int width, int height) {this.width = width;this.height = height;}/**** @param width -验证码宽度* @param height -验证码高度* @param font -字体*/public GifCaptcha(int width, int height,  Font font) {this(width, height);this.font = font;}/*** @param width -验证码宽度* @param height -验证码高度* @param font -字体* @param delay -帧延迟*/public GifCaptcha(int width, int height, Font font,int delay) {this(width, height,font);this.delay = delay;}public Font getFont() {return font;}/*** 设置字体* @param font*/public void setFont(Font font) {this.font = font;}public int getWidth() {return width;}/*** 设置验证码宽度* @param width*/public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}/*** 设置验证码高度* @param height*/public void setHeight(int height) {this.height = height;}public String getWord() {return word;}/*** 设置验证码字符* @param chars*/public void setWord(String chars) {this.word = chars;}public int getDelay() {return delay;}/*** 设置每一帧之间的延迟时间,或改变它的后续帧(适用于最后一帧添加)。* @param delay 单位是毫秒*/public void setDelay(int delay) {this.delay = delay;}public int getQuality() {return quality;}/*** 设置图像的颜色量化(转换质量 由GIF规范允许的最大256种颜色)。* 低的值(最小值= 1)产生更好的颜色,但处理显著缓慢。* 10是默认,并产生良好的颜色而且有以合理的速度。* 值更大(大于20)不产生显著的改善速度* @param quality 大于1*/public void setQuality(int quality) {if(quality<1){quality=1;}this.quality = quality;}public int getRepeat() {return repeat;}/*** 设置GIF帧应该播放的次数。* 默认是 0; 0意味着无限循环。* 必须在添加的第一个图像之前被调用。* @param repeat 必须大于等于0*/public void setRepeat(int repeat) {if (repeat>=0) {this.repeat = repeat;}}public int getRight() {return right;}public void setRight(int right) {this.right = right;}public int getMaxColor() {return maxColor;}public void setMaxColor(int maxColor) {this.maxColor = maxColor;}public int getMinColor() {return minColor;}public void setMinColor(int minColor) {this.minColor = minColor;}/*** 给定一个输出流 输入图片* @param os*/public void out(OutputStream os) {try {AnimatedGifEncoder gifEncoder = new AnimatedGifEncoder();// gif编码类//生成字符gifEncoder.start(os);gifEncoder.setQuality(quality);//设置量化器取样间隔gifEncoder.setDelay(delay);//设置帧延迟gifEncoder.setRepeat(repeat);//帧循环次数BufferedImage frame;char[] rands = createWordChar();Color fontcolor[] = new Color[word.length()];for (int i = 0; i < word.length(); i++) {fontcolor[i] = getRandomColor(minColor,maxColor);}for (int i = 0; i < word.length(); i++) {frame = graphicsImage(fontcolor, rands, i);gifEncoder.addFrame(frame);frame.flush();}gifEncoder.finish();} finally {try {os.close();} catch (IOException e) {// TODO 异常处理e.printStackTrace();}}}/*** 画随机码图** @param fontcolor 随机字体颜色* @param strs      字符数组* @param flag      透明度使用* @return BufferedImage*/private BufferedImage graphicsImage(Color[] fontcolor, char[] strs, int flag) {BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//或得图形上下文Graphics2D g2d=image.createGraphics();//Graphics2D g2d = (Graphics2D) image.getGraphics();//利用指定颜色填充背景g2d.setColor(Color.WHITE);g2d.fillRect(0, 0, width, height);AlphaComposite ac;float y = (height >> 1) + (font.getSize() >> 1) ;// 字符的y坐标float m = (width-(word.length()*font.getSize()))/word.length();float x = m/2;//字符的x坐标g2d.setFont(font);for (int i = 0; i < word.length(); i++) {ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getPellucidity(flag, i));g2d.setComposite(ac);g2d.setColor(fontcolor[i]);g2d.drawOval(Randoms.num(width), Randoms.num(height), Randoms.num(5,30), 5 + Randoms.num(5,30));//绘制椭圆边框g2d.drawString(strs[i] + "",x+(font.getSize()+m)*i+right,y);}g2d.dispose();return image;}/*** 获取透明度,从0到1,自动计算步长* @return float 透明度*/private float getPellucidity(int i, int j) {int num = i + j;float r = (float) 1 / word.length(), s = (word.length() + 1) * r;return num > word.length() ? (num * r - s) : num * r;}/*** 生成随机字符数组* @return 字符数组*/protected char[] createWordChar() {word = words.get(Randoms.num(words.size()));return word.toCharArray();}/*** 通过给定范围获得随机的颜色* @return Color 获得随机的颜色*/protected Color getRandomColor(int min, int max) {if (min > 255) {min = 255;}if (max > 255) {max = 255;}if(min<0){min=0;}if(max<0){max=0;}if(min>max){min=0;max=255;}return new Color(min + Randoms.num(max - min), min + Randoms.num(max - min), min + Randoms.num(max - min));}
}

注释没写很多~有点懒~

请求GIF验证码的Controller类

package cn.hncu.controller;import cn.hncu.utils.GifCaptcha;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.io.IOException;/*** Created with IntelliJ IDEA.* User: 陈浩翔.* Date: 2017/3/6.* Time: 下午 8:26.* Explain:演示GIF验证码的控制器*/
@Controller
public class CaptchaController {private Logger logger = LoggerFactory.getLogger(CaptchaController.class);/*** 获取Gif验证码* @param response*/@RequestMapping(value = "gifCaptcha",method= RequestMethod.GET)public void getGifCaptcha(HttpServletResponse response,HttpServletRequest request){//告诉客户端,输出的格式response.setHeader("Pragma", "No-cache");response.setHeader("Cache-Control", "no-cache");response.setDateHeader("Expires", 0);response.setContentType("image/gif");GifCaptcha gifCaptcha =  new GifCaptcha(200,80,new Font("宋体", Font.BOLD, 40),100);try {gifCaptcha.out(response.getOutputStream());logger.info("获取验证码!验证码字符为:"+gifCaptcha.getWord());HttpSession session = request.getSession(true);//存入Sessionsession.setAttribute("captchaWord",gifCaptcha.getWord());} catch (IOException e) {e.printStackTrace();}}@RequestMapping("index")public String index()    {return "index";}}

JSP页面

<%--Created by IntelliJ IDEA.User: 陈浩翔Date: 2017/3/6Time: 下午 8:24To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>演示动态验证码</title><script type="text/javascript">var path = "${pageScope.basePath}";function changImg() {var img = document.getElementById("servletImg");var d = new Date();var time = d.getTime();//如果没有这个,下面的img.src = path + "gifCaptcha?" + time;不会起作用,因为浏览器的缓存技术,图片可能并不会刷新img.src = "";//解决火狐下验证码刷不出的问题img.src = path + "gifCaptcha?" + time;//?号后面的东西是通过get方式传递的}</script>
</head>
<body>
演示动态验证码:
<a onclick="javascript:changImg();" href="javascript:void(0);"><img id="servletImg" src="gifCaptcha" alt="UIFuture验证码"/>
</a>
</body>
</html>

演示效果

大家其实可以看到,在我点击验证码的时候,有一个小停顿,会显示alt的内容,那是因为我在JS中,2次赋值给img的src属性。
原因是为了解决火狐浏览器显示GIF图的一个问题,如果我不加那个img.src = “”;,在刷新验证码2次后,验证码gif图只显示第一帧!也就是变成了静态图~但是接收到的图片其实还是GIF动图。
我加img.src = “”;,就只是为了解决火狐上验证码刷新2次后会变成静图的问题,该问题在谷歌浏览器,以及360浏览器上没有出现!

有知道原因的请评论,谢谢

出问题的是下面这样的情况,在第三次点击图片刷新时(此时用的是同一张图片,随机图片出现的问题是一样的,也就是只显示GIF动图的第一帧图片)(火狐浏览器)

谷歌浏览器,360浏览器没有出现该问题。

本篇博客涉及到的源码链接:

【->点击访问源码-©CHX】

本文章由[谙忆]编写, 所有权利保留。
欢迎转载,分享是进步的源泉。

转载请注明出处:http://blog.csdn.net/qq_26525215

本文源自【大学之旅_谙忆的博客】

【Web】Java生成中文GIF动态验证码-集成SpringMVC相关推荐

  1. 解决Linux下Java生成中文文件和文件夹乱码

    情况: java代码在本地生成文件的程序,在linux中运行后,生成的文件全部是乱码. 拷贝中文文件名的文件到linux显示正常. 原因: 程序中的部分代码发生乱码. 解决办法: 在/etc/prof ...

  2. java 中文字体_Linux 添加中文字体库,解决Java 生成中文水印不显示问题

    本机 Windows 环境测试以下代码生成中文水印完全没问题,但是发布到Linux下不显示,一开始以为是报错了没打印出来,搜索发现直接提示中文乱码的或者不显示的,才明白原来是字体库原因,于是开始解决这 ...

  3. Linux下使用ssh动态验证码登陆机器

    ssh动态验证码登录机器 Google Authenticator是一个动态验证码程序,兼容各种智能手机平板设备,可以用来做各种帐号的二次验证,增加帐号的安全性.SSH是Linux系统的最重要防线之一 ...

  4. java 图形校验_java图形验证码生成工具类 web页面校验验证码

    java图形验证码生成工具类 web页面校验验证码 发布于 2020-7-14| 复制链接 摘记: 最近做验证码,参考网上案例,发现有不少问题,特意进行了修改和完善.验证码生成器: ```java i ...

  5. java验证码验证码_Java登录页面实时验证用户名密码和动态验证码

    ●登录名和密码是同时验证的,并不是先验证登录名是否存在,然后再验证密码是否正确,是同时进行验证,若登录名和密码当中一个条件不符合,则提示用户登录名或者密码错误, 这样做的意义是为了保证用户信息的安全( ...

  6. Java登录页面实时验证用户名密码和动态验证码

    ●登录名和密码是同时验证的,并不是先验证登录名是否存在,然后再验证密码是否正确,是同时进行验证,若登录名和密码当中一个条件不符合,则提示用户登录名或者密码错误, 这样做的意义是为了保证用户信息的安全( ...

  7. javaweb生成中文验证码

    javaweb生成中文验证码 整理一份四字的文字列表的text文档 配置web.xml 创建java代码 书写index.jsp访问页 看到有的网页的验证码是中文的,就想着自己也写一个,百度了下有关知 ...

  8. Java实现pdf和Excel的生成及数据动态插入、导出

    点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 作者:慢时光 cnblogs.com/Tom-shushu/ ...

  9. java生成验证码实例_Java生成验证码功能实例代码

    页面上输入验证码是比较常见的一个功能,实现起来也很简单.给大家写一个简单的生成验证码的示例程序,需要的朋友可以借鉴一下. 闲话少续,直接上代码.代码中的注释很详细. package com.SM_te ...

  10. java生成验证码工具类_Java生成图形验证码工具类

    生成验证码效果 validatecode.java 验证码生成类 package cn.dsna.util.images; import java.awt.color; import java.awt ...

最新文章

  1. QT中在Designer中设置QToolButoon上面图标下面文字
  2. 旧文 | 舒迅:产品经理必读的九步法
  3. 【Elasticsearch】Elasticsearch底层系列之Shard Allocation机制
  4. Python int() 函数
  5. Django:应用程序的两种架构:C/S架构,B/S架构,(TCP, URL)HTTP,HTTP request, HTTP response
  6. mysql 测试 缓存_mysql 缓存开启及测试
  7. vue.js devtools安装
  8. 【BZOJ4503】两个串(FFT)
  9. linux之程序包管理器(rpm)
  10. 实战-全局唯一邀请码功能实现
  11. VC2005工程常用设置系统环境变量设置
  12. python同花顺交易接口_TradeApi为A股程序化交易接口2.9.0发布
  13. unity 暂停按钮_Unity VideoPlayer教程之 视频播放暂停切换
  14. android studio 添加 ignored files 忽略文件
  15. Bootstrap -Card卡片
  16. Hadoop实战——MapReduce对英文单词文本进行统计和排序(超详细教学,算法分析)
  17. LeetCode第1143题最长公共子序列
  18. Xbox One的Unity在这里!
  19. NER任务中BERT-CRF 模型的英文数据padding与aligning
  20. 线性系统的校正之串联校正

热门文章

  1. python发送qq邮件失败_基于python语言发送QQ邮件
  2. Springboot——使用jxls实现excel模板导出excel
  3. 如何看待勘察设计工程师报名条件放宽
  4. 【HTML——旋转火焰】(效果+代码)
  5. 云机房中计算机上网速度太慢,云桌面技术在计算机机房管理中的运用
  6. 下一步我向何处去?答女大学生的来信——网上答疑(24)
  7. 每天5分钟玩转Linux系列-CentOS7x64 1810安装tree树形目录显示工具
  8. 深度解读:数学的本质与宇宙万物的关联--数学的本质是一门语言
  9. 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一2.13 斜线构图
  10. vns可变领域_安永解读2020年12月财政部新收入准则应用案例