赞
踩
验证码,作为一种基本的安全措施,帮助在用户验证过程中防止自动化滥用。在这篇博客中,我将分享如何在 Java Web 应用程序中从头开始实现一个简单但有效的验证码功能
效果图如下:
注:本文仅介绍验证码功能的原理和简单实现,大家应根据具体应用场景和需求对代码做出修改和完善
环境与技术栈
CaptchaUtils.java
在 Java Web 应用程序中实现验证码功能的核心在于 CaptchaUtils
工具类。这个类负责生成验证码图片并输出到客户端。以下是这个类的关键功能以及它们如何协同工作:
Random
类来随机选择其中的字符来构建一个指定长度的验证码字符串。BufferedImage
类来创建空白图像,最后利用 Graphics2D
对象在图像上绘制生成的随机字符串。可以设置字体、大小和颜色以增强视觉效果和安全性。ImageIO.write
方法将 BufferedImage
输出到 HttpServletResponse
的输出流中。完整代码如下:
- package zua.util;
- import javax.imageio.ImageIO;
- import javax.servlet.http.HttpServletResponse;
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.IOException;
- import java.util.Random;
-
- public class CaptchaUtils {
-
- //定义验证码图像属性
- private static final int WIDTH = 80;//图像宽度
- private static final int HEIGHT = 40;//图像高度
- private static final int LENGTH = 4;//验证码字符数量
- private static final Random random = new Random();// 用于生成随机数,便于设置rgb参数
-
- /**
- * 创建验证码图像并返回验证码上的文本
- *
- * @param response HttpServletResponse, 用于输出图像到客户端
- * @return 返回生成的验证码文本
- */
-
- public static String createCaptchaImage(HttpServletResponse response) {
- // 创建BufferedImage对象,这是一个包含图像数据的缓冲区
- BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
- // 获取Graphics2D对象,可以在图像上进行绘制
- Graphics2D g = image.createGraphics();
-
- // 设置背景色为白色并填充整个图像区域
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, WIDTH, HEIGHT);
-
- // 设置字体,使用Arial字体,加粗,大小20
- g.setFont(new Font("Arial", Font.BOLD, 20));
-
- // 随机生成验证码文本字符
- String captchaText = generateRandomText(LENGTH);
- int x = 10; // 横坐标开始位置
- // 逐个绘制验证码中的字符
- for (char c : captchaText.toCharArray()) {
- // 随机生成字符颜色(rgb)
- g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
- // 绘制字符,并随机调整字符的垂直位置
- g.drawString(String.valueOf(c), x, 20 + random.nextInt(20));
- x += 20;// 将横坐标移动到下一个字符的绘制位置
- }
-
- // 添加噪点,使图像中的验证码不易被自动识别
- g.setColor(Color.LIGHT_GRAY);
- for (int i = 0; i < 20; i++) {
- int x1 = random.nextInt(WIDTH);
- int y1 = random.nextInt(HEIGHT);
- int x2 = random.nextInt(12);
- int y2 = random.nextInt(12);
- g.drawLine(x1, y1, x1 + x2, y1 + y2);// 绘制一条小线段,代表噪点
- }
-
- // 完成图像的绘制,释放图形上下文使用的系统资源
- g.dispose();
-
- // 设置响应内容类型为JPEG图像
- response.setContentType("image/jpeg");
- try {
- // 将创建的图像写入响应的输出流中
- ImageIO.write(image, "JPEG", response.getOutputStream());
- // 刷新输出流,确保图像数据完整发送
- response.getOutputStream().flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
- // 返回生成的验证码文本
- return captchaText;
- }
-
- /**
- * 生成随机文本,用于验证码
- *
- * @param length 需要生成的文本长度
- * @return 返回生成的随机文本
- */
- private static String generateRandomText(int length) {
- // 定义可能出现在验证码中的字符
- String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- // 随机选择字符并添加到StringBuilder中
- StringBuilder sb = new StringBuilder(length);
- for (int i = 0; i < length; i++) {
- // 将StringBuilder转换为字符串并返回
- sb.append(chars.charAt(random.nextInt(chars.length())));
- }
- return sb.toString();
- }
- }
接下来,我们创建 CaptchaServlet
类来处理生成验证码的请求。在 doGet
方法中,我们调用 CaptchaUtils
来生成图像并将验证码文本保存在 session 中。在 doPost
方法中,我们比较用户输入的验证码和 session 中设定的的验证码。
代码如下:
- package zua.servlet;
-
- import com.google.gson.Gson;
- import zua.util.CaptchaUtils;
-
- 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 javax.servlet.http.HttpSession;
- import java.io.Console;
- import java.io.IOException;
- import java.io.PrintWriter;
-
- @WebServlet("/captcha")
- public class CaptchaServlet extends HttpServlet {
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // 创建验证码图片并返回图片上的文本
- String captchaText = CaptchaUtils.createCaptchaImage(response);
- // 将验证码文本保存到Session中
- HttpSession session = request.getSession();
- session.setAttribute("captcha", captchaText);
- }
-
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // 获取用户输入的验证码
- String userInputCaptcha = request.getParameter("captcha");
-
- // 从Session中获取真正的验证码
- HttpSession session = request.getSession();
- String realCaptcha = (String) session.getAttribute("captcha");
-
-
- // 比较用户输入的验证码和真正的验证码是否一致
- // 设置响应类型为JSON
- response.setContentType("application/json");
- PrintWriter out = response.getWriter();
- Gson gson=new Gson();//gson需要相应jar包,如没有下面选其一种方式即可:
- /*
- * maven:
- * <dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <version>2.10.1</version>
- </dependency>
- *
- * jar下载路径:
- * https://mvnrepository.com/artifact/com.google.code.gson/gson/2.10.1
- * */
- String json;
- if (userInputCaptcha != null && userInputCaptcha.equalsIgnoreCase(realCaptcha)) {
- json=gson.toJson("success");
- } else {
- json=gson.toJson("fail");
- }
- out.write(json);
- }
- }
注意:示例中用的gson格式数据,需要下载jar包或在pow里添加依赖,代码中已给出下载地址和maven依赖,根据需求选用其一即可
在 HTML 页面中,我们使用一个 img
标签来显示验证码图像,并提供一个刷新链接。JavaScript 用于处理验证码的刷新和表单提交。
代码如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Captcha Example</title>
-
- </head>
- <body style="text-align: center">
- <!-- 用户输入验证码的文本框 -->
- <input type="text" name="captcha" id="captcha" style="width: 160px;height: 40px"/>
- <!-- 显示验证码图像 -->
- <a href="#" onclick="refreshCaptcha(); return false;">
- <img src="/web/captcha" id="captchaImage" alt="Captcha" />
- </a>
- <!-- 用户点击后刷新验证码的链接 -->
- <a href="#" onclick="refreshCaptcha(); return false;">换一换</a><br>
- <span id="error" style="color: red"></span><br>
- <input type="button" value="提交" id="btn">
- <script type="text/javascript">
- // 当用户点击“换一换”链接时,调用此函数以刷新验证码图像
- function refreshCaptcha() {
- var captchaImage = document.getElementById('captchaImage');
- // 更新图像的src属性,因为是get请求,所以要在后面添加一个时间戳以防止浏览器缓存图像
- captchaImage.src = '/web/captcha?' + new Date().getTime();
- }
-
- //输入框获得焦点时擦除错误信息
- document.getElementById('captcha').onclick=function (){
- document.getElementById("error").innerHTML="";
- }
-
- //点击提交时检查验证码
- document.getElementById('btn').onclick=function (){
- const captcha = document.getElementById('captcha').value.trim();//获得用户输入值
- if (captcha===""){//用户输入为空时提示错误信息
- document.getElementById("error").innerHTML='请输入验证码';
- }else {//用户输入格式正确则发送ajax请求
- fetch('/web/captcha', {
- method: 'POST', // 使用 POST 方法提交数据
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded' // 指定请求的内容类型
- },
- body: 'captcha='+ captcha //键=值格式
- })
- .then(response => response.json()) // 解析文本响应
- .then(data => {
- console.log(data)
- if (data==="success") {
- alert('验证成功')
- } else {
- refreshCaptcha();
- document.getElementById("error").innerHTML='验证码错误,请重新输入';
- }
- })
- .catch(error => console.error('Error: ', error));
- }
-
-
- }
-
-
- </script>
- </body>
- </html>
CaptchaServlet
的请求路径。这个路径在 CaptchaServlet
类上使用 @WebServlet
注解定义1.在HTML中放置一个<img>标签:
这个<img>标签有一个src属性,指向服务器上的验证码图片资源。例如,<img src="captcha" id="captchaImage" alt="Captcha" />。当浏览器解析到这个标签时,它会向服务器发送一个GET请求以获取src属性指定的资源。
2.服务器生成图像:
当请求到达服务器,并被映射到你的CaptchaServlet时,doGet方法会被调用。在doGet方法中,CaptchaUtils.createCaptchaImage(response);会负责生成一个图像,并将其写入到响应的输出流中。
3.响应与图像数据:
服务器响应请求并将图像数据作为响应体发送回客户端。此时,响应的MIME类型应该被设置为图像的MIME类型(如image/png)。
4.浏览器接收并渲染图像:
浏览器接收到包含图像数据的响应后,就会在<img>标签的位置渲染图像。
5.刷新验证码:
当用户点击“换一换”时,refreshCaptcha函数会被调用。这个函数会通过更改<img>标签的src属性来强制浏览器重新请求验证码。它通过附加当前时间戳来确保请求不会被浏览器缓存,从而获取新的验证码图像。
所以,客户端接收图像的关键在于<img>标签的src属性指向你的CaptchaServlet,它负责生成和发送图像数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。