该过程仅供参考,若有优化与建议,欢迎提出。
依赖
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
邮箱验证
邮箱工具类
此处用的是线程的方式,Callable更容易设置是否超时
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.Callable;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class SEmail implements Callable<Boolean>{
private static String USERNAME = "";
private static String PASSWORD = "";
private static String HOST = "";
private String email;
private String code;
public SEmail(String email,String code){
this.email = email;
this.code = code;
}
public Boolean call() throws Exception{
Transport transport = null;
Properties prop = new Properties();
prop.setProperty("mail.smtp.host", HOST);
prop.setProperty("mai.transport.protocol", "smtp");
prop.setProperty("mail.smtp.auth","true");
Session session = Session.getDefaultInstance(prop);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(USERNAME));
message.setRecipient(Message.RecipientType.TO,new InternetAddress(email));
message.setSentDate(new Date());
message.setSubject("邮件验证码");
String info = "<!DOCTYPE html>\r\n" +
"<html lang=\"en\"" +
"<head>\r\n" +
" <meta charset=\"UTF-8\"/>\r\n" +
" <title>验证码</title>\r\n" +
"</head>\r\n" +
" <body>\r\n" +
" <h1>欢迎您使用XXX,这是您的验证码,请于X分钟内输入激活码</h1>\r\n" +
" <p>"+ code +"</p>"+
" </body>\r\n" +
"</html>";
message.setContent(info,"text/html;charset=UTF-8");
message.saveChanges();
session.setDebug(false);
transport = session.getTransport("smtp");
transport.connect(USERNAME,PASSWORD);
transport.sendMessage(message, message.getAllRecipients());
return true;
}
}
检查邮箱格式
public class CheckData {
private static String NUM = ".*\\d+.*";
private static String SMALL = ".*[a-zA-Z]+.*";
private static String CAPTIAL= ".*[a-zA-Z]+.*";
private static String SYMBOL = ".*([~!@#$%^&*()_+|<>,.?/:;'\\[\\]{\\\\}\\\"]){1,}+.*";
private static String EMAIL = "(\\w+([-.][A-Za-z0-9]+)*){3,18}@\\w+([-.][A-Za-z0-9]+)*\\.\\w+([-.][A-Za-z0-9]+)*";
public static boolean checkEmail(String email) {
if (email != null) {
return email.matches(EMAIL);
}
return false;
}
public static boolean checkPass(String password) {
if (password == null){
return false;
}
int size = password.length();
if(size < 6||size >16) {
return false;
}
if(password.matches(SYMBOL)) {
return false;
}
int n = (password.matches(SMALL) ? 1 : 0) + (password.matches(NUM) ? 1 : 0) + (password.matches(CAPTIAL) ? 1 : 0);
return n==3;
}
}
Cache缓存
使用谷歌的一款包
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
public class VerifyCodeCache {
private static volatile Cache<String,String> codeCache;
private VerifyCodeCache(){}
public static Cache<String,String> getCodeCache() {
if (codeCache == null) {
synchronized (VerifyCodeCache.class) {
if (codeCache == null) {
codeCache = CacheBuilder.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.maximumSize(100)
.concurrencyLevel(50).build();
}
}
}
return codeCache;
}
}
SendEmail方法
private ExecutorService executor = Executors.newFixedThreadPool(10);
private Cache<String,String> codeCache = VerifyCodeCache.getCodeCache();
@ResponseBody
@RequestMapping("")
public String sendEmail(String email){
...
if(!CheckData.checkEmail(email)) {
resMessage.setAll(StatusCode.send_fail,"邮箱错误");
...
}
StringBuilder builder = new StringBuilder();
Random random = new Random();
for(int i = 0 ; i<8;i++) {
builder.append(random.nextInt(9));
}
Future<Boolean> future = executor.submit(new SEmail(email,builder.toString()));
try {
future.get(30, TimeUnit.SECONDS);
codeCache.put(email, builder.toString());
...
} catch (InterruptedException e) {
e.getStackTrace();
} catch (ExecutionException e) {
e.getStackTrace();
} catch (TimeoutException e) {
e.getStackTrace();
}
...
}
token 生成
此处用的是Java自带的加密模式,以及自己的加密密钥 注意,UTF-8的byte与String 相互转换会不一样,因为无法表示,因此,使用的是ISO-8859-1
private final static Key SECRET_KEY = new SecretKeySpec("密钥内容".getBytes(),"AES");
public static String createToken(String uuid) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
long currentTimeMillis = System.currentTimeMillis();
String token = uuid + ":"+(currentTimeMillis + TIME_OUT);
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, SECRET_KEY);
return new String(cipher.doFinal(token.getBytes()),"ISO-8859-1");
}
public static String transferToken(String token) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, SECRET_KEY);
byte[] newData = cipher.doFinal(token.getBytes("ISO-8859-1"));
String res = new String(newData);
return res;
}
|