Java验证码案例如何编写开发

wen java案例 23

本文目录导读:

Java验证码案例如何编写开发

  1. 图片验证码案例
  2. 短信验证码案例
  3. 配置与启动
  4. 使用示例

我来详细讲解Java验证码的完整开发案例,包括图片验证码和短信验证码两种常见类型。

图片验证码案例

添加依赖(Maven项目)

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Redis(用于存储验证码) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

验证码生成工具类

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Random;
public class CaptchaUtil {
    private static final int WIDTH = 120;
    private static final int HEIGHT = 40;
    private static final int CODE_LENGTH = 4;
    private static final String CHARACTERS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
    /**
     * 生成验证码
     * @return 包含验证码文本和Base64图片的Map
     */
    public static CaptchaResult generateCaptcha() {
        Random random = new Random();
        // 生成随机验证码
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < CODE_LENGTH; i++) {
            code.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
        }
        // 创建图片
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        // 设置背景色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        // 设置边框
        g.setColor(Color.LIGHT_GRAY);
        g.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
        // 添加干扰线
        g.setColor(Color.GRAY);
        for (int i = 0; i < 10; i++) {
            int x1 = random.nextInt(WIDTH);
            int y1 = random.nextInt(HEIGHT);
            int x2 = random.nextInt(WIDTH);
            int y2 = random.nextInt(HEIGHT);
            g.drawLine(x1, y1, x2, y2);
        }
        // 绘制验证码
        g.setFont(new Font("Arial", Font.BOLD, 24));
        for (int i = 0; i < CODE_LENGTH; i++) {
            // 随机颜色
            g.setColor(new Color(random.nextInt(200), random.nextInt(200), random.nextInt(200)));
            // 随机旋转角度
            double angle = random.nextDouble() * 0.3 - 0.15;
            g.rotate(angle, 15 + i * 25, 25);
            g.drawString(String.valueOf(code.charAt(i)), 15 + i * 25, 28);
            g.rotate(-angle, 15 + i * 25, 25);
        }
        g.dispose();
        // 转换为Base64
        String base64Image = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            byte[] imageBytes = baos.toByteArray();
            base64Image = Base64.getEncoder().encodeToString(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new CaptchaResult(code.toString(), base64Image);
    }
    // 验证码结果类
    public static class CaptchaResult {
        private String code;
        private String base64Image;
        public CaptchaResult(String code, String base64Image) {
            this.code = code;
            this.base64Image = base64Image;
        }
        public String getCode() {
            return code;
        }
        public String getBase64Image() {
            return base64Image;
        }
    }
}

验证码控制器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/api/captcha")
public class CaptchaController {
    @Autowired
    private StringRedisTemplate redisTemplate;
    /**
     * 获取验证码
     */
    @GetMapping("/generate")
    public Result generateCaptcha() {
        // 生成验证码
        CaptchaUtil.CaptchaResult captchaResult = CaptchaUtil.generateCaptcha();
        // 生成唯一标识
        String captchaId = UUID.randomUUID().toString().replace("-", "");
        // 存储到Redis,5分钟有效
        redisTemplate.opsForValue().set(
            "captcha:" + captchaId, 
            captchaResult.getCode(), 
            5, 
            TimeUnit.MINUTES
        );
        // 返回结果
        Map<String, String> data = new HashMap<>();
        data.put("captchaId", captchaId);
        data.put("captchaImage", "data:image/png;base64," + captchaResult.getBase64Image());
        return Result.success(data);
    }
    /**
     * 验证验证码
     */
    @PostMapping("/verify")
    public Result verifyCaptcha(@RequestBody VerifyRequest request) {
        String redisKey = "captcha:" + request.getCaptchaId();
        String storedCode = redisTemplate.opsForValue().get(redisKey);
        if (storedCode == null) {
            return Result.error("验证码已过期");
        }
        if (!storedCode.equalsIgnoreCase(request.getCaptchaCode())) {
            return Result.error("验证码错误");
        }
        // 验证成功后删除验证码(一次性使用)
        redisTemplate.delete(redisKey);
        return Result.success("验证成功");
    }
    // 验证请求体
    static class VerifyRequest {
        private String captchaId;
        private String captchaCode;
        // getter和setter方法
        public String getCaptchaId() { return captchaId; }
        public void setCaptchaId(String captchaId) { this.captchaId = captchaId; }
        public String getCaptchaCode() { return captchaCode; }
        public void setCaptchaCode(String captchaCode) { this.captchaCode = captchaCode; }
    }
}

