前言
写项目的时候总是会用到图形验证码和邮箱发送验证码,现在把那些通用的部分写在这方便后面直接使用,不然老是回去翻以前的项目代码
email_code表(mysql数据库)
create table email_code
(
email varchar(150) not null comment '邮箱',
code varchar(5) not null comment '编号',
create_time datetime null comment '创建时间',
status tinyint(1) null comment '0:未使用 1:已使用',
primary key (email, code)
)
comment '邮箱验证码';
Constants常量类
public class Constants {
public static final Integer LENGTH_5 = 5;
public static final Integer ONE = 1;
public static final Integer ZERO = 0;
public static final String CHECK_CODE_KEY = "check_code_key";
public static final String CHECK_CODE_KEY_EMAIL = "check_code_key_email";
}
StringTools工具类
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
public class StringTools {
/**
* 生成随机数(只有数字)
*/
public static String getRandomNumber(Integer count) {
return RandomStringUtils.random(count, false, true);
}
/**
* 生成随机数(字符和数字)
*/
public static String getRandomString(Integer count) {
return RandomStringUtils.random(count, true, true);
}
/**
* 判断字符串是否为空
* @param str 需要校验的字符串
* @return 是否为空
*/
public static boolean isEmpty(String str) {
if(null == str || str.isEmpty() || "null".equals(str)||"\u0000".equals(str)){
return true;
}else if(str.trim().isEmpty()){
return true;
}
return false;
}
/**
* 将字符串进行md5加密
*/
public static String encodeMD5(String sourceStr){
return isEmpty(sourceStr)?null: DigestUtils.md5Hex(sourceStr);
}
}
CreateImageCode工具类
来生成图形验证码的
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
public class CreateImageCode {
// 图片的宽度。
private int width = 160;
// 图片的高度。
private int height = 40;
// 验证码字符个数
private int codeCount = 4;
// 验证码干扰线数
private int lineCount = 20;
// 验证码
private String code = null;
// 验证码图片Buffer
private BufferedImage buffImg = null;
Random random = new Random();
public CreateImageCode() {
creatImage();
}
public CreateImageCode(int width, int height) {
this.width = width;
this.height = height;
creatImage();
}
public CreateImageCode(int width, int height, int codeCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
creatImage();
}
public CreateImageCode(int width, int height, int codeCount, int lineCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
this.lineCount = lineCount;
creatImage();
}
// 生成图片
private void creatImage() {
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();
//Graphics2D g = buffImg.createGraphics();
// 设置背景色
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
// 设置字体
//Font font1 = getFont(fontHeight);
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(a,x,y);
// a为要画出来的东西,x和y表示要画的东西最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处
g.drawString(strRand, i * fontWidth + 3, codeY);
}
}
// 得到随机字符
private String randomStr(int n) {
String str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
String str2 = "";
int len = str1.length() - 1;
double r;
for (int i = 0; i < n; i++) {
r = (Math.random()) * len;
str2 = str2 + str1.charAt((int) r);
}
return str2;
}
// 得到随机颜色
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 font[] = new Font[5];
font[0] = new Font("Ravie", Font.PLAIN, size);
font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
font[2] = new Font("Fixedsys", Font.PLAIN, size);
font[3] = new Font("Wide Latin", Font.PLAIN, size);
font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
return font[random.nextInt(5)];
}
// 扭曲方法
private void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
public void write(OutputStream sos) throws IOException {
ImageIO.write(buffImg, "png", sos);
sos.close();
}
public BufferedImage getBuffImg() {
return buffImg;
}
public String getCode() {
return code.toLowerCase();
}
}
SysSettingDto发送邮箱的信息类
可以自行更改
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.io.Serializable;
@JsonIgnoreProperties(ignoreUnknown = true)
public class SysSettingDto implements Serializable {
/**
* 注册发送邮件标题
*/
private String registerMailTitle = "邮箱验证码";
/**
* 注册发送邮件内容
*/
private String registerEmailContent = "你好,您的邮箱验证码时,%s,15分钟有效";
public String getRegisterMailTitle() {
return registerMailTitle;
}
public void setRegisterMailTitle(String registerMailTitle) {
this.registerMailTitle = registerMailTitle;
}
public String getRegisterEmailContent() {
return registerEmailContent;
}
public void setRegisterEmailContent(String registerEmailContent) {
this.registerEmailContent = registerEmailContent;
}
}
图形验证码
/**
* 生成图形验证码
*/
@RequestMapping(value = "/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());
}
发送邮箱验证码
在发送邮件是需要发件人的所以我使用AppConfig来读取配置信息,这个可以是个人或者企业的邮箱账号,但是记得要先开通了授权码才能使用
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppConfig {
@Value("${spring.mail.username:}")
private String sendUserName;
public String getSendUserName() {
return sendUserName;
}
}
service接口
/**
* 发送验证码
* @param email 邮箱
* @param type 类型
*/
void sendEmailCode(String email, Integer type);
impl实现类
在发送邮件的时候应该会调用JavaMailSender来发送,感兴趣的朋友可以去看看其他的博客
@Resource
private JavaMailSender javaMailSender;
/**
* 发送邮箱验证码,并将之前的验证码过期
*
* @param email 邮箱
* @param type 类型
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void sendEmailCode(String email, Integer type) {
if (Objects.equals(type, Constants.ZERO)) {
UserInfo userInfo = userInfoMapper.selectByEmail(email);
if (userInfo != null) {
throw new BusinessException("邮箱已存在");
}
}
//生成只含数字的邮箱验证码
String code = StringTools.getRandomNumber(Constants.LENGTH_5);
//发送验证码
sendEmailCode(email, code);
//将之前的验证码设置为已使用
emailCodeMapper.disableEmailCode(email);
EmailCode emailCode = new EmailCode();
emailCode.setCode(code);
emailCode.setEmail(email);
emailCode.setStatus(Constants.ZERO);
emailCode.setCreateTime(new Date());
emailCodeMapper.insert(emailCode);
}
/**
* 发送验证码
*
* @param toEmail 发送到那一个邮箱
* @param code 发送的验证码
*/
private void sendEmailCode(String toEmail, String code) {
try {
//构造一份邮件
MimeMessage message = javaMailSender.createMimeMessage();
//辅助构建邮件
MimeMessageHelper helper = new MimeMessageHelper(message, true);
//邮件的发件人
helper.setFrom(appConfig.getSendUserName());
//邮件的收件人
helper.setTo(toEmail);
SysSettingDto sysSettingDto = new SysSettingDto();
//邮件主题
helper.setSubject(sysSettingDto.getRegisterMailTitle());
//邮件内容
helper.setText(String.format(sysSettingDto.getRegisterEmailContent(), code));
//邮件发送时间
helper.setSentDate(new Date());
//发送邮件
javaMailSender.send(message);
} catch (Exception e) {
log.error("发送邮箱验证码失败");
throw new BusinessException("邮件发送失败");
}
}
insert方法比较简单就不写了,关于SysSettingDto的可以替换为字符串的
mapper的disableEmailCode方法
/**
* 将之前的验证码设置为已使用
* @param email 邮箱
*/
@Update("update email_code set status = 1 where status = 0 and email = #{email}")
void disableEmailCode(String email);
大概就是这些,可能还会再修改
不过需要根据实际情况修改,主要就是createImageCode类,其他的都可以自己理解然后自己写