验证码(CAPTCHA)通常是一种图像形式的测试,用于防止恶意程序或机器人自动提交表单等非人工操作。验证码可以有效地减少不必要的垃圾信息和恶意行为。
- 生成四位随机数字作为验证码。
- 用Font、Graphics和Random类创建图片缓冲区对象BufferedImage,并在图片上绘制验证码。
- 将图片显示在前端页面上并记录正确的验证码信息。
- 添加点击事件切换验证码,每点击一次就更换验证码。
- 验证用户输入的验证码是否正确,如果错误则记录错误次数,最多允许三次错误输入。
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
public class CaptchaServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 验证码宽度
private static final int WIDTH = 100;
// 验证码高度
private static final int HEIGHT = 30;
// 验证码字符数
private static final int LENGTH = 4;
// 验证码字体大小
private static final int FONT_SIZE = 24;
// 允许的最多错误次数
private static final int MAX_ERRORS = 3;
private String verifyCodeChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Random random = new Random();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型
response.setContentType("image/jpeg");
// 禁止图像缓存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
StringBuilder captcha = new StringBuilder();
// 绘制背景色
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
// 绘制验证码字符串
for (int i = 0; i < LENGTH; i++) {
int randomIndex = random.nextInt(verifyCodeChars.length());
String randomChar = verifyCodeChars.substring(randomIndex, randomIndex + 1);
captcha.append(randomChar);
Font font = new Font(Font.MONOSPACED, Font.BOLD, FONT_SIZE);
g.setFont(font);
g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
FontRenderContext context = g.getFontRenderContext();
TextLayout textLayout = new TextLayout(randomChar, font, context);
float x = (i * WIDTH / LENGTH) + (WIDTH / LENGTH - textLayout.getAdvance()) / 2;
float y = HEIGHT / 2 + textLayout.getAscent() / 2;
textLayout.draw(g, x, y);
}
// 记录正确验证码信息
request.getSession().setAttribute("captcha", captcha.toString());
// 释放图形资源
g.dispose();
// 将图片输出到响应流中
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpeg", out);
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String inputCaptcha = request.getParameter("captcha");
String captcha = (String) request.getSession().getAttribute("captcha");
// 验证用户输入的验证码是否正确,如果错误则记录错误次数
int errorCount = 0;
if (inputCaptcha != null && !"".equals(inputCaptcha)) {
if (!inputCaptcha.equals(captcha)) {
errorCount++;
request.setAttribute("errorMsg", "验证码错误");
}
}
// 如果错误次数达到上限,则禁止继续验证
if (errorCount >= MAX_ERRORS) {
request.setAttribute("errorMsg", "您已连续错误三次,不能再进行验证!");
request.getRequestDispatcher("/error.jsp").forward(request, response);
} else {
request.getRequestDispatcher("/register.jsp").forward(request, response);
}
}
}
在web.xml中添加servlet映射:
<servlet>
<servlet-name>CaptchaServlet</servlet-name>
<servlet-class>CaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name>
<url-pattern>/captchaServlet</url-pattern>
</servlet-mapping>
在前端页面中添加验证码显示和点击事件:
<img src="captcha.jpg" alt="验证码" onclick="changeCaptcha()">
<script>
function changeCaptcha() {
var img = document.getElementsByTagName("img")[0];
img.src = "captcha.jpg?" + Math.random();
}
</script>
这里使用了getElementsByTagName方法获取页面上第一个img元素,并将其src属性中的随机数改变以达到刷新验证码的效果。同时,在HTML中给标签设置了onclick属性,当用户点击该标签时,会调用changeCaptcha函数来切换验证码。