验证码
This commit is contained in:
parent
2a764f1516
commit
14f4f50e18
BIN
captcha_preview.png
Normal file
BIN
captcha_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 527 B |
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
package com.suisung.mall.common.utils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CaptchaUtil {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
// 生成示例验证码图片
|
||||
String captchaCode = generateSimpleCaptcha(4);
|
||||
System.out.println("生成的验证码: " + captchaCode);
|
||||
|
||||
BufferedImage image = createSimpleCaptchaImage(captchaCode);
|
||||
|
||||
// 保存到文件以便预览
|
||||
File output = new File("captcha_preview.png");
|
||||
ImageIO.write(image, "png", output);
|
||||
System.out.println("验证码图片已保存到: " + output.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成简单的数字和字母验证码
|
||||
*
|
||||
* @param length 验证码长度
|
||||
* @return 验证码字符串
|
||||
*/
|
||||
public static String generateSimpleCaptcha(int length) {
|
||||
String chars = "0123456789";
|
||||
StringBuilder captcha = new StringBuilder();
|
||||
java.util.Random random = new java.util.Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
captcha.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
return captcha.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建简单的验证码图片(不依赖系统字体)
|
||||
*
|
||||
* @param captchaCode 验证码
|
||||
* @return 验证码图片
|
||||
*/
|
||||
public static BufferedImage createSimpleCaptchaImage(String captchaCode) {
|
||||
int width = 120;
|
||||
int height = 40;
|
||||
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
java.awt.Graphics2D g = image.createGraphics();
|
||||
|
||||
// 设置背景色
|
||||
g.setColor(java.awt.Color.WHITE);
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
// 绘制干扰线
|
||||
java.util.Random random = new java.util.Random();
|
||||
g.setColor(new java.awt.Color(200, 200, 200));
|
||||
for (int i = 0; i < 8; 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.setColor(new java.awt.Color(200, 200, 200));
|
||||
for (int i = 0; i < 30; i++) {
|
||||
int x = random.nextInt(width);
|
||||
int y = random.nextInt(height);
|
||||
g.fillRect(x, y, 1, 1);
|
||||
}
|
||||
|
||||
// 绘制验证码字符
|
||||
int charWidth = width / (captchaCode.length() + 1);
|
||||
|
||||
for (int i = 0; i < captchaCode.length(); i++) {
|
||||
char c = captchaCode.charAt(i);
|
||||
int x = (i + 1) * charWidth - 8;
|
||||
int y = height / 2 - 10;
|
||||
|
||||
// 添加随机旋转和位置偏移
|
||||
java.awt.geom.AffineTransform original = g.getTransform();
|
||||
java.awt.geom.AffineTransform transform = new java.awt.geom.AffineTransform();
|
||||
transform.translate(x, y);
|
||||
// 减小旋转角度,避免字符变形过大
|
||||
transform.rotate((random.nextDouble() - 0.5) * 0.3);
|
||||
g.setTransform(transform);
|
||||
|
||||
// 使用点阵方式绘制字符
|
||||
drawCharacter(g, c, 0, 0, random);
|
||||
|
||||
// 恢复原始变换
|
||||
g.setTransform(original);
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用点阵方式绘制字符(避免使用字体)
|
||||
*
|
||||
* @param g Graphics对象
|
||||
* @param c 要绘制的字符
|
||||
* @param x x坐标偏移
|
||||
* @param y y坐标偏移
|
||||
* @param random 随机数生成器
|
||||
*/
|
||||
private static void drawCharacter(java.awt.Graphics2D g, char c, int x, int y, java.util.Random random) {
|
||||
// 使用5x7点阵绘制字符
|
||||
int[][] pattern = getCharacterPattern(c);
|
||||
|
||||
if (pattern != null) {
|
||||
// 设置画笔颜色
|
||||
g.setColor(java.awt.Color.BLACK);
|
||||
|
||||
for (int i = 0; i < pattern.length; i++) {
|
||||
for (int j = 0; j < pattern[i].length; j++) {
|
||||
if (pattern[i][j] == 1) {
|
||||
// 添加轻微随机偏移使字符不那么规整
|
||||
int offsetX = random.nextInt(3) - 1;
|
||||
int offsetY = random.nextInt(3) - 1;
|
||||
// 使用更清晰的绘制方式,增大像素点
|
||||
g.fillRect(x + j * 3, y + i * 3, 2, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果字符图案未定义,绘制一个简单的替代图形
|
||||
g.setColor(java.awt.Color.GRAY);
|
||||
g.fillOval(x + 5, y + 5, 6, 6);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符的点阵图案
|
||||
*
|
||||
* @param c 字符
|
||||
* @return 点阵图案(二维数组)
|
||||
*/
|
||||
private static int[][] getCharacterPattern(char c) {
|
||||
// 简化的5x7点阵字符图案
|
||||
switch (c) {
|
||||
case '0':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case '1':
|
||||
return new int[][]{
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 1, 1, 0, 0},
|
||||
{1, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{1, 1, 1, 1, 1}
|
||||
};
|
||||
case '2':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 0, 1, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 1, 0, 0, 0},
|
||||
{1, 1, 1, 1, 1}
|
||||
};
|
||||
case '3':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 1, 1, 0},
|
||||
{0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case '4':
|
||||
return new int[][]{
|
||||
{0, 0, 0, 1, 0},
|
||||
{0, 0, 1, 1, 0},
|
||||
{0, 1, 0, 1, 0},
|
||||
{1, 0, 0, 1, 0},
|
||||
{1, 1, 1, 1, 1},
|
||||
{0, 0, 0, 1, 0},
|
||||
{0, 0, 0, 1, 0}
|
||||
};
|
||||
case '5':
|
||||
return new int[][]{
|
||||
{1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 0},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 0}
|
||||
};
|
||||
case '6':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case '7':
|
||||
return new int[][]{
|
||||
{1, 1, 1, 1, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 0, 1, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 1, 0, 0, 0},
|
||||
{0, 1, 0, 0, 0},
|
||||
{0, 1, 0, 0, 0}
|
||||
};
|
||||
case '8':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case '9':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case 'A':
|
||||
case 'a':
|
||||
return new int[][]{
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 1, 0, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1}
|
||||
};
|
||||
case 'B':
|
||||
case 'b':
|
||||
return new int[][]{
|
||||
{1, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 0}
|
||||
};
|
||||
case 'C':
|
||||
case 'c':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case 'D':
|
||||
case 'd':
|
||||
return new int[][]{
|
||||
{1, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 0}
|
||||
};
|
||||
case 'E':
|
||||
case 'e':
|
||||
return new int[][]{
|
||||
{1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 1}
|
||||
};
|
||||
case 'F':
|
||||
case 'f':
|
||||
return new int[][]{
|
||||
{1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0}
|
||||
};
|
||||
case 'G':
|
||||
case 'g':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0},
|
||||
{1, 0, 1, 1, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
case 'H':
|
||||
case 'h':
|
||||
return new int[][]{
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 1}
|
||||
};
|
||||
case 'I':
|
||||
case 'i':
|
||||
return new int[][]{
|
||||
{0, 1, 1, 1, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 1, 1, 1, 0}
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.suisung.mall.common.constant.RedisConstant;
|
||||
import com.suisung.mall.common.modules.base.ShopBaseConfig;
|
||||
import com.suisung.mall.common.utils.CaptchaUtil;
|
||||
import com.suisung.mall.core.web.service.RedisService;
|
||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||
import com.suisung.mall.shop.base.mapper.ShopBaseConfigMapper;
|
||||
@ -116,10 +117,10 @@ public class ShopBaseConfigServiceImpl extends BaseServiceImpl<ShopBaseConfigMap
|
||||
}
|
||||
|
||||
// 创建一个不依赖字体的简单数字验证码
|
||||
String captchaCode = generateSimpleCaptcha(4);
|
||||
String captchaCode = CaptchaUtil.generateSimpleCaptcha(4);
|
||||
|
||||
// 手动创建简单的验证码图片
|
||||
BufferedImage image = createSimpleCaptchaImage(captchaCode);
|
||||
BufferedImage image = CaptchaUtil.createSimpleCaptchaImage(captchaCode);
|
||||
|
||||
// 保存验证码到Redis
|
||||
String code = RedisConstant.Verifycode_NameSpace + verify_token + captchaCode;
|
||||
@ -152,133 +153,6 @@ public class ShopBaseConfigServiceImpl extends BaseServiceImpl<ShopBaseConfigMap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成简单的数字验证码
|
||||
*
|
||||
* @param length 验证码长度
|
||||
* @return 验证码字符串
|
||||
*/
|
||||
private String generateSimpleCaptcha(int length) {
|
||||
String chars = "0123456789";
|
||||
StringBuilder captcha = new StringBuilder();
|
||||
java.util.Random random = new java.util.Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
captcha.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
return captcha.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建简单的验证码图片(不依赖系统字体)
|
||||
*
|
||||
* @param captchaCode 验证码
|
||||
* @return 验证码图片
|
||||
*/
|
||||
private BufferedImage createSimpleCaptchaImage(String captchaCode) {
|
||||
int width = 120;
|
||||
int height = 40;
|
||||
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
java.awt.Graphics2D g = image.createGraphics();
|
||||
|
||||
// 设置背景色
|
||||
g.setColor(java.awt.Color.WHITE);
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
// 绘制干扰线
|
||||
java.util.Random random = new java.util.Random();
|
||||
g.setColor(java.awt.Color.LIGHT_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.setColor(java.awt.Color.BLACK);
|
||||
int fontSize = 20;
|
||||
for (int i = 0; i < captchaCode.length(); i++) {
|
||||
char c = captchaCode.charAt(i);
|
||||
// 使用drawString可能会触发字体问题,所以我们用图形代替
|
||||
int x = 20 + i * 20;
|
||||
int y = 25;
|
||||
|
||||
// 绘制数字的简单表示(这里仍然可能有问题,所以我们用点阵方式)
|
||||
drawSimpleNumber(g, c, x, y);
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用简单图形绘制数字(避免使用字体)
|
||||
*
|
||||
* @param g Graphics对象
|
||||
* @param c 要绘制的字符
|
||||
* @param x x坐标
|
||||
* @param y y坐标
|
||||
*/
|
||||
private void drawSimpleNumber(java.awt.Graphics2D g, char c, int x, int y) {
|
||||
// 简单的数字绘制,避免使用字体
|
||||
switch (c) {
|
||||
case '0':
|
||||
g.drawOval(x, y - 15, 15, 15);
|
||||
break;
|
||||
case '1':
|
||||
g.drawLine(x + 7, y - 15, x + 7, y);
|
||||
break;
|
||||
case '2':
|
||||
g.drawLine(x, y - 15, x + 15, y - 15); // 上横线
|
||||
g.drawLine(x + 15, y - 15, x + 15, y - 7); // 右上竖线
|
||||
g.drawLine(x, y - 7, x + 15, y - 7); // 中横线
|
||||
g.drawLine(x, y - 7, x, y); // 左下竖线
|
||||
g.drawLine(x, y, x + 15, y); // 下横线
|
||||
break;
|
||||
case '3':
|
||||
g.drawLine(x, y - 15, x + 15, y - 15); // 上横线
|
||||
g.drawLine(x + 15, y - 15, x + 15, y); // 右竖线
|
||||
g.drawLine(x, y - 7, x + 15, y - 7); // 中横线
|
||||
g.drawLine(x, y, x + 15, y); // 下横线
|
||||
break;
|
||||
case '4':
|
||||
g.drawLine(x, y - 15, x, y - 7); // 左上竖线
|
||||
g.drawLine(x + 15, y - 15, x + 15, y); // 右竖线
|
||||
g.drawLine(x, y - 7, x + 15, y - 7); // 中横线
|
||||
break;
|
||||
case '5':
|
||||
g.drawLine(x, y - 15, x + 15, y - 15); // 上横线
|
||||
g.drawLine(x, y - 15, x, y - 7); // 左上竖线
|
||||
g.drawLine(x, y - 7, x + 15, y - 7); // 中横线
|
||||
g.drawLine(x + 15, y - 7, x + 15, y); // 右下竖线
|
||||
g.drawLine(x, y, x + 15, y); // 下横线
|
||||
break;
|
||||
case '6':
|
||||
g.drawOval(x, y - 15, 15, 15);
|
||||
g.drawLine(x, y - 7, x, y); // 左下竖线
|
||||
g.drawLine(x, y, x + 15, y); // 下横线
|
||||
break;
|
||||
case '7':
|
||||
g.drawLine(x, y - 15, x + 15, y - 15); // 上横线
|
||||
g.drawLine(x + 15, y - 15, x + 15, y); // 右竖线
|
||||
break;
|
||||
case '8':
|
||||
g.drawOval(x, y - 15, 15, 15);
|
||||
g.drawOval(x, y - 7, 15, 15);
|
||||
break;
|
||||
case '9':
|
||||
g.drawOval(x, y - 15, 15, 15);
|
||||
g.drawLine(x + 15, y - 7, x + 15, y); // 右下竖线
|
||||
g.drawLine(x, y, x + 15, y); // 下横线
|
||||
break;
|
||||
default:
|
||||
// 绘制一个简单的点作为默认
|
||||
g.fillOval(x + 7, y - 7, 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * 获取验证码
|
||||
|
||||
Loading…
Reference in New Issue
Block a user