注册功能——Java Mail实现本地注册时邮箱的验证
主要使用JSP+Servlet的方式来完成一个发送邮箱邮件完成验证注册
其中邮件的收发过程:
注册功能的主要逻辑是:
- 用户填写相关信息,点击注册按钮
- 系统先将用户记录保存到数据库中,其中用户状态为未激活
- 系统发送一封邮件并通知用户去验证
- 用户登录邮箱并点击激活链接
- 系统将用户状态更改为已激活并通知用户注册成功
涉及内容分析:
1. 前端校验:
先在前端,校验用户名,密码,手机号,邮箱等信息都是采用正则表达式先进行第一步校验,检查是否合法,目的是:提升用户体验,并减轻服务器压力
前端是采用异步ajax提交表单,为了获取服务器响应的数据。因为我们前台使用的是html作为视图层,不能够直接从servlet相关的域对象获取数据,只能通过ajax获取响应数据
2. JavaWeb知识点:
- servlet域四大对象
域对象的作用:用于保存数据,获取数据-
pageContext
pageContext作用域为page(页面执行期)。
-
request
request是表示一个请求,只要发出一个请求就会创建一个request,它的作用域仅在当前请求中有效。
用处:服务器间同一请求不同页面之间的参数传递
-
session
服务器会为每一个会话创建一个Session对象,所以Session中的数据可供当前会话中所有Servlet共享。
用处:常用于web开发中的登录验证界面(当用户登陆成功后浏览器分配其中一个Session键值对)。
-
Application
作用范围:所有的用户都可以取得此信息,此信息在整个服务器端被保留。Application属性范围值只要设置一次,则所有的网页窗口都可以取得数据。ServletContext在服务器启动时创建,在服务器关闭时销毁,一个JavaWeb应用只创建一个ServletContext对象。
-
servlet九大内置对象
- request对象
- response对象
- session对象
- application对象
- out对象
- pageContext对象
- config对象
- page对象
- exception对象
-
-
3. 采用doPost请求
为什么使用doPost请求,和doGet有什么区别?用doPost有什么好处?
- get传送的数据量较小,不能大于2kb;post传送的数据量较大,一般不受限制
- get是从服务器上获取数据的,post是往服务器传送数据
- 安全性,get安全性低,因为发送的数据是URL的一部分;post安全性较高,传递的参数不会被保存在浏览器历时或日志中
4. 在后端的session中获取验证码并验证
为什么先校验验证码?
- 验证码校验,先判断验证码,不正确就不用校验别的数据了,节省空间
怎么校验验证码?
5. 验证码正确,获取数据,并封装成对象,调用service完成注册,注册成功后将info对象序列化为json,并切回客户端
userService用来注册用户,激活用户,并且进行登录
- 注册用户
-
判断用户名是否存在
-
存在,返回false,注册失败
- return false;
-
不存在,调用dao保存用户信息,并将用户激活状态设置为N,之后进行邮件激活
- userDao.save(user)——调用dao保存用户信息
-
/**
* 注册用户
* @param user
* @return
*/
@Override
public boolean regist(User user) {
//1.根据用户名查询用户对象
User u = userDao.findByUsername(user.getUsername());
//判断u是否为null
if (u != null){
//用户名存在,注册失败
return false;
}
//2.保存用户信息
//2.1设置激活码,唯一字符串
user.setCode(UuidUtil.getUuid());
//2.2设置激活状态
user.setStatus("N");
userDao.save(user);
//3.激活邮件发送,邮件正文?
String content = "<a href='http://localhost/travel/activeUserServlet?code="+user.getCode() + "'>点击激活【这是个激活链接】</a>";
MailUtils.sendMail(user.getEmail(),content,"激活邮件");
return true;
}
邮件工具类:
package cn.itcast.travel.util;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/**
* 发邮件工具类
*/
public final class MailUtils {
private static final String USER = "1361050253@qq.com"; // 发件人称号,同邮箱地址
private static final String PASSWORD = "nlgrgqszkbuxfgbj"; // 如果是qq邮箱可以使户端授权码,或者登录密码
/**
*
* @param to 收件人邮箱
* @param text 邮件正文
* @param title 标题
*/
/* 发送验证信息的邮件 */
public static boolean sendMail(String to, String text, String title){
try {
final Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", "smtp.qq.com");
// 发件人的账号
props.put("mail.user", USER);
//发件人的密码
props.put("mail.password", PASSWORD);
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
String username = props.getProperty("mail.user");
InternetAddress form = new InternetAddress(username);
message.setFrom(form);
// 设置收件人
InternetAddress toAddress = new InternetAddress(to);
message.setRecipient(Message.RecipientType.TO, toAddress);
// 设置邮件标题
message.setSubject(title);
// 设置邮件的内容体
message.setContent(text, "text/html;charset=UTF-8");
// 发送邮件
Transport.send(message);
return true;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
public static void main(String[] args) throws Exception { // 做测试用
MailUtils.sendMail("cc15979097571@163.com","你好,这是一封测试邮件,无需回复。","测试邮件");
System.out.println("发送成功");
}
}
- 激活用户
通过激活邮件发送,写了一个邮件工具类进行发送邮件
-
为什么要激活邮件?
- 为了保证用户填写的邮箱是正确的,将来可以推广一些宣传信息到用户邮箱中。
-
邮件激活的几个步骤:
-
发送邮件
- 开启授权码
- 在邮件工具类(MailUtils)中设置自己的邮箱账号和密码(授权码)
- 一般有现成的激活邮件的工具类
-
邮件激活
-
编写一个生成唯一字符串Uuid的类,并写入到用户信息中
- 为什么要生成Uuid,为什么不用id直接作为code?
1、——获取user对象,点击超链接需要区分是哪个用户点击的超链接,判断是哪个用户要激活,则用生成的Uuid,因为他是唯一的
2、——激活码,用户激活用户,如果是用id的话就特别好猜,安全性不高
3、——通过定义一个content文本信息,传入激活链接的URL,其中URL中携带code参数,点击后进行URL的跳转,则判定激活成功。
- 为什么要生成Uuid,为什么不用id直接作为code?
-
获取激活码
- 通过activeUserServlet类获取code激活码,去service查询用户对象和修改激活状态,并且service层去调用Dao层操作数据库,如果dao层没有找到用户信息就打印错误,否则更新用户状态
-
-
UserServiceImpl:
点击邮件激活用户后,根据用户码查询用户对象,并且修改激活状态
/**
* 激活用户
* @param code
* @return
*/
@Override
public boolean active(String code) {
//1.根据激活码查询用户对象
User user = userDao.findByCode(code);
if (user != null){
//2.调用dao的修改激活状态的方法
userDao.updataStatus(user);
return true;
}else {
return false;
}
}
UserDaoImpl:
UserDao层进行用户激活状态的修改和根据激活码查询用户对象是否存在
/**
* 根据激活码查询用户对象
* @param code
* @return
*/
@Override
public User findByCode(String code) {
User user = null;
try {
String sql = "select * from tab_user where code = ?";
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), code);
} catch (DataAccessException e) {
System.out.println("打印错误信息:");
e.printStackTrace();
System.out.println("结束错误信息打印");
System.out.println("报错,没有查出会抛异常,而不会返回null");
}
return user;
}
/**
* 修改指定用户激活状态
* @param user
*/
@Override
public void updataStatus(User user) {
String sql = "update tab_user set status = 'Y' where uid = ?";
template.update(sql,user.getUid());
}
-
判断是否有激活码
为什么要判断是否有激活码?
因为如果恶意用浏览器直接访问servlet,但是没有激活码,则查询过多会造成数据库的压力- 根据激活码查询user对象,判断对象是否为空,不为空则调用service激活
@WebServlet("/activeUserServlet")
public class ActiveUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.点击链接里面的,获取激活码code
String code = request.getParameter("code");
if (code != null){
//2.调用service完成激活
UserService service = new UserServiceImpl();
boolean flag = service.active(code);
//3.判断标记
String msg = null;
if (flag){
//激活成功
msg = "激活成功,请<a href='login.html'>登录</a>";
}else {
//激活失败
msg = "激活失败,请联系管理员!";
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(msg);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}