统一响应类

public class Result {
    private int code;
    private String message;
    private Object data;
    public static Result success(Object data) {
        Result result = new Result();
        result.code = 200;
        result.message = "success";
        result.data = data;
        return result;
    }
    public static Result error(String message) {
        Result result = new Result();
        result.code = 400;
        result.message = message;
        return result;
    }
    // getter和setter方法
    public int getCode() { return code; }
    public void setCode(int code) { this.code = code; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public Object getData() { return data; }
    public void setData(Object data) { this.data = data; }
}

前端HTML示例

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">验证码示例</title>
</head>
<body>
    <div style="margin: 20px;">
        <h2>图形验证码示例</h2>
        <div>
            <input type="text" id="captchaCode" placeholder="请输入验证码">
            <img id="captchaImg" src="" onclick="refreshCaptcha()" style="cursor: pointer;">
            <button onclick="verifyCaptcha()">验证</button>
        </div>
        <div id="result" style="margin-top: 10px;"></div>
    </div>
    <script>
        // 获取验证码
        function getCaptcha() {
            fetch('/api/captcha/generate')
                .then(response => response.json())
                .then(data => {
                    if (data.code === 200) {
                        document.getElementById('captchaImg').src = data.data.captchaImage;
                        document.getElementById('captchaImg').dataset.captchaId = data.data.captchaId;
                    }
                });
        }
        // 刷新验证码
        function refreshCaptcha() {
            getCaptcha();
        }
        // 验证验证码
        function verifyCaptcha() {
            const captchaId = document.getElementById('captchaImg').dataset.captchaId;
            const captchaCode = document.getElementById('captchaCode').value;
            fetch('/api/captcha/verify', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    captchaId: captchaId,
                    captchaCode: captchaCode
                })
            })
            .then(response => response.json())
            .then(data => {
                document.getElementById('result').innerHTML = 
                    data.code === 200 ? 
                    '<span style="color: green;">✓ 验证成功</span>' : 
                    '<span style="color: red;">✗ ' + data.message + '</span>';
            });
        }
        // 页面加载时获取验证码
        window.onload = getCaptcha;
    </script>
</body>
</html>

短信验证码案例

短信验证码服务

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Service
public class SmsCaptchaService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    // 阿里云短信服务(示例中使用模拟实现)
    @Autowired(required = false)
    private SmsService smsService;
    /**
     * 发送短信验证码
     */
    public Result sendSmsCaptcha(String phone) {
        // 检查发送频率(60秒内不能重复发送)
        String rateLimitKey = "sms:rate:" + phone;
        if (redisTemplate.hasKey(rateLimitKey)) {
            return Result.error("发送过于频繁,请60秒后重试");
        }
        // 生成6位随机验证码
        String captcha = String.format("%06d", new Random().nextInt(999999));
        // 存储验证码到Redis(5分钟有效)
        String captchaKey = "sms:captcha:" + phone;
        redisTemplate.opsForValue().set(captchaKey, captcha, 5, TimeUnit.MINUTES);
        // 设置发送频率限制
        redisTemplate.opsForValue().set(rateLimitKey, "1", 60, TimeUnit.SECONDS);
        // 发送短信(模拟)
        boolean sendSuccess = sendSms(phone, captcha);
        if (sendSuccess) {
            System.out.println("短信验证码发送成功:" + phone + " - " + captcha);
            return Result.success("验证码已发送");
        } else {
            return Result.error("短信发送失败");
        }
    }
    /**
     * 验证短信验证码
     */
    public Result verifySmsCaptcha(String phone, String captcha) {
        String captchaKey = "sms:captcha:" + phone;
        String storedCaptcha = redisTemplate.opsForValue().get(captchaKey);
        if (storedCaptcha == null) {
            return Result.error("验证码已过期");
        }
        if (!storedCaptcha.equals(captcha)) {
            return Result.error("验证码错误");
        }
        // 验证成功后删除验证码
        redisTemplate.delete(captchaKey);
        return Result.success("验证成功");
    }
    /**
     * 模拟发送短信
     */
    private boolean sendSms(String phone, String captcha) {
        // 实际项目中调用短信服务商API
        // 阿里云短信、腾讯云短信等
        try {
            // 模拟发送延迟
            Thread.sleep(100);
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }
}

