一、功能分析
1.注册页面前后台的验证
2.注册功能实现
3.激活功能实现
二、代码实现
1.前端验证
1 $(function() { 2 /* 3 * 1. 得到所有的错误信息,循环遍历之。调用一个方法来确定是否显示错误信息! 4 */ 5 $(".labelError").each(function() { 6 showError($(this));//遍历每个元素,使用每个元素来调用showError方法 7 }); 8 9 /* 10 * 2. 切换注册按钮的图片 11 */ 12 $("#submitBtn").hover( 13 function(){$(this).attr("src", "/goods/images/regist2.jpg")}, 14 function(){$(this).attr("src", "/goods/images/regist1.jpg")} 15 ); 16 17 /* 18 * 3. 输入框得到焦点隐藏错误信息 19 */ 20 $(".input").focus(function() { 21 var labelId = $(this).attr("id") + "Error";//通过输入框找到对应的label的id 22 var domEl = $("#" + labelId); 23 domEl.text("");//把label的内容清空! 24 showError(domEl);//隐藏没有信息的label 25 }); 26 27 /* 28 * 4. 输入框失去焦点进行校验 29 */ 30 $(".input").blur(function() { 31 var id = $(this).attr("id");//获取当前输入框的id 32 var funName = "validate" + id.substring(0,1).toUpperCase() + id.substring(1) + "()";//得到对应的校验函数名 33 eval(funName);//执行函数调用 34 }); 35 36 /* 37 * 5. 表单提交时进行校验 38 */ 39 $("#registForm").submit(function() { 40 var result = true; 41 if(!validateLoginname()) result = false; 42 if(!validateLoginpass()) result = false; 43 if(!validateReloginpass()) result = false; 44 if(!validateEmail()) result = false; 45 if(!validateVerifyCode()) result = false; 46 return result; 47 }); 48 }) 49 50 /* 51 * 登录名校验方法 52 */ 53 function validateLoginname() { 54 var $id = "#loginname"; 55 var value = $($id).val();//获取输入框内容 56 var $errorId = $id + "Error"; 57 /* 58 * 1. 非空校验 59 */ 60 if(!value) { 61 /* 62 * 获取对应的label 63 * 添加错误信息 64 * 显示label 65 */ 66 processError($errorId, "用户名不能为空!"); 67 return false; 68 } 69 /* 70 * 2. 长度校验 71 */ 72 if(value.length < 3 || value.length > 20) { 73 /* 74 * 获取对应的label 75 * 添加错误信息 76 * 显示label 77 */ 78 processError($errorId, "用户名长度必须在3 ~ 20之间!"); 79 return false; 80 } 81 /* 82 * 3. 是否注册校验 83 */ 84 $.ajax({ 85 url:"/goods/UserServlet", 86 data:{method : "validateLoginname", loginname:value}, 87 type:"POST", 88 dataType:"json", 89 asycn:false,//是否异步请求,如果是异步,那么不会等服务器返回,我们这个函数就向下运行了。 90 cache:false, 91 success:function(result) { 92 if(!result) { 93 processError($errorId, "用户名已被注册!"); 94 return false; 95 } 96 } 97 }); 98 return true; 99 } 100 101 /* 102 * 登录密码校验方法 103 */ 104 function validateLoginpass() { 105 var $id = "#loginpass"; 106 var $errorId = $id + "Error"; 107 var value = $($id).val(); 108 if(!value) { 109 processError($errorId, "密码不能为空!"); 110 return false; 111 } 112 if(value.length < 3 || value.length > 20) { 113 processError($errorId, "密码长度必须在3 ~ 20之间!"); 114 return false; 115 } 116 return true; 117 } 118 119 /* 120 * 确认密码校验方法 121 */ 122 function validateReloginpass() { 123 var $id = "#reloginpass"; 124 var $errorId = $id + "Error"; 125 var value = $($id).val(); 126 if(!value) { 127 processError($errorId, "确认密码不能为空!"); 128 return false; 129 } 130 if(value != $("#loginpass").val()){ 131 processError($errorId, "两次输入不一致!"); 132 return false; 133 } 134 return true; 135 } 136 137 /* 138 * 判断当前元素是否存在内容,如果存在显示,不页面不显示! 139 */ 140 function showError(ele) { 141 var text = ele.text();//获取元素的内容 142 if(!text) {//如果没有内容 143 ele.css("display", "none");//隐藏元素 144 } else {//如果有内容 145 ele.css("display", "");//显示元素 146 } 147 } 148 149 /** 150 * Email校验方法 151 */ 152 function validateEmail() { 153 var $id = "#email"; 154 var $errorId = $id + "Error"; 155 var value = $($id).val(); 156 if(!value){ 157 processError($errorId, "Email不能为空!"); 158 return false; 159 } 160 //Email格式校验 161 if(!/^([a-zA-Z0-9_-])+@([a-zA-Z-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(value)) { 162 processError($errorId, "错误的Email格式!"); 163 return false; 164 } 165 $.ajax({ 166 url : "/goods/UserServlet", 167 data : {method : "validateEmail", email : value}, 168 type : "post", 169 dataType: "json", 170 async : false, 171 cache : false, 172 success : function(result) { 173 if(!result) { 174 processError($errorId, "Email已被注册!"); 175 return false; 176 } 177 } 178 }); 179 return true; 180 } 181 182 /* 183 * 验证码校验方法 184 */ 185 function validateVerifyCode() { 186 var $id = "#verifyCode"; 187 var $errorId = $id + "Error"; 188 var value = $($id).val(); 189 if(!value) { 190 processError($errorId, "验证码不能为空!"); 191 return false; 192 } 193 194 //长度验证 195 if(value.length != 4) { 196 processError($errorId, "错误的验证码!"); 197 return false; 198 } 199 200 //是否正确 201 $.ajax({ 202 url : "/goods/UserServlet", 203 data : {method : "validateVerifyCode", verifyCode : value}, 204 type : "POST", 205 dataType : "json", 206 asyc : false, 207 cache : false, 208 success : function(result) { 209 if(!result) { 210 processError($errorId, "验证码错误!"); 211 return false; 212 } 213 } 214 }); 215 return true; 216 } 217 218 /* 219 * 换一张验证码 220 */ 221 function _changeVerifyCode() { 222 /* 223 * 1. 获取<img>元素 224 * 2. 重新设置它的src 225 * 3. 使用毫秒来添加参数 226 */ 227 $("#vCode").attr("src", "/goods/VerifyCodeServlet?'/>" + new Date().getTime()); 228 } 229 230 /* 231 * 校验完后调用此方法进行错误信息处理 232 */ 233 function processError($errorId, msg) { 234 var errorEl = $($errorId); 235 errorEl.text(msg); 236 showError(errorEl); 237 return; 238 }
2.后台验证
(1)servlet层
a).UserServlet.java
1 package com.tony.goods.user.web.servlet; 2 3 import java.io.IOException; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import javax.servlet.http.HttpSession; 10 11 import cn.itcast.commons.CommonUtils; 12 import cn.itcast.servlet.BaseServlet; 13 14 import com.tony.goods.user.domain.User; 15 import com.tony.goods.user.service.UserService; 16 import com.tony.goods.user.service.exception.UserException; 17 18 /** 19 * 用户模块WEB层 20 * @author T 21 * 22 */ 23 public class UserServlet extends BaseServlet { 24 25 private UserService userService = new UserService(); 26 27 /** 28 * 用户名是否注册校验 29 * @param request 30 * @param response 31 * @return 32 * @throws IOException 33 */ 34 public String validateLoginname(HttpServletRequest request, HttpServletResponse response) throws IOException { 35 String loginname = request.getParameter("loginname"); 36 boolean result = userService.validateLoginname(loginname); 37 response.getWriter().print(result); 38 return null; 39 } 40 41 /** 42 * Email是否注册校验 43 * @param request 44 * @param response 45 * @return 46 * @throws IOException 47 */ 48 public String validateEmail(HttpServletRequest request, HttpServletResponse response) throws IOException { 49 String email = request.getParameter("email"); 50 boolean result = userService.validateEmail(email); 51 response.getWriter().print(result); 52 return null; 53 } 54 55 /** 56 * Email是否注册校验 57 * @param request 58 * @param response 59 * @return 60 * @throws IOException 61 */ 62 public String validateVerifyCode(HttpServletRequest request, HttpServletResponse response) throws IOException { 63 //1. 获取输入框中的验证码 64 String verifyCode = request.getParameter("verifyCode"); 65 //2. 获取图片上真实的校验码 66 String vCode = (String) request.getSession().getAttribute("vCode"); 67 //3. 进行忽略大小写比较,得到结果 68 boolean result = verifyCode.equalsIgnoreCase(vCode); 69 response.getWriter().print(result); 70 return null; 71 } 72 73 public String regist(HttpServletRequest request, HttpServletResponse response) { 74 //1. 封装表单数据到User对象 75 User formUser = CommonUtils.toBean(request.getParameterMap(), User.class); 76 77 //2. 校验之, 如果校验失败,保存错误信息,返回到regist.jsp显示 78 Map<String, String> errors = validateRegist(formUser, request.getSession()); 79 if(errors.size() > 0) { 80 request.setAttribute("form", formUser); 81 request.setAttribute("errors", errors); 82 return "f:/jsps/user/regist.jsp"; 83 } 84 //3. 使用service完成业务,会 发激活链接到邮箱 85 userService.regist(formUser); 86 87 //4. 保存成功信息,转发到msg.jsp显示! 88 request.setAttribute("code", "success"); 89 request.setAttribute("msg", "注册成功,请马上到邮箱激活!"); 90 return "f:/jsps/msg.jsp"; 91 } 92 93 /** 94 * 注册校验 95 * 对表单的字段进行逐个校验,如果有错误,使用当前字段名称为key,错误信息为value,保存到map中 96 * 返回map 97 */ 98 private Map<String, String> validateRegist(User formUser, HttpSession session) { 99 Map<String, String> errors = new HashMap<String, String>(); 100 // 1. 校验登录名 101 String loginname = formUser.getLoginname(); 102 if(loginname == null || loginname.trim().isEmpty()) { 103 errors.put("loginname", "用户名不能为空!"); 104 } else if(loginname.length() < 3 || loginname.length() > 20) { 105 errors.put("loginname", "用户名长度必须在3~20之间!"); 106 } else if(!userService.validateLoginname(loginname)) { 107 errors.put("loginname", "用户名已被注册!"); 108 } 109 110 // 2. 校验登录密码 111 String loginpass = formUser.getLoginpass(); 112 if(loginpass == null || loginpass.trim().isEmpty()) 113 errors.put("loginpass", "密码不能为空!"); 114 else if(loginpass.length() < 3 || loginpass.length() > 20) 115 errors.put("loginpass", "密码长度必须在3~20之间!"); 116 117 // 3. 确认密码校验 118 String reloginpass = formUser.getReloginpass(); 119 if(reloginpass == null || reloginpass.trim().isEmpty()) { 120 errors.put("reloginpass", "确认密码不能为空!"); 121 } else if(!reloginpass.equals(loginpass)) { 122 errors.put("reloginpass", "两次输入不一致!"); 123 } 124 125 // 4. 校验email 126 String email = formUser.getEmail(); 127 if(email == null || email.trim().isEmpty()) { 128 errors.put("email", "Email不能为空!"); 129 } else if(!email.matches("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})$")) { 130 errors.put("email", "Email格式错误!"); 131 } else if(!userService.validateEmail(email)) { 132 errors.put("email", "Email已被注册!"); 133 } 134 135 // 5. 验证码校验 136 String verifyCode = formUser.getVerifyCode(); 137 String vCode = (String) session.getAttribute("vCode"); 138 if(verifyCode == null || verifyCode.trim().isEmpty()) { 139 errors.put("verifyCode", "验证码不能为空!"); 140 } else if(!verifyCode.equalsIgnoreCase(vCode)) { 141 errors.put("verifyCode", "验证码错误!"); 142 } 143 144 return errors; 145 } 146 147 /** 148 * 激活功能 149 * @param request 150 * @param response 151 * @return 152 */ 153 public String activation(HttpServletRequest request, HttpServletResponse response) { 154 /* 155 * 1. 获取参数激活码 156 * 2. 用激活码调用service方法完成激活 157 * > service方法有可能抛出异常, 把异常信息拿来,保存到request中,转发到msg.jsp显示 158 * 3. 保存成功信息到request,转发到msg.jsp显示。 159 */ 160 String code = request.getParameter("activationCode"); 161 try { 162 userService.activate(code); 163 request.setAttribute("code", "success");//通知msg.jsp显示对号 164 request.setAttribute("msg", "恭喜,激活成功,请马上登录!"); 165 } catch (UserException e) { 166 // 说明service抛出了异常 167 request.setAttribute("msg", e.getMessage()); 168 request.setAttribute("code", "error");//通知msg.jsp显示X 169 } 170 return "f:/jsps/msg.jsp"; 171 } 172 }
b).BaseServlet.java
1 package cn.itcast.servlet; 2 3 import java.io.IOException; 4 import java.lang.reflect.Method; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * BaseServlet用来作为其它Servlet的父类 13 * 14 * @author qdmmy6 15 * 16 * 一个类多个请求处理方法,每个请求处理方法的原型与service相同! 原型 = 返回值类型 + 方法名称 + 参数列表 17 */ 18 @SuppressWarnings("serial") 19 public class BaseServlet extends HttpServlet { 20 @Override 21 public void service(HttpServletRequest request, HttpServletResponse response) 22 throws ServletException, IOException { 23 response.setContentType("text/html;charset=UTF-8");//处理响应编码 24 25 /** 26 * 1. 获取method参数,它是用户想调用的方法 2. 把方法名称变成Method类的实例对象 3. 通过invoke()来调用这个方法 27 */ 28 String methodName = request.getParameter("method"); 29 Method method = null; 30 /** 31 * 2. 通过方法名称获取Method对象 32 */ 33 try { 34 method = this.getClass().getMethod(methodName, 35 HttpServletRequest.class, HttpServletResponse.class); 36 } catch (Exception e) { 37 throw new RuntimeException("您要调用的方法:" + methodName + "它不存在!", e); 38 } 39 40 /** 41 * 3. 通过method对象来调用它 42 */ 43 try { 44 String result = (String)method.invoke(this, request, response); 45 if(result != null && !result.trim().isEmpty()) {//如果请求处理方法返回不为空 46 int index = result.indexOf(":");//获取第一个冒号的位置 47 if(index == -1) {//如果没有冒号,使用转发 48 request.getRequestDispatcher(result).forward(request, response); 49 } else {//如果存在冒号 50 String start = result.substring(0, index);//分割出前缀 51 String path = result.substring(index + 1);//分割出路径 52 if(start.equals("f")) {//前缀为f表示转发 53 request.getRequestDispatcher(path).forward(request, response); 54 } else if(start.equals("r")) {//前缀为r表示重定向 55 response.sendRedirect(request.getContextPath() + path); 56 } 57 } 58 } 59 } catch (Exception e) { 60 throw new RuntimeException(e); 61 } 62 } 63 }
(2)service层
a).UserService.java
1 package com.tony.goods.user.service; 2 3 import java.io.IOException; 4 import java.sql.SQLException; 5 import java.text.MessageFormat; 6 import java.util.Properties; 7 8 import javax.mail.MessagingException; 9 import javax.mail.Session; 10 11 import cn.itcast.commons.CommonUtils; 12 import cn.itcast.mail.Mail; 13 import cn.itcast.mail.MailUtils; 14 15 import com.tony.goods.user.dao.UserDao; 16 import com.tony.goods.user.domain.User; 17 import com.tony.goods.user.service.exception.UserException; 18 19 /** 20 * 用户模块业务层 21 * @author T 22 * 23 */ 24 public class UserService { 25 private UserDao userDao = new UserDao(); 26 27 /** 28 * 用户名注册校验 29 * @param loginname 30 * @return 31 */ 32 public boolean validateLoginname(String loginname) { 33 try { 34 return userDao.validateLoginname(loginname); 35 } catch (SQLException e) { 36 throw new RuntimeException(e); 37 } 38 } 39 40 /** 41 * Email校验 42 * @param email 43 * @return 44 */ 45 public boolean validateEmail(String email) { 46 try { 47 return userDao.validateEmail(email); 48 } catch (SQLException e) { 49 throw new RuntimeException(e); 50 } 51 } 52 53 public void regist(User user) { 54 //1. 数据的补齐 55 user.setUid(CommonUtils.uuid()); 56 user.setStatus(false); 57 user.setActivationCode(CommonUtils.uuid() + CommonUtils.uuid()); 58 59 //2. 向数据库插入 60 try { 61 userDao.add(user); 62 } catch (SQLException e) { 63 throw new RuntimeException(e); 64 } 65 66 //3. 发邮件 67 //3.1 把配置文件内容加载到prop中 68 Properties prop = new Properties(); 69 try { 70 prop.load(this.getClass().getClassLoader().getResourceAsStream("email_template.properties")); 71 } catch (IOException e) { 72 throw new RuntimeException(e); 73 } 74 //3.2 登录邮件服务器,得到session 75 String host = prop.getProperty("host"); 76 String username = prop.getProperty("username"); 77 String password = prop.getProperty("password"); 78 Session session = MailUtils.createSession(host, username, password); 79 80 //3.3 创建Mail对象 81 String from = prop.getProperty("from"); 82 String to = user.getEmail(); 83 String subject = prop.getProperty("subject"); 84 // MessageForm.format方法会把第一个参数中的{0},使用第二个参数来替换。 85 // 例如MessageFormat.format("你好{0}, 你{1}!", "张三", "去死吧"); 返回“你好张三,你去死吧!” 86 String content = MessageFormat.format(prop.getProperty("content"), user.getActivationCode()); 87 Mail mail = new Mail(from, to ,subject, content); 88 89 //3.4 发送邮件 90 try { 91 MailUtils.send(session, mail); 92 } catch (MessagingException e) { 93 throw new RuntimeException(e); 94 } catch (IOException e) { 95 throw new RuntimeException(e); 96 } 97 } 98 99 /** 100 * 激活功能 101 * @param code 102 * @throws UserException 103 */ 104 public void activate(String code) throws UserException { 105 /* 106 * 1. 通过激活码查询用户 107 * 2. 如果User为null,说明是无效激活码,抛出异常,给出异常信息(无效激活码) 108 * 3. 查看用户状态是否为true,如果为true,抛出异常,给出异常信息(请不要二次激活) 109 * 4. 修改用户状态为true 110 */ 111 try { 112 User user = userDao.findByCode(code); 113 if(user == null) throw new UserException("无效的激活码!"); 114 if(user.isStatus()) throw new UserException("您已经激活过了,不要二次激活!"); 115 userDao.updateStatus(user.getUid(), true);//修改状态 116 } catch (SQLException e) { 117 throw new RuntimeException(e); 118 } 119 } 120 }
(3)dao层
a).UserDao.java
1 package com.tony.goods.user.dao; 2 3 import java.sql.SQLException; 4 5 import org.apache.commons.dbutils.QueryRunner; 6 import org.apache.commons.dbutils.handlers.BeanHandler; 7 import org.apache.commons.dbutils.handlers.ScalarHandler; 8 9 import cn.itcast.jdbc.TxQueryRunner; 10 11 import com.tony.goods.user.domain.User; 12 13 /** 14 * 用户模块持久层 15 * @author T 16 * 17 */ 18 public class UserDao { 19 private QueryRunner qr = new TxQueryRunner(); 20 21 /** 22 * 通过激活码查询用户 23 * @param code 24 * @return 25 * @throws SQLException 26 */ 27 public User findByCode(String code) throws SQLException { 28 String sql = "select * from t_user where activationCode=?"; 29 return qr.query(sql, new BeanHandler<User>(User.class), code); 30 } 31 32 /** 33 * 修改用户状态 34 * @param uid 35 * @param b 36 * @throws SQLException 37 */ 38 public void updateStatus(String uid, boolean status) throws SQLException { 39 String sql = "update t_user set status=? where uid=?"; 40 qr.update(sql, status, uid); 41 } 42 43 /** 44 * 校验用户名是否注册 45 * @param loginname 46 * @return 47 * @throws SQLException 48 */ 49 public boolean validateLoginname(String loginname) throws SQLException { 50 String sql = "select count(1) from t_user where loginname=?"; 51 Number number = (Number) qr.query(sql, new ScalarHandler(), loginname); 52 return number.intValue() == 0; 53 } 54 55 /** 56 * 校验Email是否注册 57 * @param email 58 * @return 59 * @throws SQLException 60 */ 61 public boolean validateEmail(String email) throws SQLException { 62 String sql = "select count(1) from t_user where email=?"; 63 Number number = (Number) qr.query(sql, new ScalarHandler(), email); 64 return number.intValue() == 0; 65 } 66 67 /** 68 * 添加用户 69 * @param user 70 * @throws SQLException 71 */ 72 public void add(User user) throws SQLException { 73 String sql = "insert into t_user values(?,?,?,?,?,?)"; 74 Object[] params = {user.getUid(), user.getLoginname(), user.getLoginpass(), user.getEmail(), user.isStatus(), user.getActivationCode()}; 75 qr.update(sql, params); 76 } 77 78 79 }
(4)view层
a)regist.jsp
3.配置文件
(1)web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> 3 4 <!-- 统一编码处理 --> 5 <filter> 6 <filter-name>EncodingFilter</filter-name> 7 <filter-class>cn.itcast.filter.EncodingFilter</filter-class> 8 </filter> 9 <filter-mapping> 10 <filter-name>EncodingFilter</filter-name> 11 <url-pattern>/*</url-pattern> 12 </filter-mapping> 13 14 <!-- 生成验证码 --> 15 <servlet> 16 <servlet-name>VerifyCodeServlet</servlet-name> 17 <servlet-class>cn.itcast.vcode.servlet.VerifyCodeServlet</servlet-class> 18 </servlet> 19 <servlet-mapping> 20 <servlet-name>VerifyCodeServlet</servlet-name> 21 <url-pattern>/VerifyCodeServlet</url-pattern> 22 </servlet-mapping> 23 24 <!-- 用户模块的注册校验(eg:用户名是 否已注册) --> 25 <servlet> 26 <servlet-name>UserServlet</servlet-name> 27 <servlet-class>com.tony.goods.user.web.servlet.UserServlet</servlet-class> 28 </servlet> 29 <servlet-mapping> 30 <servlet-name>UserServlet</servlet-name> 31 <url-pattern>/UserServlet</url-pattern> 32 </servlet-mapping> 33 </web-app>
(2)email.properties
1 subject=\u6765\u81EAI\u65B0\u6708\u4E66\u5E97\u7684\u6FC0\u6D3B\u90AE\u4EF6 2 content=\u606D\u559C\uFF0C\u60A8\u5DF2\u6CE8\u518C\u6210\u529F\uFF0C\u8BF7\u70B9\u51FB<a href\="http\://localhost\:8080/goods/UserServlet?method\=activation&activationCode\={0}">\u8FD9\u91CC</a>\u5B8C\u6210\u6FC0\u6D3B\u3002 3 from=aaa@163.com 4 host=smtp.163.com 5 username=bbb 6 password=xxx