基于Java實(shí)現(xiàn)圖形驗(yàn)證碼工具類
工具類:
package com.example.demo.util; import lombok.extern.slf4j.Slf4j; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.security.SecureRandom; /** * 驗(yàn)證碼工具類 * * @author wangbo * @since 2024/10/29 */ @Slf4j public class CaptchaGeneratorUtil { private CaptchaGeneratorUtil() { // ... } public static void main(String[] args) throws IOException { // 生成4位隨機(jī)數(shù)字驗(yàn)證碼 String text = generateRandomCode(); // 創(chuàng)建驗(yàn)證碼圖片 BufferedImage image = createImage(text); // 保存圖片到文件 ImageIO.write(image, "png", new File("captcha.png")); } private static final SecureRandom RANDOM = new SecureRandom(); /** * 生成4位隨機(jī)數(shù)字字母驗(yàn)證碼 */ public static String generateRandomCode() { StringBuilder code = new StringBuilder(); for (int i = 0; i < 4; i++) { int i1 = RANDOM.nextInt(3); if (i1 == 0) { code.append((char) (RANDOM.nextInt(26) + 65)); } else if (i1 == 1) { code.append((char) (RANDOM.nextInt(26) + 97)); } else { code.append(RANDOM.nextInt(10)); } } log.info("生成的驗(yàn)證碼文本 text = {}", code); return code.toString(); } /** * 創(chuàng)建驗(yàn)證碼圖片 */ public static BufferedImage createImage(String text) { log.info("待生成驗(yàn)證碼圖片的文本 text = {}", text); int width = 75; int height = 25; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 使用Graphics2D以獲得更好的圖形控制 Graphics2D g2d = image.createGraphics(); try { // 設(shè)置背景顏色 g2d.setColor(new Color(0xDCDCDC)); g2d.fillRect(0, 0, width, height); // 設(shè)置字體和顏色 g2d.setFont(new Font("Arial", Font.BOLD, 20)); g2d.setColor(new Color(0x004000)); // 確保文本不會(huì)超出圖像邊界 FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(text); // 居中文本 int x = (width - textWidth) / 2; // 居中文本(基線對(duì)齊) int y = (height - fm.getHeight()) / 2 + fm.getAscent(); g2d.drawString(text, x, y); // 添加噪聲線 for (int i = 0; i < 5; i++) { g2d.setColor(new Color(RANDOM.nextInt(255), RANDOM.nextInt(255), RANDOM.nextInt(255))); g2d.drawLine(RANDOM.nextInt(width), RANDOM.nextInt(height), RANDOM.nextInt(width), RANDOM.nextInt(height)); } // 設(shè)置渲染提示以提高圖像質(zhì)量(可選) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } finally { // 確保在try塊之后釋放Graphics2D資源 g2d.dispose(); } return image; } private static final String CAPTCHA_PREFIX = "captcha:"; public static String generateCaptchaRedisKey(String key) { return CAPTCHA_PREFIX + key; } }
生成圖片驗(yàn)證碼接口(該接口無需權(quán)限校驗(yàn)):
/** * 生成圖片驗(yàn)證碼 * * @param key UUID字符串 */ @GetMapping("/captcha/generator/{key}") public void captchaGenerator(@PathVariable("key") String key, HttpServletResponse response) throws BaseException { userService.captchaGenerator(key, response); }
public void captchaGenerator(String key, HttpServletResponse response) throws BaseException { //查看key的驗(yàn)證碼是否已存在 String captchaRedisKey = CaptchaGeneratorUtil.generateCaptchaRedisKey(key); boolean hasKey = Boolean.TRUE.equals(redisTemplate.hasKey(captchaRedisKey)); if (hasKey) { throw new BaseException(ErrorCode.USER_KEY_REPETITION); } String captcha = CaptchaGeneratorUtil.generateRandomCode(); BufferedImage image = CaptchaGeneratorUtil.createImage(captcha); //設(shè)置驗(yàn)證碼,有效期1分鐘 redisTemplate.opsForValue().set(captchaRedisKey, captcha, 60L, TimeUnit.SECONDS); response.setContentType("image/jpeg"); try (ServletOutputStream out = response.getOutputStream()) { ImageIO.write(image, "JPEG", out); } catch (IOException e) { throw new RuntimeException(e); } }
登錄接口或者其他涉及驗(yàn)證碼的接口進(jìn)行驗(yàn)證碼校驗(yàn):
//校驗(yàn)驗(yàn)證碼 String key = loginPage.getKey(); String captcha = loginPage.getCaptcha(); if (StringUtils.isNullOrEmpty(key) || StringUtils.isNullOrEmpty(captcha)) { throw new BaseException(ErrorCode.USER_KEY_OR_CAPTCHA_NOT_FOUND); } String captchaRedisKey = CaptchaGeneratorUtil.generateCaptchaRedisKey(key); String redisCaptcha = redisTemplate.opsForValue().get(captchaRedisKey); if (StringUtils.isNullOrEmpty(redisCaptcha) || !captcha.equalsIgnoreCase(redisCaptcha)) { throw new BaseException(ErrorCode.USER_CAPTCHA_ERROR); } else { //刪除驗(yàn)證碼緩存 redisTemplate.delete(captchaRedisKey); }
到此這篇關(guān)于基于Java實(shí)現(xiàn)圖形驗(yàn)證碼工具類的文章就介紹到這了,更多相關(guān)Java圖形驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot攔截器如何獲取@RequestBody參數(shù)
這篇文章主要介紹了Springboot攔截器如何獲取@RequestBody參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Springboot使用JustAuth實(shí)現(xiàn)各種第三方登陸
本文主要介紹了Springboot使用JustAuth實(shí)現(xiàn)各種第三方登陸,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07使用Java?Executors創(chuàng)建線程池的9種方法
文章主要介紹了?Java?中Executors類創(chuàng)建線程池的?9?種方法,每種方法都詳細(xì)闡述了實(shí)現(xiàn)原理、源代碼分析、參數(shù)解釋、實(shí)現(xiàn)過程、特性和使用場(chǎng)景,感興趣的小伙伴跟著小編一起來看看吧2024-11-11由@NotNull注解引出的關(guān)于Java空指針的控制
這是一些很容易學(xué)會(huì)的簡(jiǎn)單技術(shù),但是對(duì)于代碼質(zhì)量和健壯性來說確實(shí)很重要。以我的經(jīng)驗(yàn),僅是第一個(gè)小技巧就已經(jīng)對(duì)改進(jìn)代碼質(zhì)量具有很大的作用了2016-09-09統(tǒng)一建模語言_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了統(tǒng)一建模語言的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-06-06