短信验证码控制器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/sms")
public class SmsCaptchaController {
    @Autowired
    private SmsCaptchaService smsCaptchaService;
    /**
     * 发送短信验证码
     */
    @PostMapping("/send")
    public Result sendSmsCaptcha(@RequestBody SendSmsRequest request) {
        // 验证手机号格式
        if (!isValidPhone(request.getPhone())) {
            return Result.error("手机号格式不正确");
        }
        return smsCaptchaService.sendSmsCaptcha(request.getPhone());
    }
    /**
     * 验证短信验证码
     */
    @PostMapping("/verify")
    public Result verifySmsCaptcha(@RequestBody VerifySmsRequest request) {
        if (!isValidPhone(request.getPhone())) {
            return Result.error("手机号格式不正确");
        }
        if (request.getCaptcha() == null || request.getCaptcha().length() != 6) {
            return Result.error("验证码格式不正确");
        }
        return smsCaptchaService.verifySmsCaptcha(request.getPhone(), request.getCaptcha());
    }
    /**
     * 简单手机号验证
     */
    private boolean isValidPhone(String phone) {
        return phone != null && phone.matches("^1[3-9]\\d{9}$");
    }
    // 请求体类
    static class SendSmsRequest {
        private String phone;
        public String getPhone() { return phone; }
        public void setPhone(String phone) { this.phone = phone; }
    }
    static class VerifySmsRequest {
        private String phone;
        private String captcha;
        public String getPhone() { return phone; }
        public void setPhone(String phone) { this.phone = phone; }
        public String getCaptcha() { return captcha; }
        public void setCaptcha(String captcha) { this.captcha = captcha; }
    }
}

配置与启动

application.yml 配置

spring:
  redis:
    host: localhost
    port: 6379
    timeout: 5000
  # 如果使用阿里云短信服务,配置如下
  aliyun:
    sms:
      access-key-id: your-access-key-id
      access-key-secret: your-access-key-secret
      sign-name: 您的签名
      template-code: SMS_123456789

主启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CaptchaApplication {
    public static void main(String[] args) {
        SpringApplication.run(CaptchaApplication.class, args);
    }
}

使用示例

获取图片验证码

GET /api/captcha/generate

验证图片验证码

POST /api/captcha/verify
Body: {
    "captchaId": "生成的captchaId",
    "captchaCode": "用户输入的验证码"
}

发送短信验证码

POST /api/sms/send
Body: {
    "phone": "13800138000"
}

验证短信验证码

POST /api/sms/verify
Body: {
    "phone": "13800138000",
    "captcha": "123456"
}

这个案例提供了完整的验证码解决方案,包括:

  • 图形验证码的生成与验证
  • 短信验证码的发送与验证
  • Redis存储验证码(支持过期时间)
  • 防刷机制(发送频率限制)
  • 前端集成示例

你可以根据实际需求进行扩展,比如添加更复杂的图形验证码(中文、计算题等),或者集成实际的短信服务商API。

抱歉,评论功能暂时关闭!