验证码是网页中很常见的一个功能,基本所有实现都需验证码验证;
接下来就是如何实现基本的验证码的生成:
1.首先定义一个用来生成验证码的JAVA基本类:
package cn.java.code;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Random;
/*
制作验证码工具类,进行验证码验证;
*/
public class CaptcahCode {
/**
* 验证码数据流生成
* 后面进行生成一个图片;只需要获取名称前端调用即可
* @param response
* @return
*/
public static String dramCodeImg(HttpServletResponse response){
//进行随机数的生成,就是对随机生成的数进行一个拼接;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 4; i++) {
sb.append(randomCode());
}
String code = sb.toString();
//进行一个图片的编写;
//1.定义图片的高度和宽度:
int width = 300;
int height = 150;
//2.设置bufferImg对象,制作图片的宽度,长度以及色彩,这个是新内容需要加强学习
BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);//需要传入图片的宽度,高度,类型等内容
//3.获取Graphics2D绘制对象,绘制验证码
Graphics2D gra = bi.createGraphics();//拿到内存对象
//4.设置文字的颜色和大小
Font font = new Font("微软雅黑",Font.PLAIN,30);
//5.设置字体的颜色
Color color = new Color(0,0,0);
//设置字体,设置颜色
gra.setFont(font);
gra.setColor(color);
//设置背景颜色
gra.setBackground(new Color(226,226,240));
//开始绘制对象
gra.clearRect(0,0,width,height);
//6.绘制形状,一般是矩形,这边也进行一个矩形绘制,拿到一个矩形对象
//首先需要获取内容对象
FontRenderContext context = gra.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(code,context);//数据内容的传输
//7.计算文件的坐标和间距
double x = (width - bounds.getWidth())/2;
double y = (height - bounds.getHeight())/2;
//y坐标比较特殊需要进行一个获取值
double asscent = bounds.getY();
double baseY = y -asscent;
//进行内容的编辑
gra.drawString(code,(int)x,(int)baseY);
//8.结束编辑
gra.dispose();
//9.进行图片的保存,也是最一步
try{
ImageIO.write(bi, "jpg", response.getOutputStream());
//10.刷新响应流
response.flushBuffer();
}catch(Exception ex)
{
ex.printStackTrace();
}
return code;//进行验证码和验证码存储地方一个返回;
}
/**
* 生成一个随机数,从a-z,1-9
* @return
*/
private static char randomCode(){
//1.定义验证的需要的字母和数字
String string = "QWERTYUIOPASDFGHJKLZXCVBNM123456789";
//2.进行一个随机的抽取,需要使用random
Random random = new Random();
return string.charAt(random.nextInt(string.length()));
}
public static void main(String[] args) {
System.out.println(dramCodeImg(null));//I8D15是可以随机生成;
}
}
其中用了几个以前不常用的工具:
BufferedImage//需要传入图片的宽度,高度,类型等内容
Graphics2D//获取Graphics2D绘制对象,绘制验证码
Font //设置文字的颜色和大小
Color //设置字体的颜色
FontRenderContext//首先需要获取内容对象
Rectangle2D //数据内容的传输
ImageIO.write(bi, "jpg", respo//进行图片的保存,也是最一步
然后就可以进行前端的调用
进验证码生成页面定义:
<%@ page import="cn.java.code.CaptcahCode" %><%
//验证码使用的时候要记住清楚浏览器的缓存,不然会导致验证码不刷新;
response.setHeader("pragma","no-cache");
response.setHeader("cache-control","no-cache");
response.setHeader("expires","0");
//调用验证码生成工具
String code = CaptcahCode.dramCodeImg(response);
//最后将验证码生成路径存储在session中
session.setAttribute("code",code);
//3.关于解决getOutPutStream问题
out.clear();
out = pageContext.pushBody();
%>
之后进行数据的调用:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>验证码生成测试</title>
</head>
<body>
<img src="code.jsp" alt="" id="code"/>
<a href="javascript:void(0);" onclick="changerCode()">看不清楚?换一张验证码</a>
<script type="application/javascript">
function changerCode() {
//对图片进行重新发送请求,需要进行不同数据的发送
document.getElementById("code").src = "code.jsp?d="+new Date().getTime();
}
</script>
</body>
</html>
关于算数验证码的随机生成:
接上面的代码,具体实现随机验证码Java:
/**
* 算术表达式验证码生成;可以生成随机数,随机颜色等内容
*
* 干扰线的绘制,绘制验证码中的线条
* @param response
* @return
*/
public static String drawImgVerificate(HttpServletResponse response)
{
int width = 300;
int height = 150;
//在内存中创建图片
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//创建图片上下文
Graphics2D gp = bufferedImage.createGraphics();
//生成随机对象,用于生成随机的算术表达式
Random random = new Random();
//设置背景颜色
gp.setColor(setRandomColor(120,110));
Font font = new Font("微软雅黑",Font.PLAIN,30);
//设置字体
gp.setFont(font);
//开始绘制
gp.fillRect(0,0,width,height);
//干扰线的编写,绘制在图片中
gp.setColor(setRandomColor(180,110));
//随机生成100条随机线
for (int i = 0; i < 100; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int x1 = random.nextInt(60);
int y1 = random.nextInt(60);
gp.drawLine(x,y,x1,y1);//对线条的绘制,利用两点生成一条直线
}
//进行算术验证码的生成
int num1= (int)(Math.random()*100 + 1);
int num2 = (int)(Math.random()*100 + 1);
String fuhaoStr = "";
int result = 0;//用来记录运行值
//对随机符号的生成
int fuhao = random.nextInt(3); //一般只生成3个,加减乘
switch (fuhao)
{
case 0:fuhaoStr = "+";result = num1 + num2;break;
case 1:fuhaoStr = "-";result = num1 - num2;break;
case 2:fuhaoStr = "*";result = num1 * num2;break;
default:break;
}
//拼接表达式,用户用图片显示
String code = num1 + " " + fuhaoStr + " " + num2 + " = ?";
//设置随机颜色
gp.setColor(new Color(20+random.nextInt(110),20+random.nextInt(200),30+random.nextInt(150)));
//计算图像内容
FontRenderContext context = gp.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(code,context);//数据内容的传输
//7.计算文件的坐标和间距
double x = (width - bounds.getWidth())/2;
double y = (height - bounds.getHeight())/2;
//y坐标比较特殊需要进行一个获取值
double asscent = bounds.getY();
double baseY = y -asscent;
//绘制表达式
gp.drawString(code,(int)x,(int)baseY);
//结束绘制
gp.dispose();
try {
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
return String.valueOf(result);//返回一个表达值;
}catch (Exception ex){
ex.printStackTrace();
return null;
}
}
/**
* 随机生成颜色;特定范围内随机
* @param fc
* @param bc
* @return
*/
private static Color setRandomColor(int fc,int bc){
//利用随机数进行生成随机颜色,颜色rgb是0-255随机数
Random random = new Random();
if(fc > 255) fc = 255;
if(bc > 255) bc = 255;
int g = fc+random.nextInt(fc-bc);
int r = fc+random.nextInt(fc-bc);
int b = fc+random.nextInt(fc-bc);
return new Color(r,g,b);
}
添加了线条干扰和颜色随机的功能,这样子就可以很轻松的实现了;
//计算图像内容
FontRenderContext context = gp.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(code,context);//数据内容的传输
//7.计算文件的坐标和间距
double x = (width - bounds.getWidth())/2;
double y = (height - bounds.getHeight())/2;
//y坐标比较特殊需要进行一个获取值
double asscent = bounds.getY();
double baseY = y -asscent;
//绘制表达式
gp.drawString(code,(int)x,(int)baseY);
在实现验证码居中过程中需要这个来辅助使用,前端调用和上面的步骤一样;
实现效果:点击字体可以实现更换操作
详细看博客
这边对基本配置以及使用idea的一个讲解:
1.配web.xml内容,进行包的引用,配置内容也在这里面
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Kaptcha</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<!-- 宽度-->
<init-param>
<param-name>kaptcha.image.width</param-name>
<param-value>200</param-value>
</init-param>
<!-- 验证码图高度-->
<init-param>
<param-name>kaptcha.image.height</param-name>
<param-value>50</param-value>
</init-param>
<!-- 验证码长度-->
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>5</param-value>
</init-param>
<!-- 干扰实列类-->
<init-param>
<param-name>kaptcha.noise.impl</param-name>
<param-value>com.google.code.kaptcha.impl.DefaultNoise</param-value>
</init-param>
<!-- 验证码边框-->
<init-param>
<param-name>kaptcha.border</param-name>
<param-value>yes</param-value>
</init-param>
<!-- 字体间的间隔-->
<init-param>
<param-name>kaptcha.textproducer.char.space</param-name>
<param-value>4</param-value>
</init-param>
<!-- 图片背景样式-->
<init-param>
<param-name>kaptcha.obscurificator.impl</param-name>
<param-value>com.google.code.kaptcha.impl.WaterRipple</param-value>
</init-param>
<!-- 背景实例化类-->
<init-param>
<param-name>kaptcha.background.impl</param-name>
<param-value>com.google.code.kaptcha.impl.DefaultBackground</param-value>
</init-param>
<!-- 详细需要去看谷歌实现:
http://code.google.com/p/kaptcha/wiki/ConfigParameters
-->
</servlet>
<servlet-mapping>
<servlet-name>Kaptcha</servlet-name>
<url-pattern>/Kaptcha.jpg</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>cn.java.Servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
讲解使用过程中遇见的问题,以及解决:
jar包放置正确但是没有找到,问题解决:
需要进行一个仓库的添加,不然不可以使用,idea没有自动导包路径操作;
2.引用后也可能出现不可以使用,需要进行下面的配置
之后就可以使用了;
后端编写验证条件,后端编写的servlet处理需要配置web.xml路径才可以调用
package cn.java.Servlet;
import com.google.code.kaptcha.Constants;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
//获取浏览器输出流对象,可以直接给浏览器返回一个值
PrintWriter out = response.getWriter();
String code = request.getParameter("code");//获取输入框的值
String seessionCode = (String)request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
if(code != null && seessionCode != null)
{
//如果验证码比对正确返回一个成功值
if(code.equalsIgnoreCase(seessionCode))
{
//忽略大小写验证
out.print("success");
}else{
out.print("fail");
}
}else {
out.print("fail");
}
System.out.println("sessionCode="+seessionCode);
//使用过后需要进行关闭
out.flush();
out.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
前端的调用,以及基本验证:
<%--
Created by IntelliJ IDEA.
User: XXXIERW
Date: 2020/7/9
Time: 15:23
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>kaptcha验证码生成框架使用</title>
<script src="/js/jquerymin.min.js"></script>
</head>
<body>
<form action="submit.action">
<input type="text" name="kaptcha" value="" id="code"/>
<img src="/Kaptcha.jpg" alt="图片加载失败" height="50px" width="100px" id="changeImg"/>
<br/>
<br/>
<input type="button" value="登录" id="login"/>
<br/>
<h5 id="result"></h5>
</form>
<%--利用jquery进行一个简单的后端交互--%>
<script>
$(function () {
$("#changeImg").on("click",function () {
$(this).attr("src","/Kaptcha.jpg?d="+ new Date().getTime())//使用时间戳来改变状态
});
//进行登录验证
$("#login").on("click",function () {
var code = $("#code").val();
//然后进行异步发送请求
var params = {"code":code};
$.post("/login",params,function (data) {
//接收一个返回值
if(data == "success") {
$("#result").html("验证码输入正确");
}else{
$("#result").html( "验证码输入错误,请重新输入");
//获取焦点并且重新刷新验证码
$("#code").val("").focus();
//延时自动刷新
//setTimeout(function (){window.location.reload(),1500});
}
})
})
})
</script>
</body>
</html>
最后就可以实现如下效果:
使用框架会大大降低开发的复杂程度,也建议使用框架,但是导包出现的bug也是很多的,这边是我遇见的问题已经都写在上面了,所以更多东西还是需要不断发展;
Kaptcha是一个基于SimpleCaptcha的验证码开源项目。
官网地址:http://code.google.com/p/kaptcha/
kaptcha的使用比较方便,只需添加jar包依赖之后简单地配置就可以使用了。kaptcha所有配置都可以通过web.xml来完成,如果你的项目中使用了Spring MVC,那么则有另外的一种方式来实现。
一、简单的jsp-servlet项目
1.添加jar包依赖
如果你使用maven来统一管理jar包,则在工程的pom.xml中添加dependency
Xml代码 收藏代码
com.google.code.kaptcha
kaptcha
2.3.2
如果是非maven管理的项目,则直接在官网下载kaptcha的jar包,然后添加到项目lib库中,下载地址:http://code.google.com/p/kaptcha/downloads/list
2.配置web.xml
上面说了,kaptcha都是在web.xml中配置,我们必须在web.xml中配置kaptcha的servlet,具体如下:
Xml代码 收藏代码
Kaptcha
com.google.code.kaptcha.servlet.KaptchaServlet
Kaptcha
/kaptcha.jpg
其中servlet的url-pattern可以自定义。
kaptcha所有的参数都有默认的配置,如果我们不显示配置的话,会采取默认的配置。
如果要显示配置kaptcha,在配置kaptcha对应的Servlet时,在init-param增加响应的参数配置即可。示例如下:
Xml代码 收藏代码
Kaptcha
com.google.code.kaptcha.servlet.KaptchaServlet
kaptcha.image.width
200
Width in pixels of the kaptcha image.
kaptcha.image.height
50
Height in pixels of the kaptcha image.
kaptcha.textproducer.char.length
4
The number of characters to display.
kaptcha.noise.impl
com.google.code.kaptcha.impl.NoNoise
The noise producer.
具体的配置参数参见:http://code.google.com/p/kaptcha/wiki/ConfigParameters
Constant 描述 默认值
kaptcha.border 图片边框,合法值:yes , no yes
kaptcha.border.color 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. black
kaptcha.border.thickness 边框厚度,合法值:>0 1
kaptcha.image.width 图片宽 200
kaptcha.image.height 图片高 50
kaptcha.producer.impl 图片实现类 com.google.code.kaptcha.impl.DefaultKaptcha
kaptcha.textproducer.impl 文本实现类 com.google.code.kaptcha.text.impl.DefaultTextCreator
kaptcha.textproducer.char.string 文本集合,验证码值从此集合中获取 abcde2345678gfynmnpwx
kaptcha.textproducer.char.length 验证码长度 5
kaptcha.textproducer.font.names 字体 Arial, Courier
kaptcha.textproducer.font.size 字体大小 40px
kaptcha.textproducer.font.color 字体颜色,合法值: r,g,b 或者 white,black,blue. black
kaptcha.textproducer.char.space 文字间隔 2
kaptcha.noise.impl 干扰实现类 com.google.code.kaptcha.impl.DefaultNoise
kaptcha.noise.color 干扰颜色,合法值: r,g,b 或者 white,black,blue. black
kaptcha.obscurificator.impl 图片样式:
水纹com.google.code.kaptcha.impl.WaterRipple
鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
阴影com.google.code.kaptcha.impl.ShadowGimpy
com.google.code.kaptcha.impl.WaterRipple
kaptcha.background.impl 背景实现类 com.google.code.kaptcha.impl.DefaultBackground
kaptcha.background.clear.from 背景颜色渐变,开始颜色 light grey
kaptcha.background.clear.to 背景颜色渐变,结束颜色 white
kaptcha.word.impl 文字渲染器
com.google.code.kaptcha.text.impl.DefaultWordRenderer
kaptcha.session.key session key KAPTCHA_SESSION_KEY
kaptcha.session.date session date KAPTCHA_SESSION_DATE
3.页面调用
Html代码 收藏代码
4.在submit的action方法中进行验证码校验
Java代码 收藏代码
//从session中取出servlet生成的验证码text值
String kaptchaExpected = (String)request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
//获取用户页面输入的验证码
String kaptchaReceived = request.getParameter("kaptcha");
//校验验证码是否正确
if (kaptchaReceived == null || !kaptchaReceived.equalsIgnoreCase(kaptchaExpected)){
setError("kaptcha", "Invalid validation code.");
}
注:确保JDK设置了 -Djava.awt.headless=true
5.实现页面验证码刷新
Html代码 收藏代码
看不清,点击换一张