java web图片验证码
java web图片验证码
1.验证码的作用:
防止恶意破解密码、刷票、论坛灌水、刷页。
有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试,实际上使用验证码是现在很多网站通行的方式(比如招商银行的网上个人银行,百度社区),我们利用比较简易的方式实现了这个功能。虽然登录麻烦一点,但是对网友的密码安全来说这个功能还是很有必要,也很重要。但我们还是 提醒大家要保护好自己的密码 ,尽量使用混杂了数字、字母、符号在内的6位以上密码,不要使用诸如1234之类的简单密码或者与用户名相同、类似的密码 ,免得你的账号被人盗用给自己带来不必要的麻烦。
验证码通常使用一些线条和一些不规则的字符组成,主要作用是为了防止一些黑客把密码数据化盗取。
2.服务端
2.1.验证码生成工具类
package com.dzqc.dz.common.controller;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;
/**
* 验证码生成工具类
*/
public class ValidateCode {
// 图片的宽度。
private int width = 160;
// 图片的高度。
private int height = 40;
// 验证码字符个数
private int codeCount = 5;
// 验证码干扰线数
private int lineCount = 150;
// 验证码
private String code = null;
// 验证码图片Buffer
private BufferedImage buffImg = null;
// 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了)
private char[] codeSequence = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
/**
* 默认构造函数,设置默认参数
*/
public ValidateCode() {
this.createCode();
}
/**
* @param width 图片宽
* @param height 图片高
*/
public ValidateCode(int width, int height) {
this.width = width;
this.height = height;
this.createCode();
}
/**
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param lineCount 干扰线条数
*/
public ValidateCode(int width, int height, int codeCount, int lineCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
this.lineCount = lineCount;
this.createCode();
}
public void createCode() {
int x = 0, fontHeight = 0, codeY = 0;
int red = 0, green = 0, blue = 0;
x = width / (codeCount + 2);//每个字符的宽度(左右各空出一个字符)
fontHeight = height - 2;//字体的高度
codeY = height - 4;
// 图像buffer
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();
/*// 将图像背景填充为白色
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);*/
// 增加下面代码使得背景透明
buffImg = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g.dispose();
g = buffImg.createGraphics();
// 背景透明代码结束
// 画图BasicStroke是JDK中提供的一个基本的画笔类,我们对他设置画笔的粗细,就可以在drawPanel上任意画出自己想要的图形了。
g.setColor(new Color(255, 0, 0));
g.setStroke(new BasicStroke(1f));
g.fillRect(128, 128, width, height);
// 生成随机数
Random random = new Random();
//设置字体类型、字体大小、字体样式
Font font = new Font("微软雅黑",Font.PLAIN, fontHeight);
g.setFont(font);
for (int i = 0; i < lineCount; i++) {
// 设置随机开始和结束坐标
int xs = random.nextInt(width);//x坐标开始
int ys = random.nextInt(height);//y坐标开始
int xe = xs + random.nextInt(width / 8);//x坐标结束
int ye = ys + random.nextInt(height / 8);//y坐标结束
// 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
g.setColor(new Color(red, green, blue));
g.drawLine(xs, ys, xe, ye);
}
// randomCode记录随机产生的验证码
StringBuffer randomCode = new StringBuffer();
// 随机产生codeCount个字符的验证码。
for (int i = 0; i < codeCount; i++) {
String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
// 产生随机的颜色值,让输出的每个字符的颜色值都将不同。
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
//指定某种颜色
//g.setColor(new Color(252, 145, 83));
g.setColor(new Color(red, green, blue));
g.drawString(strRand, (i + 1) * x, codeY);
// 将产生的四个随机数组合在一起。
randomCode.append(strRand);
}
// 将四位数字的验证码保存到Session中。
code = randomCode.toString();
}
public void write(String path) throws IOException {
OutputStream sos = new FileOutputStream(path);
this.write(sos);
}
public void write(OutputStream sos) throws IOException {
ImageIO.write(buffImg, "png", sos);
sos.close();
}
public BufferedImage getBuffImg() {
return buffImg;
}
public String getCode() {
return code;
}
/**
* 测试函数,默认生成到d盘
* @param args
*/
public static void main(String[] args) {
ValidateCode vCode = new ValidateCode(160,40,5,150);
try {
String path="D:/"+new Date().getTime()+".png";
System.out.println(vCode.getCode()+" >"+path);
vCode.write(path);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2.控制层代码:
package com.dzqc.dz.common.controller;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.dzqc.dz.common.util.MyAjaxResult;
@Controller
@RequestMapping("/test")
public class TestControllers {
/**
* 跳转页面
* @param session
* @param id
* @return
*/
@RequestMapping("/login")
public String login() {
return "loginTest";
}
/**
* 获取验证码图片
* @param request
* @param response
* @throws IOException
*/
@RequestMapping("/user/check")
public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 通知浏览器不要缓存
response.setHeader("Expires", "-1");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "-1");
ValidateCode vCode = new ValidateCode(160,40,5,150);
// 将验证码输入到session中,用来验证
String code=vCode.getCode();
request.getSession().setAttribute("code", code);
// 输出到web页面
ImageIO.write(vCode.getBuffImg(), "jpg", response.getOutputStream());
}
@RequestMapping("/submit")
@ResponseBody
public MyAjaxResult submit(HttpSession session,String username,String password,String judge) {
if(username==null||"".equals(username)) {
return MyAjaxResult.fail_300("请输入用户名");
}
if(password==null||"".equals(password)) {
return MyAjaxResult.fail_300("请输入密码");
}
if(judge==null||"".equals(judge)) {
return MyAjaxResult.success("请输入验证码");
}
Object code=session.getAttribute("code");
if(code==null) {
return MyAjaxResult.fail_300("验证码错误,请刷新验证码");
}else {
if(!judge.equals(code.toString())) {
session.removeAttribute("code");
return MyAjaxResult.fail_500("验证码错误");
}
}
session.removeAttribute("code");
return MyAjaxResult.success("登陆成功");
}
}
3.jsp页面
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>login test</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
</head>
<body>
用户名<input type="text" value="" name="username" id="username"><br>
密码<input type="password" value="" name="password" id="password"><br><br>
<img alt="验证码" src="${path}/test/user/check" id="img"><br><br>
验证码<input type="text" value="" name="judge" id="judge"><br>
<input type="button" value="提交" id="sub"><br>
<script type="text/javascript">
$(function(){
$("#img").click(function(){
var url = "${path}/test/user/check?number="+Math.random();
$("#img").attr("src",url);
})
$("#sub").click(function(){
$.ajax({
url:'${path}/test/submit',
dataType:'json',
type:'post',
data:{
username:$("#username").val(),
password:$("#password").val(),
judge:$("#judge").val()
},
success:function(res){
alert(res.msg)
if(res.code==500){
var url = "${path}/test/user/check?number="+Math.random();
$("#img").attr("src",url);
}
},
error:function(res){
alert("网络错误");
}
})
})
})
</script>
</body>
</html>
评论区
请写下您的评论...
猜你喜欢
框架
1284
/groupIdartifactIdkaptcha/artifactIdversion${kaptcha.version}/version/dependency生成验证码的配置类importcom.google
工具
1839
java正则表达式同时验证手机号或电话号码importjava.util.regex.Matcher;importjava.util.regex.Pattern;publicclassPhone
工具
2645
/versionclassifierjdk15/classifier/dependencydependency groupIdcom.aliyun/groupId artifactIdaliyun-java-sdk-core/
blog
java(身份证号,手机号等)验证总结
工具
2451
验证packagecom.dzqc.dz.main.util;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/***验证
blog
java base64转图片工具
工具
1677
工具类packagecom.dzqc.yx.util;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importsun.misc.BASE64Decoder;impo
blog
java五子棋(AI)
数据结构与算法
2352
java实现五子棋人机对战packagefir;importjava.awt.*;importjavax.swing.JPanel;/***有背景图片的Panel类*@authortntxia
blog
Aspose实现word转图片、pdf
其他
1054
式:Word,Excel,PowerPoint,Project,等office文档以及PDF文档。除了强大的文件操纵组件之外,Aspose.Total还提供了用于制图、写电子邮件、拼写检查、创建条形码、
weblog
5441
前言之前的博客中提到了floyd最短路径算法,此算法的优点是,简单易懂,核心算法代码只有5行,但是缺点是时间复杂度o(n3),时间复杂度太高。而下面要介绍的Dijkstra算法虽然设计上略有复杂,但
最新发表
归档
2018-11
12
2018-12
33
2019-01
28
2019-02
28
2019-03
32
2019-04
27
2019-05
33
2019-06
6
2019-07
12
2019-08
12
2019-09
21
2019-10
8
2019-11
15
2019-12
25
2020-01
9
2020-02
5
2020-03
16
2020-04
4
2020-06
1
2020-07
7
2020-08
13
2020-09
9
2020-10
5
2020-12
3
2021-01
1
2021-02
5
2021-03
7
2021-04
4
2021-05
4
2021-06
1
2021-07
7
2021-08
2
2021-09
8
2021-10
9
2021-11
16
2021-12
14
2022-01
7
2022-05
1
2022-08
3
2022-09
2
2022-10
2
2022-12
5
2023-01
3
2023-02
1
2023-03
4
2023-04
2
2023-06
3
2023-07
4
2023-08
1
2023-10
1
2024-02
1
2024-03
1
2024-04
1
2024-08
1
标签
算法基础
linux
前端
c++
数据结构
框架
数据库
计算机基础
储备知识
java基础
ASM
其他
深入理解java虚拟机
nginx
git
消息中间件
搜索
maven
redis
docker
dubbo
vue
导入导出
软件使用
idea插件
协议
无聊的知识
jenkins
springboot
mqtt协议
keepalived
minio
mysql
ensp
网络基础
xxl-job
rabbitmq
haproxy
srs
音视频
webrtc
javascript
加密算法
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。