黑马旅游网学习笔记之注册功能(二)
概述
(一)功能分析
(二)前台:表单校验
(三)前台:异步提交表单
(四)后台:Servlet代码的实现
(五)后台:Dao代码的实现
(六)后台:service代码的实现&测试
(七)后台:验证码&前台数据处理
(八)后台:邮件激活分析
(九)后台:发送邮件分析
(十)后台:点击激活分析
(十一)后台:邮件激活代码实现之Servlet
(十二)后台:邮件激活代码实现之service&Dao
(一)功能分析

(二)前台:表单校验
<script>
/*
表单校验:
1.用户名:单词字符,长度8到20位
2.密码:单词字符,长度8到20位
3.email:邮件格式
4.姓别:非空(因为是单选框)
5.手机号:手机号格式
6.出生日期:非空(因为使用了H5的插件)
7.验证码:非空
*/
//校验用户名
function checkUsername() {
//1.获取用户名的值
var username = $("#username").val();
//2.定义正则
var reg_username = /^\w{8,20}$/;
//3.判断,给出提示信息
var flag = reg_username.test(username);
if (flag) {
//用户名合法
$("#username").css("border", "");
} else {
//用户名非法,加一个红色的边框
$("#username").css("border", "1px solid red");
}
return flag;
}
//校验密码
function checkPassword() {
//1.获取密码的值
var password = $("#password").val();
//2.定义正则
var reg_password = /^\w{8,20}$/;
//3.判断,给出提示信息
var flag = reg_password.test(password);
if (flag) {
//密码合法
$("#password").css("border", "");
} else {
//密码非法,加一个红色的边框
$("#password").css("border", "1px solid red");
}
return flag;
}
//校验邮箱
function checkEmail() {
//1.获取邮箱
var email = $("#email").val();
//2.定义正则 itcast@163.com
var reg_email = /^\w+@\w+\.\w+$/;
//3.判断
var flag = reg_email.test(email);
if (flag) {
$("#email").css("border", "");
} else {
$("#email").css("border", "1px solid red");
}
return flag;
}
$(function () {
//当表单提交时,调用所有的校验方法
$("#registerForm").submit(function () {
return checkUsername() && checkPassword() && checkEmail();//只有都为真,表单才会提交
//如果这个方法(这个匿名的function方法)没有返回值,或者返回为true,则表单提交;反之不提交
});
//当某一个组件失去焦点时,调用对应的校验方法
$("#username").blur(checkUsername);
$("#password").blur(checkPassword);
$("#email").blur(checkEmail);
});
</script>
(三)前台:异步提交表单
在此使用异步提交表单是为了获取服务器响应的数据
因为我们前台使用的是html作为视图层,不能够像JSP一样直接从servlet相关的域对象获取值
只能通过ajax获取响应数据
$(function () {
//当表单提交时,调用所有的校验方法
$("#registerForm").submit(function () {
//1.发送数据到服务器
if (checkUsername() && checkPassword() && checkEmail()) {
//校验通过,发送ajax请求,提交表单的数据
$.post("registUserServlet", $(this).serialize(), function (data) {
});
}
//2.跳转页面
// return checkUsername() && checkPassword() && checkEmail();//只有都为真,表单才会提交
return false;
//如果这个方法(这个匿名的function方法)没有返回值,或者返回为true,则表单提交;反之不提交
});
//当某一个组件失去焦点时,调用对应的校验方法
$("#username").blur(checkUsername);
$("#password").blur(checkPassword);
$("#email").blur(checkEmail);
});
(四)后台:Servlet代码的实现
- 前提(一):写一个作用于所有请求的过滤器,用于处理字符集编码的问题

代码:
/**
* 解决全站乱码问题,处理所有的请求
*/
@WebFilter("/*")
public class CharchaterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {
//将父接口转为子接口
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) rep;
//获取请求方法
String method = request.getMethod();
//解决post请求中文数据乱码问题
if (method.equalsIgnoreCase("post")) {
request.setCharacterEncoding("utf-8");
}
//处理响应乱码
response.setContentType("text/html;charset=utf-8");
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
- 前提(二):写一个类,用于封装后端返回前端数据对象

