用户在登录注册时需要验证码邮箱验证码,为此需要提供一个验证码生成接口。

接口信息

使用字节流的方式写回前端

路径地址 http://localhost:7090/api/checkCode
请求方式 GET
请求参数 Integer
返回结果

图片验证码DTO

创建包com.swx.easypan.entity.dto,创建 CreateImageCode 实体类,将下面代码放入:

CreateImageCode
public class CreateImageCode {

// 图片高度
private int width = 160;
// 图片宽度
private int height = 40;
// 验证码字符个数
private int codeCount = 4;
// 验证码干扰线数
private int lineCount = 20;
// 验证码
private String code;
// 验证码图片Buffer
private BufferedImage buffImg;
Random random = new Random();

public CreateImageCode() {
createImage();
}

public CreateImageCode(int width, int height) {
this.width = width;
this.height = height;
createImage();
}

public CreateImageCode(int width, int height, int codeCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
createImage();
}

public CreateImageCode(int width, int height, int codeCount, int lineCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
this.lineCount = lineCount;
createImage();
}

private void createImage() {
int fontWidth = width / codeCount; // 字体的宽度
int fontHeight = height - 5; // 字体的高度
int codeY = height - 8;

// 图像buffer
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = buffImg.getGraphics();
// 设置背景色
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
// 设置字体
Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
g.setFont(font);

// 设置干扰线
for (int i = 0; i < lineCount; i++) {
int xs = random.nextInt(width);
int ys = random.nextInt(height);
int xe = xs + random.nextInt(width);
int ye = ys + random.nextInt(height);
g.setColor(getRandColor(1, 255));
g.drawLine(xs, ys, xe, ye);
}

// 添加躁点
float yawpRate = 0.01f; // 噪声率
int area = (int) (yawpRate * width * height);
for (int i = 0; i < area; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
buffImg.setRGB(x, y, random.nextInt(255));
}

// 得到随机字符
String str1 = randomStr(codeCount);
this.code = str1;
for (int i = 0; i < codeCount; i++) {
String strRand = str1.substring(i, i + 1);
g.setColor(getRandColor(1, 255));
g.drawString(strRand, i * fontWidth + 3, codeY);
}
}

// 得到随机字符
private String randomStr(int n) {
String str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
StringBuilder str2 = new StringBuilder();
int len = str1.length() - 1;
double r;
for (int i = 0; i < n; i++) {
r = (Math.random()) * len;
str2.append(str1.charAt((int) r));
}
return str2.toString();
}

// 得到随机颜色
private Color getRandColor(int fc, int bc) {
if (fc > 255) fc = 255;
if (bc > 255) bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}

// 得到随机字体
private Font getFont(int size) {
Random random = new Random();
Font[] fonts = new Font[5];
fonts[0] = new Font("Ravie", Font.PLAIN, size);
fonts[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
fonts[2] = new Font("Fixedsys", Font.PLAIN, size);
fonts[3] = new Font("Wide Latin", Font.PLAIN, size);
fonts[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
return fonts[random.nextInt(5)];
}

public void write(OutputStream sos) throws IOException {
ImageIO.write(buffImg, "png", sos);
sos.close();
}

public String getCode() {
return code.toLowerCase();
}
}

定义常量

com.swx.easypan.entity.constants包下的 Constants 类中定义常量

Constants
public class Constants {
public static final Integer ZERO = 0;
public static final String ZERO_STR = "0";
public static final Integer LENGTH_5 = 5;
public static final Integer LENGTH_10 = 10;
public static final Integer LENGTH_15 = 15;
public static final Integer LENGTH_20 = 20;
public static final Integer LENGTH_50 = 50;
public static final Integer LENGTH_150 = 150;
public static final String CHECK_CODE_KEY = "check_code_key";
public static final String CHECK_CODE_KEY_EMAIL = "check_code_key_email";
}

定义Service

找到 EmailCodeService,定义检查验证码方法:

EmailCodeService
public interface EmailCodeService extends IService<EmailCode> {
void checkCode(String email, String code);
}

在 EmailCodeServiceImpl 中实现该方法:

@Service
public class EmailCodeServiceImpl extends ServiceImpl<EmailCodeMapper, EmailCode> implements EmailCodeService {
@Override
public void checkCode(String email, String code) {
LambdaQueryWrapper<EmailCode> wrapper = new LambdaQueryWrapper<EmailCode>().eq(EmailCode::getEmail, email).eq(EmailCode::getCode, code);
EmailCode one = this.getOne(wrapper);
if (null == one) {
throw new BizException("邮箱验证码错误");
}
ZoneId zoneId = ZoneId.systemDefault();
long expire = System.currentTimeMillis() - one.getCreateTime().atZone(zoneId).toInstant().toEpochMilli();
if (one.getStatus() == 1 || expire > Constants.LENGTH_15 * 60 * 1000) {
throw new BizException("邮箱验证码已失效");
}
baseMapper.disableEmailCode(email);
}
}

定义Controller

在 UserInfoController 下定义接口

@GetMapping("/checkCode")
public void checkCode(HttpServletResponse response, HttpSession session, Integer type) throws IOException {
CreateImageCode vCode = new CreateImageCode(130, 38, 5, 10);
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
String code = vCode.getCode();
if (type == null || type == 0) {
session.setAttribute(Constants.CHECK_CODE_KEY, code);
} else {
session.setAttribute(Constants.CHECK_CODE_KEY_EMAIL, code);
}
vCode.write(response.getOutputStream());
}