文章目录
- 一、GUI开发
- 二、读取邮件、验证验证码
- 三、发邮件
本文主要学习的是邮箱验证码知识,只是需要一个载体来验证这个功能,所以选择了gui。
直接看最终效果图
两个输入框两个按钮,输入邮箱,点击获取,登入邮箱查看验证码,再输入验证码,点击登录,流程结束
一、GUI开发
定义一个JFrame
JFrame frame = new JFrame("登录");
// 设置frame的其他属性
frame.setSize(300, 300);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
// 替换左上角默认java图标,如果图片不存在,还会使用默认图标
Image icon = Toolkit.getDefaultToolkit().getImage("C:\\Users\\diyan\\Pictures\\avatar.jpg");
frame.setIconImage(icon);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
定义面板JPanel上的控件,绝对定位布局,通过坐标(x,y)和宽高(w,h)来实现控件的布局,这里的数字需要进行简单的计算方能保证控件的对齐
// 第一行
JLabel title = new JLabel("登录界面");
title.setBounds(100, 20, 300, 30);
// 第二行
JLabel mailLabel = new JLabel("邮箱:");
mailLabel.setBounds(30, 70, 100, 30);
JTextField mailField = new JTextField(17);
mailField.setBounds(80, 70, 170, 30);
// 第三行
JLabel codeLabel = new JLabel("验证码:");
codeLabel.setBounds(30, 120, 100, 30);
JTextField codeField = new JTextField(12);
codeField.setBounds(80, 120, 100, 30);
JButton getBtn = new JButton("获取");
getBtn.setBounds(185, 120, 65, 30);
// 第四行
JButton loginBtn = new JButton("登录");
loginBtn.setBounds(30, 170, 220, 30);
定义一个JPanel,把上一步的控件全部add进来
JPanel panel = new JPanel();
panel.setLayout(null);
panel.add(title);
panel.add(mailLabel);
panel.add(mailField);
panel.add(codeLabel);
panel.add(codeField);
panel.add(getBtn);
panel.add(loginBtn);
面板里有两个按钮,点击事件处理,具体的处理逻辑就是本文的核心
getBtn.addActionListener(e -> {
String mail = mailField.getText();
if (mail == null || mail.isEmpty()) {
JOptionPane.showMessageDialog(frame, "邮箱不能为空!");
return;
}
if (!isValidEmail(mail)) {
JOptionPane.showMessageDialog(frame, "邮箱格式不合法!");
return;
}
// 获取验证码前先判断当前邮箱5分钟之内是否已发送过验证码
JDialog dialog = showProgress(frame);
// 此处的111111为随便填的6个数字,为的就是返回code300,当然该代码还可优化
Map<String, Object> res = MailUtil.verifyCode(mail, "111111");
if ((int) res.get("code") == 301) {
MailUtil.sendEmail(mail);
hideProgress(dialog);
JOptionPane.showMessageDialog(frame, "验证码已发送!");
} else if ((int) res.get("code") == 300) {
hideProgress(dialog);
JOptionPane.showMessageDialog(frame, "您的验证码获取过于频繁,请稍后再试!");
}
});
loginBtn.addActionListener(e -> {
System.out.println("点击了登录");
String mail = mailField.getText();
String code = codeField.getText();
if (mail == null || mail.isEmpty()) {
JOptionPane.showMessageDialog(frame, "邮箱不能为空!");
return;
}
if (!isValidEmail(mail)) {
JOptionPane.showMessageDialog(frame, "邮箱格式不合法!");
return;
}
if (code == null || code.isEmpty()) {
JOptionPane.showMessageDialog(frame, "验证码不能为空!");
return;
}
JDialog dialog = showProgress(frame);
Map<String, Object> res = MailUtil.verifyCode(mail, code);
if ((int) res.get("code") == 200) {
hideProgress(dialog);
JOptionPane.showMessageDialog(frame, "登录成功!");
} else {
hideProgress(dialog);
JOptionPane.showMessageDialog(frame, "登录失败," + (String) res.get("msg"));
}
});
最后把面板JPanel添加到JFrame中,并让JFrame显示
frame.add(panel);
// 显示frame
frame.setVisible(true);
工具方法
显隐等待框
// 显示等待框
private static JDialog showProgress(JFrame frame) {
JDialog dialog = new JDialog(frame, "登陆中...");
dialog.setSize(100, 100);
dialog.setLocationRelativeTo(null);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setVisible(true); // 显示进度等待框
return dialog;
}
// 隐藏等待框
private static void hideProgress(JDialog dialog) {
dialog.setVisible(false); // 关闭进度等待框
dialog.dispose(); // 释放资源
}
邮箱格式验证
private static final Pattern EMAIL_PATTERN =
Pattern.compile(
"[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
"\\@" +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
"(" +
"\\." +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
")+"
);
private static boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
二、读取邮件、验证验证码
关于邮件读写,我这里使用的是qq邮箱
读取邮件
/**
* 读取发件箱指定收件人邮件
*/
public static Map<String,Object> readMail(String host, int port, String userName, String password, String toAddress,String code) throws MessagingException, IOException {
Map<String,Object> res = new HashMap<>();
res.put("code",301);
res.put("msg","验证失败");
Properties properties = new Properties();
properties.put("mail.store.protocol", "imaps");
// 普通邮箱
properties.put("mail.imaps.starttls.enable", "true");
properties.put("mail.imaps.host", host);
properties.put("mail.imaps.port", port);
Session session = Session.getDefaultInstance(properties);
Store store = session.getStore();
store.connect(userName, password);
Folder box = store.getFolder("已发送");
box.open(Folder.READ_ONLY);
// 应该只能取最近一个月或一年的
Message[] messages = box.getMessages();
for (Message msg : messages) {
if (msg instanceof MimeMessage) {
MimeMessage mimeMessage = (MimeMessage) msg;
// 获取收件人
StringBuilder addressSb = new StringBuilder();
InternetAddress[] recipients = (InternetAddress[]) mimeMessage.getAllRecipients();
for (InternetAddress addr : recipients) {
addressSb.append(addr.getAddress()).append(",");
}
String address = addressSb.substring(0, addressSb.length() - 1);
if(!address.contains(toAddress)){
System.out.println("不是目标用户,PASS");
continue;
}
// 获取发送时间,计算有效期
Date sentDate = mimeMessage.getSentDate();
Date now = new Date();
long fiveMinute = 5 * 60 * 1000;
boolean flag = fiveMinute >= (now.getTime() - sentDate.getTime());
if (!flag) {
System.out.println("验证码已失效,PASS");
continue;
}
// 获取邮件内容
Object content = mimeMessage.getContent();
if (content instanceof String) {
// 正则表达式匹配出验证码
String expression = "\\d+";
Pattern pattern = Pattern.compile(expression);
Matcher matcher = pattern.matcher((String) content);
if (matcher.find()) {
String realCode = matcher.group();
if(realCode.equals(code)){
res.put("code",200);
res.put("msg","验证成功");
}else{
res.put("code",300);
res.put("msg","验证码错误");
}
System.out.println("验证码==>" + realCode);
}
}
}
}
box.close();
store.close();
return res;
}
验证码
public static Map<String,Object> verifyCode(String mail,String code){
Map<String,Object> res = new HashMap<>();
try {
res = MailUtil.readMail("imap.qq.com", 993, "真实邮箱账号", "真实邮箱密码"
, mail,code);
}catch (Exception e){
res.put("code",302);
res.put("msg","验证异常:" + e.getMessage());
e.printStackTrace();
}
return res;
}
三、发邮件
public static void sendEmail(String host, int port, String userName, String password,
String toAddress, String subject, String message) throws MessagingException, IOException {
Properties properties = new Properties();
// 是否需要用户认证
properties.put("mail.smtp.auth", "true");
// 普通邮箱
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", port);
// qq邮箱
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
Session session = Session.getInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
});
session.setDebug(true);
MimeMessage mimeMessage = new MimeMessage(session);
// qq邮箱
mimeMessage.setFrom(new InternetAddress("真实发件人邮箱地址"));
mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
mimeMessage.setSubject(subject);
mimeMessage.setText(message);
Transport.send(mimeMessage);
}
发邮件方法简化
public static void sendEmail(String toAddress){
try {
MailUtil.sendEmail("smtp.qq.com", 465, "真实邮箱地址", "真实邮箱密码"
, toAddress, "测试验证码", "【苏州测试】您的验证码为" + MailUtil.generateRandomCode() + ",有效期为5分钟");
}catch (Exception e){
e.printStackTrace();
}
}
生成4位随机验证码
public static String generateRandomCode() {
Random random = new Random();
StringBuilder code = new StringBuilder();
for (int i = 0; i < 4; i++) {
int num = random.nextInt(10);
code.append(num);
}
return code.toString();
}