代码:
/**
* 用于封装后端返回前端数据对象
*/
public class ResultInfo implements Serializable {
private boolean flag;//后端返回结果正常为true,发生异常返回false
private Object data;//后端返回结果数据对象
private String errorMsg;//发生异常的错误消息
//无参构造方法
public ResultInfo() {
}
public ResultInfo(boolean flag) {
this.flag = flag;
}
/**
* 有参构造方法
* @param flag
* @param errorMsg
*/
public ResultInfo(boolean flag, String errorMsg) {
this.flag = flag;
this.errorMsg = errorMsg;
}
/**
* 有参构造方法
* @param flag
* @param data
* @param errorMsg
*/
public ResultInfo(boolean flag, Object data, String errorMsg) {
this.flag = flag;
this.data = data;
this.errorMsg = errorMsg;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
- RegistUserServlet.java:
@WebServlet("/registUserServlet")
public class RegistUserServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取数据
Map<String, String[]> map = request.getParameterMap();
//2.封装对象
User user = new User();
try {
BeanUtils.populate(user, map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//3.调用service完成注册
UserService service = new UserServiceImpl();
boolean flag = service.regist(user);
//4.响应结果
ResultInfo info = new ResultInfo();
if (flag) {
//注册成功
info.setFlag(true);
} else {
//注册失败
info.setFlag(false);
info.setErrorMsg("注册失败!");
}
//讲info对象序列化为json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
//讲json数据写回客户端
//设置content-type
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
(五)后台:Dao代码的实现
我们根据UserServiceImpl的两个需求分别写两个Dao类的方法
写Dao类的方法之前,先在Dao类的接口
public interface UserDao {
/**
* 根据用户名查询用户信息
*
* @param username
* @return
*/
public User findByUsername(String username);
/**
* 用户保存
*
* @param user
*/
public void save(User user);
}
接下来写Dao的实现类
public class UserDaoImpl implements UserDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public User findByUsername(String username) {
//1.定义sql
String sql = "select * from tab_user where username = ?";
//2.执行sql
User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
return user;
}
@Override
public void save(User user) {
//1.定义sql
String sql = "insert into user(username,password,name,birthday,sex,telephone,email) values(?,?,?,?,?,?,?)";
//2.执行sql
template.update(sql, user.getUsername(),
user.getPassword(),
user.getName(),
user.getBirthday(),
user.getSex(),
user.getTelephone(),
user.getEmail());
}
}
(六)后台:service代码的实现&测试
在写service代码之前先注意一个问题
使用JdbcTemplate的queryForObject()方法,如果查询不到用户,不会返回Null,而实直接抛出异常
所以我们要捉异常
@Override
public User findByUsername(String username) {
User user = null;
try {
//1.定义sql
String sql = "select * from tab_user where username = ?";
//2.执行sql
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
} catch (Exception e) {
}
return user;
}
UserServiceImpl.java:
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
/**
* 注册用户
*
* @param user
* @return
*/
@Override
public boolean regist(User user) {
//1.根据用户名查询用户对象
User u = userDao.findByUsername(user.getUsername());
//判断u是否为null
if (u != null) {
//用户名存在,注册失败
return false;
}
//2.保存用户信息
userDao.save(user);
return true;
}
}
注意:黑马的教程用的mysql版本是5,我们的是8,要进行以下变动
- 改pom.xml的mysql驱动版本号
- 把我们旧项目的JDBCUtils导进来(详情见JDBC文集)
- 在druid.properties文件加上
cj(详情见JDBC文集) - druid.properties的url后面加上
?useSSL=true&serverTimezone=UTC
(七)后台:验证码&前台数据处理
我们把验证码校验的代码写在最前面,如果验证码错误,就不必进行其他的校验了
//验证码校验
String check = request.getParameter("check");
//从session中获取验证码
HttpSession session = request.getSession();
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
session.removeAttribute("CHECKCODE_SERVER");//为了保证验证码只能使用一次
//比较
if (checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)) {
//验证码错误
ResultInfo info = new ResultInfo();
info.setFlag(false);
info.setErrorMsg("验证码错误!");
//讲info对象序列化为json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
return;
}
前台页面跳转代码如下:
$.post("registUserServlet", $(this).serialize(), function (data) {
if (data.flag) {
//注册成功,跳转成功页面
location.href = "register_ok.html";
} else {
//注册失败,给errorMsg添加提示信息
$("#errorMsg").html(data.errorMsg);
}
});
注意:此时有一个前端的BUG,注册失败需要手动刷新验证码
我们需要在展示错误信息的代码下面加一行代码
(八)后台:邮件激活分析
为什么要进行邮件激活?
- 为了保证用户填写的邮箱是正确的
- 将来可以推广一些宣传信息,到用户邮箱中

(九)后台:发送邮件分析
先准备一个MailUtils工具类
/**
* 发邮件工具类
*/
public final class MailUtils {
private static final String USER = ""; // 发件人称号,同邮箱地址
private static final String PASSWORD = ""; // 如果是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("itcast_xian@163.com", "你好,这是一封测试邮件,无需回复。", "测试邮件");
System.out.println("发送成功");
}
}
配置了网易邮箱发现无法通过测试,配置过程如下:


用同样的方法配置了qq邮箱,并且获得授权码,填到工具类中可以通过测试,如下:
我们从QQ邮箱发送到网易邮箱
效果如下:
(十)后台:点击激活分析
需求分析:
我们看看User类:
所以用户点击超链接激活,后端只需要把该用户的status字段从N改成Y即可
详细分析:
我们先编写UserServiceImpl:
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
/**
* 注册用户
*
* @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;
}
}
效果如下:

注意:我们这里封装Java的UuidUtil工具类来生成全球唯一的字符串
/**
* 产生UUID随机字符串工具类
*/
public final class UuidUtil {
private UuidUtil(){}
public static String getUuid(){
return UUID.randomUUID().toString().replace("-","");
}
/**
* 测试
*/
public static void main(String[] args) {
System.out.println(UuidUtil.getUuid());
System.out.println(UuidUtil.getUuid());
System.out.println(UuidUtil.getUuid());
System.out.println(UuidUtil.getUuid());
}
}
(十一)后台:邮件激活代码实现之Servlet
@WebServlet("/activeUserServlet")
public class ActiveUserServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取激活码
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);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}


(十二)后台:邮件激活代码实现之service&Dao
我们先把save方法完善,如下:
UserServiceImpl:
/**
* 激活用户
*
* @param code
* @return
*/
@Override
public boolean active(String code) {
//1.根据激活码查询用户对象
User user = userDao.findByCode(code);
//2.调用dao的修改激活状态的方法
if (user != null) {
userDao.updateStatus(user);
return true;
} else {
return false;
}
}
UserDao:
/**
* 根据激活码查询用户对象
*
* @param code
* @return
*/
User findByCode(String code);
/**
* 修改执行用户的激活状态
*
* @param user
*/
void updateStatus(User user);
UserDaoImpl:
/**
* 根据激活码查询用户对象
*
* @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 (Exception e) {
e.printStackTrace();
}
return user;
}
/**
* 修改执行用户的激活状态
*
* @param user
*/
@Override
public void updateStatus(User user) {
String sql = "update user set status = 'Y' where id = ?";
template.update(sql, user.getUid());
}
效果:

更多推荐



所有评论(0)