java生成简单验证码图片
概要
最近项目需要用java实现输出随机验证码图片到前台,正好有机会接触下java的绘图类,完成需求后也有时间做个总结,写篇随笔记录下也希望能帮助到有同样需求的人!
需求流程图

1.生成随机数
在java中生成随机数无非就是调用Random的api,但为了后续更好的实用,应该分成多种组合以适应需求的变化,应将生成随机数的个数和类型组合还有排除字符抽取成参数,这个也比较简单,没有什么难度,就直接贴上代码
/**
* 生成随机验证码
* @param type 类型
* @param length 长度
* @param exChars 排除的字符
* @return
*/
public static String getRandomCode(int type,int length,String exChars){
case TYPE_NUM_CHAR://数字+(大小写)字母
while(i<length){
int t=random.nextInt(123);
if((t>=97||(t>=65&&t<=90)||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
sb.append((char)t);
i++;
}
}
break; }
2.绘制图片
绘制图片是重点也是难点,老实说我之前都没用过BufferedImage、Graphics、Color等对象,都是从度娘处脑补并结合帖子写出来的输出图片
1)创建BufferedImage对象
如果把BufferedImage比作是画板,那么Graphics就是画纸,这样比较好理解,后续的操作都是在这画纸上进行的
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
//随机操作对象
Random r=new Random();
2)绘制背景
Graphics有个setColor()方法,可理解为画笔,在绘制任何东西前要选好画笔,即颜色,然后调用fillRect()进行轮廓的绘制,后续的绘制范围不会超过这个轮廓
g.setColor(backColor==null?getRandomColor():backColor);
g.fillRect(0,0,width,height);
3)绘制干扰线
调用drawLine画直线,绘制不超过interLine条干扰线
if(interLine>0){
int x=r.nextInt(4),y=0;
int x1=width-r.nextInt(4),y1=0;
for(int i=0;i<interLine;i++){
g.setColor(lineColor==null?getRandomColor():lineColor);
y=r.nextInt(height-r.nextInt(4));
y1=r.nextInt(height-r.nextInt(4));
g.drawLine(x,y,x1,y1);
}
}
4)写验证码
写验证码时调用drawString()方法,为了不整整齐齐而且重叠的写,应将每个字符的高度和水平位置随机,重点在于每绘制完一个字符后,需将画笔的水平坐标往右边移动一定的位置,这里我用了依据宽度浮动,可不必照搬这里的,有合适的算法就行
int fsize=(int)(height*0.8);//字体大小为图片高度的80%
int fx=0;
int fy=fsize;
g.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,fsize));
//写字符
for(int i=0;i<textCode.length();i++){
fy=randomLocation?(int)((Math.random()*0.3+0.6)*height):fy;//每个字符高低是否随机
g.setColor(foreColor==null?getRandomColor():foreColor);
g.drawString(textCode.charAt(i)+"",fx,fy);
fx+=(width / textCode.length()) * (Math.random() * 0.3 + 0.8); //依据宽度浮动
}
5)扭曲图片
图片的扭曲就是将图片水平和垂直按不同比例平移,copyArea()方法简单明了,直接是复制区域,也是同个意识
//扭曲图片
shearX(g, width, height, backColor);
shearY(g, width, height, backColor);
private static void shearX(Graphics g, int w1, int h1, Color color) {
Random random=new Random();
int period = 2; boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2); for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)* Math.sin((double) i / (double) period
+ (2.2831853071795862D * (double) phase)/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
} } private static void shearY(Graphics g, int w1, int h1, Color color) {
Random random=new Random();
int period = random.nextInt(40) + 10; // 50; boolean borderGap = true;
int frames = 20;
int phase = random.nextInt(2);
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (2.2831853071795862D * (double) phase)/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
} } }
6)添加噪点
噪点的添加实质上就是在画纸上没有规律的点点点...,所以用随机颜色随机位置来执行image.setRGB()方法最合适了
float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * width * height);//噪点数量
for (int i = 0; i < area; i++) {
int xxx = r.nextInt(width);
int yyy = r.nextInt(height);
int rgb = getRandomColor().getRGB();
image.setRGB(xxx, yyy, rgb);
}
7)封笔
以上一切画完之后,下一步就是封笔了,思来想去这样表达最合适,绘制完之后就是放好笔,收起画纸,这里就是返回BufferedImage对象
g.dispose();
return image;
输出目标位置
1)输出文件
这里写了一个简单的测试类,将图片输出成文件
public static void main(String[] args) {
String randomCode = CodeUtils.getRandomCode(CodeUtils.TYPE_NUM_CHAR, 4, null);
System.out.println(randomCode);
BufferedImage imageFromCode = ImageUtils.getImageFromCode(randomCode, 100, 50, 3, true, Color.WHITE, Color.BLACK, null);
try {
File file = new File("d:/test01.jpg");
ImageIO.write(imageFromCode,"jpg",file);
System.out.println("成功保存到:"+file.getAbsolutePath());
} catch (IOException e) {
System.out.println("保存失败");
e.printStackTrace();
}
}
效果图:

