项目总结一:注册模块
一、业务逻辑分析
二、原型图
三、实现过程
1、创建用户模块相关类
User:作为实体类与数据库表对应。
UserDao:封装了数据库的基本操作。
UserService:封装了业务功能,每个方法对应一个业务功能,例如注册方法、登录方法等。
UserServlet:用来接收客户端请求,处理与web相关的问题,例如获取客户端的请求参数,然后转发或重定向。
2、regist.jsp页面功能实现
注册从regist.jsp页面开始。我们需要在regist.jsp页面中对表单数据使用JQuery进行校验。当用户在文本框中输入数据后,光标离开文件框时对数据进行校验!如果校验未通过,会在文本框后台显示错误信息。
用户名校验:
- 用户名不能为空;
- 用户名长度必须在3 ~ 20之间;
- 用户名已被注册(需要异步访问服务器)。
登录密码校验:
- 密码不能为空;
- 密码长度必须在3 ~ 10之间;
确认密码校验:
- 确认密码不能为空;
- 两次输入不一致;
Email校验:
- Email不能为空;
- Email格式错误(/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/);
- Email已被注册(需要异步访问服务器);
验证码校验:
- 验证码不能为空;
- 验证码错误(需要异步访问服务器);
当点击“立即注册”按钮时,还要对表单每项进行校验!因为一开始可能填写了正确的验证码,所以光标离开时没有错误,但用户又点击了“换一张”链接,这时填入的验证码就是错误的了,所以我们需要在提交表单时再次进行校验。
UserServlet对前端异步请求的支持
3、UserServlet#regist()
当表单校验通过后,客户端会请求UserServlet#regist() 方法。regist()方法的工作内容如下:
封装表单数据到User对象中;
对User对象数据进行服务器端校验;
- 如果校验失败,把错误信息保存到Map中;
- 把Map保存到request中;
- 把user保存到request,用来在表单中回显;
- 转发到regist.jsp页面,return;
调用UserService#regist(User)方法完成注册;
- 对user进行数据补全:uid、activationCode、status;
- 通过userDao的add(User)方法完成向数据库表插入记录;
使用TxQueryRunner的update()完成插入记录;
- 发送激活邮件。
保存成功信息,转发到msg.jsp。
/**
* 注册功能
* @param req
* @param resp
* @return
* @throws ServletException
* @throws IOException
*/
public String regist(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*
* 1. 封装表单数据到User对象
*/
User formUser = CommonUtils.toBean(req.getParameterMap(), User.class);
/*
* 2. 校验之, 如果校验失败,保存错误信息,返回到regist.jsp显示
*/
Map<String,String> errors = validateRegist(formUser, req.getSession());
if(errors.size() > 0) {
req.setAttribute("form", formUser);
req.setAttribute("errors", errors);
return "f:/jsps/user/regist.jsp";
}
/*
* 3. 使用service完成业务
*/
userService.regist(formUser);
/*
* 4. 保存成功信息,转发到msg.jsp显示!
*/
req.setAttribute("code", "success");
req.setAttribute("msg", "注册功能,请马上到邮箱激活!");
return "f:/jsps/msg.jsp";
}
/*
* 注册校验
* 对表单的字段进行逐个校验,如果有错误,使用当前字段名称为key,错误信息为value,保存到map中
* 返回map
*/
private Map<String,String> validateRegist(User formUser, HttpSession session) {
Map<String,String> errors = new HashMap<String,String>();
/*
* 1. 校验登录名
*/
String loginname = formUser.getLoginname();
if(loginname == null || loginname.trim().isEmpty()) {
errors.put("loginname", "用户名不能为空!");
} else if(loginname.length() < 3 || loginname.length() > 20) {
errors.put("loginname", "用户名长度必须在3~20之间!");
} else if(!userService.ajaxValidateLoginname(loginname)) {
errors.put("loginname", "用户名已被注册!");
}
/*
* 2. 校验登录密码
*/
String loginpass = formUser.getLoginpass();
if(loginpass == null || loginpass.trim().isEmpty()) {
errors.put("loginpass", "密码不能为空!");
} else if(loginpass.length() < 3 || loginpass.length() > 20) {
errors.put("loginpass", "密码长度必须在3~20之间!");
}
/*
* 3. 确认密码校验
*/
String reloginpass = formUser.getReloginpass();
if(reloginpass == null || reloginpass.trim().isEmpty()) {
errors.put("reloginpass", "确认密码不能为空!");
} else if(!reloginpass.equals(loginpass)) {
errors.put("reloginpass", "两次输入不一致!");
}
/*
* 4. 校验email
*/
String email = formUser.getEmail();
if(email == null || email.trim().isEmpty()) {
errors.put("email", "Email不能为空!");
} else if(!email.matches("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})$")) {
errors.put("email", "Email格式错误!");
} else if(!userService.ajaxValidateEmail(email)) {
errors.put("email", "Email已被注册!");
}
/*
* 5. 验证码校验
*/
String verifyCode = formUser.getVerifyCode();
String vcode = (String) session.getAttribute("vCode");
if(verifyCode == null || verifyCode.trim().isEmpty()) {
errors.put("verifyCode", "验证码不能为空!");
} else if(!verifyCode.equalsIgnoreCase(vcode)) {
errors.put("verifyCode", "验证码错误!");
}
return errors;
}
4、用户激活
激活页面是在用户的邮箱里,是在注册成功时发送到用户邮箱中的。
这里的超链接地址为:"http://localhost:8080/login_regist/UserServlet?method=activation&activationCode=xxx",
其中method=activation表示调用UserServlet的activation()方法;其中activationCode就是用户注册成功后生成的唯一激活码!通过唯一的activationCode可以在表中查询出User,如果没有查询到User,那么说明激活码无效;如果查询到了,把User的status修改为true,就表示激活成功。
激活功能的代码实现:
1、首先是发送邮件到注册的邮箱
/* * 3. 发邮件 */ /* * 把配置文件内容加载到prop中 */ Properties prop = new Properties(); try { prop.load(this.getClass().getClassLoader().getResourceAsStream("email_template.properties")); } catch (IOException e1) { throw new RuntimeException(e1); } /* * 登录邮件服务器,得到session */ String host = prop.getProperty("host");//服务器主机名 String name = prop.getProperty("username");//登录名 String pass = prop.getProperty("password");//登录密码 Session session = MailUtils.createSession(host, name, pass); /* * 创建Mail对象 */ String from = prop.getProperty("from"); String to = user.getEmail(); String subject = prop.getProperty("subject"); // MessageForm.format方法会把第一个参数中的{0},使用第二个参数来替换。 String content = MessageFormat.format(prop.getProperty("content"), user.getActivationCode()); Mail mail = new Mail(from, to, subject, content); /* * 发送邮件 */ try { MailUtils.send(session, mail); } catch (MessagingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } }
2、用户点击上面的超链接,会访问UserServlet#activation()方法
如下所示:
/** * 激活功能 * @param req * @param resp * @return * @throws ServletException * @throws IOException */ public String activation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * 1. 获取参数激活码 * 2. 用激活码调用service方法完成激活 * > service方法有可能抛出异常, 把异常信息拿来,保存到request中,转发到msg.jsp显示 * 3. 保存成功信息到request,转发到msg.jsp显示。 */ String code = req.getParameter("activationCode"); try { userService.activatioin(code); req.setAttribute("code", "success");//通知msg.jsp显示对号 req.setAttribute("msg", "恭喜,激活成功,请马上登录!"); } catch (UserException e) { // 说明service抛出了异常 req.setAttribute("msg", e.getMessage()); req.setAttribute("code", "error");//通知msg.jsp显示X } return "f:/jsps/msg.jsp"; }