2)输出流
输出到流中也是用到和到文件中的方法,根据业务保存到目标位置即可
public static void outputStream(HttpServletRequest request,HttpServletResponse response){
try {
// 设置浏览器不缓存本页
response.addHeader("Pragma", "no-cache");
response.addHeader("Cache-Control", "no-cache");
response.addHeader("Expires", "0");
// 生成验证码,写入用户session
String verifyCode = CodeUtils.getRandomCode(CodeUtils.TYPE_NUM_CHAR, 4, null);
request.getSession().setAttribute("imageVerify", verifyCode);
// 输出验证码给客户端
response.setContentType("image/jpeg");
BufferedImage bim = ImageUtils
.getImageFromCode(verifyCode, 47, 18, 3, true,
Color.WHITE, Color.BLACK, null);
ImageIO.write(bim, "JPEG", response.getOutputStream());
} catch (Exception e) {
}
return null;
}
总结
也没有比较深入的去分析绘制类,有需求可以通过调整位置参数来实现自己要的效果
java生成简单验证码图片的更多相关文章
- java生成随机验证码图片
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; i ...
- java 生成简单word(利用Itext工具),生成简单Excel,以及下载笔记
1.java 生成简单word(包含图片表格) pom中加入itext 相关依赖 <dependency> <groupId>com.lowagie</groupId&g ...
- struts2生成随机验证码图片
之前想做一个随机验证码的功能,自己也搜索了一下别人写的代码,然后自己重新用struts2实现了一下,现在将我自己实现代码贴出来!大家有什么意见都可以指出来! 首先是生成随机验证码图片的action: ...
- java生成汉字验证码
java实现的汉字输入验证码,主要包含两个类,一个是生成验证码,一个是判断验证码输入是否正确,实现原理非常简单,将汉字和干扰线生成图片并将汉字保存到session,前台获取每次生成验证码图片并用文本框 ...
- Java生成随机验证码
package com.tg.snail.core.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphic ...
- java生成简单Excel工作薄
前言: 代码都是建立在实际需求上的,上周做完一个调外部电影券接口的项目,这周产品又要excel表格,大致内容为:券所属影院.图片URL.等信息制作为excel表格,把每次同步过来的数据给他分析. jx ...
- 如何用java生成随机验证码
1.VerifyCode 类: 1 package com.HRuinger.enity; ImageIO.write(image, " ...
- java生成图形验证码
效果图 import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.Buf ...
- Python利用PIL生成随机验证码图片
安装pillow: pip install pillow PIL中的Image等模块提供了创建图片,制作图片的功能,大致的步骤就是我们利用random生成6个随机字符串,然后利用PIL将字符串绘制城图 ...
随机推荐
- es6 this指向
在非箭头函数中,谁调用的函数,this指向就是谁: var obj={ fn:function(){ console.log(this); } } obj.fn();//object 如果this出现 ...
- 7th week blog
DOM:Document Object Model(文档对象模型) Document Object Model的历史可以追溯至1990年代后期微软与Netscape的“浏览器大战”,双方为了在Java ...
- C++动态链接库方法调用
//定义内存的信息结构 [StructLayout(LayoutKind.Sequential)] public struct MEMORY_INFO { public uint dwLength; ...
- C语言中sizeof、strlen函数的部分理解
一.测试环境 Win10 + Visual Studio 2017 二.测试代码 #include "pch.h" #include <iostream> #inclu ...
- 【python】闭包
一.闭包满足的条件 闭包 = 内部函数 + 定义函数的环境 条件一 : 内部函数 条件二: 外部环境的变量 二.实战 def outer(): x = 10 y = 20 def inner(): p ...
- git 创建删除分支
进入仓库目录 -- 查看本地分支 git branch -- 查看远程分支 git branch -r -- 查看远程和本地的分支 git branch -a -- 下载远程分支代码,并切换到分支 进 ...
- Java Native
native 什么是Native Method 简单地讲,一个Native Method就是一个java调用非java代码的接口.一个Native Method是这样一个java的方法:该方法的实现由 ...
- 第七节《Git协议与工作协同》
Git提供了丰富的协议支持,包括:SSH.GIT.HTTPS.FTP.FTPS.RSYNC,这些协议可以分为两类:智能协议和哑协议. <1>智能协议 在会话时使用智能协议,会在会话的两个版 ...
- Event对象中的target属性和currentTarget属性的区别
先上结论: Event.target:触发事件的元素: Event.currentTarget:事件绑定的元素: 通过下面的例子来理解这两个属性的区别: 使用Event.target属性的例子:(我在 ...
- MySQL Hardware--Linux 文件句柄限制
Linux会限制文件句柄数量,默认为1024,当超过该阈值后,会报"to many open files" ## 使用ulimit -a查看当前打开文件句柄限制 ulimit -a ...