javascript
javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
一、Servlet+JSP+JavaBean開發(fā)模式(MVC)介紹
Servlet+JSP+JavaBean模式(MVC)適合開發(fā)復(fù)雜的web應(yīng)用,在這種模式下,servlet負(fù)責(zé)處理用戶請(qǐng)求,jsp負(fù)責(zé)數(shù)據(jù)顯示,javabean負(fù)責(zé)封裝數(shù)據(jù)。 Servlet+JSP+JavaBean模式程序各個(gè)模塊之間層次清晰,web開發(fā)推薦采用此種模式。
這里以一個(gè)最常用的用戶登錄注冊(cè)程序來講解Servlet+JSP+JavaBean開發(fā)模式,通過這個(gè)用戶登錄注冊(cè)程序綜合案例,把之前的學(xué)過的XML、Xpath、Servlet、jsp的知識(shí)點(diǎn)都串聯(lián)起來。
二、創(chuàng)建MVC架構(gòu)的Web項(xiàng)目
在MyEclipse中新創(chuàng)建一個(gè)webmvcframework項(xiàng)目,導(dǎo)入項(xiàng)目所需要的開發(fā)包(jar包),創(chuàng)建項(xiàng)目所需要的包,在java開發(fā)中,架構(gòu)的層次是以包的形式體現(xiàn)出來的
| 項(xiàng)目所需要的開發(fā)包(jar包) | ||
| 序號(hào) | 開發(fā)包名稱 | 描述 |
| 1 | dom4j-1.6.1.jar | dom4j用于操作XML文件 |
| 2 | jaxen-1.1-beta-6.jar | 用于解析XPath表達(dá)式 |
| 3 | commons-beanutils-1.8.0.jar | 工具類,用于處理bean對(duì)象 |
| 4 | commons-logging.jar | commons-beanutils-1.8.0.jar的依賴jar包 |
| 5 | jstl.jar | jstl標(biāo)簽庫(kù)和EL表達(dá)式依賴包 |
| 6 | standard.jar | jstl標(biāo)簽庫(kù)和EL表達(dá)式依賴包 |
| 項(xiàng)目所需要的包 | |||
| 序號(hào) | 包名 | 描述 | 所屬層次 |
| 1 | me.gacl.domain | 存放系統(tǒng)的JavaBean類(只包含簡(jiǎn)單的屬性以及屬性對(duì)應(yīng)的get和set方法,不包含具體的業(yè)務(wù)處理方法),提供給【數(shù)據(jù)訪問層】、【業(yè)務(wù)處理層】、【W(wǎng)eb層】來使用 | ?domain(域模型)層 |
| 2 | me.gacl.dao | 存放訪問數(shù)據(jù)庫(kù)的操作接口類 | 數(shù)據(jù)訪問層 |
| 3 | me.gacl.dao.impl | 存放訪問數(shù)據(jù)庫(kù)的操作接口的實(shí)現(xiàn)類 | |
| 4 | me.gacl.service | 存放處理系統(tǒng)業(yè)務(wù)接口類 | 業(yè)務(wù)處理層 |
| 5 | me.gacl.service.impl | 存放處理系統(tǒng)業(yè)務(wù)接口的實(shí)現(xiàn)類 | |
| 6 | me.gacl.web.controller | 存放作為系統(tǒng)控制器的Servlet | Web層(表現(xiàn)層) |
| 7 | me.gacl.web.UI | 存放為用戶提供用戶界面的servlet(UI指的是user interface) | |
| 8 | me.gacl.web.filter | 存放系統(tǒng)的用到的過濾器(Filter) | |
| 9 | me.gacl.web.listener | 存放系統(tǒng)的用到的監(jiān)聽器(Listener) | |
| 10 | me.gacl.util | 存放系統(tǒng)的通用工具類,提供給【數(shù)據(jù)訪問層】、【業(yè)務(wù)處理層】、【W(wǎng)eb層】來使用 | ? |
| 11 | junit.test | 存放系統(tǒng)的測(cè)試類 | ? |
一個(gè)良好的JavaWeb項(xiàng)目架構(gòu)應(yīng)該具有以上的11個(gè)包,這樣顯得層次分明,各個(gè)層之間的職責(zé)也很清晰明了,搭建JavaWeb項(xiàng)目架構(gòu)時(shí),就按照上面的1~11的序號(hào)順序創(chuàng)建包:domain→dao→dao.impl→service→service.impl→web.controller→web.UI→web.filter→web.listener→util→junit.test,包的層次創(chuàng)建好了,項(xiàng)目的架構(gòu)也就定下來了,當(dāng)然,在實(shí)際的項(xiàng)目開發(fā)中,也不一定是完完全全按照上面說的來創(chuàng)建包的層次結(jié)構(gòu),而是根據(jù)項(xiàng)目的實(shí)際情況,可能還需要?jiǎng)?chuàng)建其他的包,這個(gè)得根據(jù)項(xiàng)目的需要來定了
在src目錄(類目錄)下面,創(chuàng)建用于保存用戶數(shù)據(jù)的xml文件(DB.xml)
在WEB-INF目錄下創(chuàng)建一個(gè)pages目錄,pages目錄存放系統(tǒng)的一些受保護(hù)(不允許用戶直接通過URL地址訪問)的jsp頁(yè)面,用戶要想訪問這些受保護(hù)的jsp頁(yè)面,那么只能通過me.gacl.web.UI這個(gè)包里面的Servlet
創(chuàng)建好的項(xiàng)目如下圖(圖-1)所示:
圖-1
三、分層架構(gòu)的代碼編寫
分層架構(gòu)的代碼也是按照【域模型層(domain)】→【數(shù)據(jù)訪問層(dao、dao.impl)】→【業(yè)務(wù)處理層(service、service.impl)】→【表現(xiàn)層(web.controller、web.UI、web.filter、web.listener)】→【工具類(util)】→【測(cè)試類(junit.test)】的順序進(jìn)行編寫的。
3.1、開發(fā)domain層
在me.gacl.domain包下創(chuàng)建一個(gè)User類
User類具體代碼如下:
1 package me.gacl.domain;2 3 import java.io.Serializable;4 import java.util.Date;5 /**6 * @author gacl7 * 用戶實(shí)體類8 */9 public class User implements Serializable { 10 11 private static final long serialVersionUID = -4313782718477229465L; 12 13 // 用戶ID 14 private String id; 15 // 用戶名 16 private String userName; 17 // 用戶密碼 18 private String userPwd; 19 // 用戶郵箱 20 private String email; 21 // 用戶生日 22 private Date birthday; 23 24 public String getId() { 25 return id; 26 } 27 28 public void setId(String id) { 29 this.id = id; 30 } 31 32 public String getUserName() { 33 return userName; 34 } 35 36 public void setUserName(String userName) { 37 this.userName = userName; 38 } 39 40 public String getUserPwd() { 41 return userPwd; 42 } 43 44 public void setUserPwd(String userPwd) { 45 this.userPwd = userPwd; 46 } 47 48 public String getEmail() { 49 return email; 50 } 51 52 public void setEmail(String email) { 53 this.email = email; 54 } 55 56 public Date getBirthday() { 57 return birthday; 58 } 59 60 public void setBirthday(Date birthday) { 61 this.birthday = birthday; 62 } 63 }3.2、開發(fā)數(shù)據(jù)訪問層(dao、dao.impl)
在me.gacl.dao包下創(chuàng)建一個(gè)IUserDao接口類,對(duì)于開發(fā)接口類,我習(xí)慣以字母I作類的前綴,這樣一眼就看出當(dāng)前這個(gè)類是一個(gè)接口,這也算是一種良好的開發(fā)習(xí)慣吧,通過看類名就可以方便區(qū)分出是接口還是具體的實(shí)現(xiàn)類。
IUserDao接口的具體代碼如下:
1 package me.gacl.dao;2 3 import me.gacl.domain.User;4 5 public interface IUserDao {6 7 /**8 * 根據(jù)用戶名和密碼來查找用戶9 * @param userName 10 * @param userPwd 11 * @return 查到到的用戶 12 */ 13 User find(String userName, String userPwd); 14 15 /** 16 * 添加用戶 17 * @param user 18 */ 19 void add(User user); 20 21 /**根據(jù)用戶名來查找用戶 22 * @param userName 23 * @return 查到到的用戶 24 */ 25 User find(String userName); 26 }? 對(duì)于接口中的方法定義,這個(gè)只能是根據(jù)具體的業(yè)務(wù)來分析需要定義哪些方法了,但是無論是多么復(fù)雜的業(yè)務(wù),都離不開基本的CRUD(增刪改查)操作,Dao層是直接和數(shù)據(jù)庫(kù)交互的,所以Dao層的接口一般都會(huì)有增刪改查這四種操作的相關(guān)方法。
在me.gacl.dao.impl包下創(chuàng)建一個(gè)UserDaoImpl類
UserDaoImpl類是IUserDao接口的具體實(shí)現(xiàn)類,對(duì)于接口的實(shí)現(xiàn)類命名方式,我習(xí)慣以"接口名(去除前綴I)+impl"形式或者"接口名+impl"形式來命名:IUserDao(接口)→UserDaoImpl(實(shí)現(xiàn)類)或者IUserDao(接口)→IUserDaoImpl(實(shí)現(xiàn)類),這也算是一些個(gè)人的編程習(xí)慣吧,平時(shí)看到的代碼大多數(shù)都是以這兩種形式中的一種來來命名接口的具體實(shí)現(xiàn)類的,反正就是要能夠一眼看出接口對(duì)應(yīng)的實(shí)現(xiàn)類是哪一個(gè)就可以了。
UserDaoImpl類的具體代碼如下:
1 package me.gacl.dao.impl;2 3 import java.text.SimpleDateFormat;4 import org.dom4j.Document;5 import org.dom4j.Element;6 import me.gacl.dao.IUserDao;7 import me.gacl.domain.User;8 import me.gacl.util.XmlUtils;9 10 /** 11 * IUserDao接口的實(shí)現(xiàn)類 12 * @author gacl 13 */ 14 public class UserDaoImpl implements IUserDao { 15 16 @Override 17 public User find(String userName, String userPwd) { 18 try{ 19 Document document = XmlUtils.getDocument(); 20 //使用XPath表達(dá)式來操作XML節(jié)點(diǎn) 21 Element e = (Element) document.selectSingleNode("//user[@userName='"+userName+"' and @userPwd='"+userPwd+"']"); 22 if(e==null){ 23 return null; 24 } 25 User user = new User(); 26 user.setId(e.attributeValue("id")); 27 user.setEmail(e.attributeValue("email")); 28 user.setUserPwd(e.attributeValue("userPwd")); 29 user.setUserName(e.attributeValue("userName")); 30 String birth = e.attributeValue("birthday"); 31 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 32 user.setBirthday(sdf.parse(birth)); 33 34 return user; 35 36 }catch (Exception e) { 37 throw new RuntimeException(e); 38 } 39 } 40 41 @SuppressWarnings("deprecation") 42 @Override 43 public void add(User user) { 44 try{ 45 Document document = XmlUtils.getDocument(); 46 Element root = document.getRootElement(); 47 Element user_node = root.addElement("user"); //創(chuàng)建user結(jié)點(diǎn),并掛到root 48 user_node.setAttributeValue("id", user.getId()); 49 user_node.setAttributeValue("userName", user.getUserName()); 50 user_node.setAttributeValue("userPwd", user.getUserPwd()); 51 user_node.setAttributeValue("email", user.getEmail()); 52 53 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); 54 user_node.setAttributeValue("birthday", sdf.format(user.getBirthday())); 55 56 XmlUtils.write2Xml(document); 57 58 }catch (Exception e) { 59 throw new RuntimeException(e); 60 } 61 } 62 63 @Override 64 public User find(String userName) { 65 try{ 66 Document document = XmlUtils.getDocument(); 67 Element e = (Element) document.selectSingleNode("//user[@userName='"+userName+"']"); 68 if(e==null){ 69 return null; 70 } 71 User user = new User(); 72 user.setId(e.attributeValue("id")); 73 user.setEmail(e.attributeValue("email")); 74 user.setUserPwd(e.attributeValue("userPwd")); 75 user.setUserName(e.attributeValue("userName")); 76 String birth = e.attributeValue("birthday"); 77 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 78 user.setBirthday(sdf.parse(birth)); 79 80 return user; 81 82 }catch (Exception e) { 83 throw new RuntimeException(e); 84 } 85 } 86 87 }3.3、開發(fā)service層(service層對(duì)web層提供所有的業(yè)務(wù)服務(wù))
? 在me.gacl.service包中創(chuàng)建IUserService接口類
IUserService接口的具體代碼如下:
1 package me.gacl.service;2 3 import me.gacl.domain.User;4 import me.gacl.exception.UserExistException;5 6 public interface IUserService {7 8 /**9 * 提供注冊(cè)服務(wù) 10 * @param user 11 * @throws UserExistException 12 */ 13 void registerUser(User user) throws UserExistException; 14 15 /** 16 * 提供登錄服務(wù) 17 * @param userName 18 * @param userPwd 19 * @return 20 */ 21 User loginUser(String userName, String userPwd); 22 }在me.gacl.service.impl包中創(chuàng)建UserServiceImpl類
UserServiceImpl類為IUserService接口的具體實(shí)現(xiàn)類,具體代碼如下:
1 package me.gacl.service.impl;2 3 import me.gacl.dao.IUserDao;4 import me.gacl.dao.impl.UserDaoImpl;5 import me.gacl.domain.User;6 import me.gacl.exception.UserExistException;7 import me.gacl.service.IUserService;8 9 public class UserServiceImpl implements IUserService { 10 11 private IUserDao userDao = new UserDaoImpl(); 12 13 @Override 14 public void registerUser(User user) throws UserExistException { 15 if (userDao.find(user.getUserName())!=null) { 16 //checked exception 17 //unchecked exception 18 //這里拋編譯時(shí)異常的原因:是我想上一層程序處理這個(gè)異常,以給用戶一個(gè)友好提示 19 throw new UserExistException("注冊(cè)的用戶名已存在!!!"); 20 } 21 userDao.add(user); 22 } 23 24 @Override 25 public User loginUser(String userName, String userPwd) { 26 return userDao.find(userName, userPwd); 27 } 28 29 }3.4、開發(fā)web層
3.4.1、 開發(fā)注冊(cè)功能
1、在me.gacl.web.UI包下寫一個(gè)RegisterUIServlet為用戶提供注冊(cè)界面
RegisterUIServlet收到用戶請(qǐng)求后,就跳到register.jsp
RegisterUIServlet的代碼如下:
1 package me.gacl.web.UI;2 3 import java.io.IOException;4 import javax.servlet.ServletException;5 import javax.servlet.http.HttpServlet;6 import javax.servlet.http.HttpServletRequest;7 import javax.servlet.http.HttpServletResponse;8 /**9 * @author gacl 10 * 為用戶提供注冊(cè)的用戶界面的Servlet 11 * RegisterUIServlet負(fù)責(zé)為用戶輸出注冊(cè)界面 12 * 當(dāng)用戶訪問RegisterUIServlet時(shí),就跳轉(zhuǎn)到WEB-INF/pages目錄下的register.jsp頁(yè)面 13 */ 14 public class RegisterUIServlet extends HttpServlet { 15 16 public void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response); 19 } 20 21 public void doPost(HttpServletRequest request, HttpServletResponse response) 22 throws ServletException, IOException { 23 doGet(request, response); 24 } 25 26 }??? ???? 2、在/WEB-INF/pages/目錄下編寫用戶注冊(cè)的jsp頁(yè)面register.jsp
凡是位于WEB-INF目錄下的jsp頁(yè)面是無法直接通過URL地址直接訪問的,
在開發(fā)中如果項(xiàng)目中有一些敏感web資源不想被外界直接訪問,那么可以考慮將這些敏感的web資源放到WEB-INF目錄下,這樣就可以禁止外界直接通過URL來訪問了。
register.jsp頁(yè)面的代碼如下:
1 <%@ page language="java" pageEncoding="UTF-8"%>2 <!DOCTYPE HTML>3 <html>4 <head>5 <title>用戶注冊(cè)</title>6 </head>7 8 <body style="text-align: center;">9 <form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post"> 10 <table width="60%" border="1"> 11 <tr> 12 <td>用戶名</td> 13 <td> 14 15 <input type="text" name="userName"> 16 </td> 17 </tr> 18 <tr> 19 <td>密碼</td> 20 <td> 21 <input type="password" name="userPwd"> 22 </td> 23 </tr> 24 <tr> 25 <td>確認(rèn)密碼</td> 26 <td> 27 <input type="password" name="confirmPwd"> 28 </td> 29 </tr> 30 <tr> 31 <td>郵箱</td> 32 <td> 33 <input type="text" name="email"> 34 </td> 35 </tr> 36 <tr> 37 <td>生日</td> 38 <td> 39 <input type="text" name="birthday"> 40 </td> 41 </tr> 42 <tr> 43 <td> 44 <input type="reset" value="清空"> 45 </td> 46 <td> 47 <input type="submit" value="注冊(cè)"> 48 </td> 49 </tr> 50 </table> 51 </form> 52 </body> 53 </html> register.jsp中的<form?action="${pageContext.request.contextPath}/servlet/RegisterServlet"?method="post">指明表單提交后,交給RegisterServlet進(jìn)行處理
???? 3、在me.gacl.web.controller包下編寫用于處理用戶注冊(cè)的RegisterServlet
RegisterServlet擔(dān)任著以下幾個(gè)職責(zé):
??? ??? ??? ? 1、接收客戶端提交到服務(wù)端的表單數(shù)據(jù)。
2、校驗(yàn)表單數(shù)據(jù)的合法性,如果校驗(yàn)失敗跳回到register.jsp,并回顯錯(cuò)誤信息。
3、如果校驗(yàn)通過,調(diào)用service層向數(shù)據(jù)庫(kù)中注冊(cè)用戶。
為了方便RegisterServlet接收表單數(shù)據(jù)和校驗(yàn)表單數(shù)據(jù),在此我設(shè)計(jì)一個(gè)用于校驗(yàn)注冊(cè)表單數(shù)據(jù)RegisterFormbean,再寫WebUtils工具類,封裝客戶端提交的表單數(shù)據(jù)到formbean中。
在me.gacl.web.formbean包下創(chuàng)建一個(gè)用于校驗(yàn)注冊(cè)表單數(shù)據(jù)RegisterFormbean
RegisterFormbean代碼如下:
1 package me.gacl.web.formbean;2 3 import java.util.HashMap;4 import java.util.Map;5 6 import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;7 8 /**9 * 封裝的用戶注冊(cè)表單bean,用來接收register.jsp中的表單輸入項(xiàng)的值10 * RegisterFormBean中的屬性與register.jsp中的表單輸入項(xiàng)的name一一對(duì)應(yīng)11 * RegisterFormBean的職責(zé)除了負(fù)責(zé)接收register.jsp中的表單輸入項(xiàng)的值之外還擔(dān)任著校驗(yàn)表單輸入項(xiàng)的值的合法性12 * @author gacl13 *14 */15 public class RegisterFormBean {16 17 //RegisterFormBean中的屬性與register.jsp中的表單輸入項(xiàng)的name一一對(duì)應(yīng)18 //<input type="text" name="userName"/>19 private String userName;20 //<input type="password" name="userPwd"/>21 private String userPwd;22 //<input type="password" name="confirmPwd"/>23 private String confirmPwd;24 //<input type="text" name="email"/>25 private String email;26 //<input type="text" name="birthday"/>27 private String birthday;28 29 30 /**31 * 存儲(chǔ)校驗(yàn)不通過時(shí)給用戶的錯(cuò)誤提示信息32 */33 private Map<String, String> errors = new HashMap<String, String>();34 35 public Map<String, String> getErrors() {36 return errors;37 }38 39 public void setErrors(Map<String, String> errors) {40 this.errors = errors;41 }42 43 /*44 * validate方法負(fù)責(zé)校驗(yàn)表單輸入項(xiàng)45 * 表單輸入項(xiàng)校驗(yàn)規(guī)則:46 * private String userName; 用戶名不能為空,并且要是3-8的字母 abcdABcd 47 * private String userPwd; 密碼不能為空,并且要是3-8的數(shù)字48 * private String confirmPwd; 兩次密碼要一致49 * private String email; 可以為空,不為空要是一個(gè)合法的郵箱 50 * private String birthday; 可以為空,不為空時(shí),要是一個(gè)合法的日期51 */52 public boolean validate() {53 54 boolean isOk = true;55 56 if (this.userName == null || this.userName.trim().equals("")) {57 isOk = false;58 errors.put("userName", "用戶名不能為空!!");59 } else {60 if (!this.userName.matches("[a-zA-Z]{3,8}")) {61 isOk = false;62 errors.put("userName", "用戶名必須是3-8位的字母!!");63 }64 }65 66 if (this.userPwd == null || this.userPwd.trim().equals("")) {67 isOk = false;68 errors.put("userPwd", "密碼不能為空!!");69 } else {70 if (!this.userPwd.matches("\\d{3,8}")) {71 isOk = false;72 errors.put("userPwd", "密碼必須是3-8位的數(shù)字!!");73 }74 }75 76 // private String password2; 兩次密碼要一致77 if (this.confirmPwd != null) {78 if (!this.confirmPwd.equals(this.userPwd)) {79 isOk = false;80 errors.put("confirmPwd", "兩次密碼不一致!!");81 }82 }83 84 // private String email; 可以為空,不為空要是一個(gè)合法的郵箱85 if (this.email != null && !this.email.trim().equals("")) {86 if (!this.email.matches("\\w+@\\w+(\\.\\w+)+")) {87 isOk = false;88 errors.put("email", "郵箱不是一個(gè)合法郵箱!!");89 }90 }91 92 // private String birthday; 可以為空,不為空時(shí),要是一個(gè)合法的日期93 if (this.birthday != null && !this.birthday.trim().equals("")) {94 try {95 DateLocaleConverter conver = new DateLocaleConverter();96 conver.convert(this.birthday);97 } catch (Exception e) {98 isOk = false;99 errors.put("birthday", "生日必須要是一個(gè)日期!!"); 100 } 101 } 102 103 return isOk; 104 } 105 106 public String getUserName() { 107 return userName; 108 } 109 110 public void setUserName(String userName) { 111 this.userName = userName; 112 } 113 114 public String getUserPwd() { 115 return userPwd; 116 } 117 118 public void setUserPwd(String userPwd) { 119 this.userPwd = userPwd; 120 } 121 122 public String getConfirmPwd() { 123 return confirmPwd; 124 } 125 126 public void setConfirmPwd(String confirmPwd) { 127 this.confirmPwd = confirmPwd; 128 } 129 130 public String getEmail() { 131 return email; 132 } 133 134 public void setEmail(String email) { 135 this.email = email; 136 } 137 138 public String getBirthday() { 139 return birthday; 140 } 141 142 public void setBirthday(String birthday) { 143 this.birthday = birthday; 144 } 145 }在me.gacl.util包下創(chuàng)建一個(gè)WebUtils工具類,該工具類的功能就是封裝客戶端提交的表單數(shù)據(jù)到formbean中
1 package me.gacl.util;2 3 import java.util.Enumeration;4 import java.util.UUID;5 import javax.servlet.http.HttpServletRequest;6 import org.apache.commons.beanutils.BeanUtils;7 8 /**9 * @author gacl 10 * 把request對(duì)象中的請(qǐng)求參數(shù)封裝到bean中 11 */ 12 public class WebUtils { 13 14 /** 15 * 將request對(duì)象轉(zhuǎn)換成T對(duì)象 16 * @param request 17 * @param clazz 18 * @return 19 */ 20 public static <T> T request2Bean(HttpServletRequest request,Class<T> clazz){ 21 try{ 22 T bean = clazz.newInstance(); 23 Enumeration<String> e = request.getParameterNames(); 24 while(e.hasMoreElements()){ 25 String name = (String) e.nextElement(); 26 String value = request.getParameter(name); 27 BeanUtils.setProperty(bean, name, value); 28 } 29 return bean; 30 }catch (Exception e) { 31 throw new RuntimeException(e); 32 } 33 } 34 35 /** 36 * 生成UUID 37 * @return 38 */ 39 public static String makeId(){ 40 return UUID.randomUUID().toString(); 41 } 42 43 }
最后看一下負(fù)責(zé)處理用戶注冊(cè)的RegisterServlet完整代碼:
1 package me.gacl.web.controller;2 3 import java.io.IOException;4 import java.util.Date;5 import javax.servlet.ServletException;6 import javax.servlet.http.HttpServlet;7 import javax.servlet.http.HttpServletRequest;8 import javax.servlet.http.HttpServletResponse;9 import org.apache.commons.beanutils.BeanUtils; 10 import org.apache.commons.beanutils.ConvertUtils; 11 import org.apache.commons.beanutils.locale.converters.DateLocaleConverter; 12 import me.gacl.domain.User; 13 import me.gacl.exception.UserExistException; 14 import me.gacl.service.IUserService; 15 import me.gacl.service.impl.UserServiceImpl; 16 import me.gacl.util.WebUtils; 17 import me.gacl.web.formbean.RegisterFormBean; 18 /** 19 * 處理用戶注冊(cè)的Servlet 20 * @author gacl 21 * 22 */ 23 public class RegisterServlet extends HttpServlet { 24 25 public void doGet(HttpServletRequest request, HttpServletResponse response) 26 throws ServletException, IOException { 27 //將客戶端提交的表單數(shù)據(jù)封裝到RegisterFormBean對(duì)象中 28 RegisterFormBean formbean = WebUtils.request2Bean(request,RegisterFormBean.class); 29 //校驗(yàn)用戶注冊(cè)填寫的表單數(shù)據(jù) 30 if (formbean.validate() == false) {//如果校驗(yàn)失敗 31 //將封裝了用戶填寫的表單數(shù)據(jù)的formbean對(duì)象發(fā)送回register.jsp頁(yè)面的form表單中進(jìn)行顯示 32 request.setAttribute("formbean", formbean); 33 //校驗(yàn)失敗就說明是用戶填寫的表單數(shù)據(jù)有問題,那么就跳轉(zhuǎn)回register.jsp 34 request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response); 35 return; 36 } 37 38 User user = new User(); 39 try { 40 // 注冊(cè)字符串到日期的轉(zhuǎn)換器 41 ConvertUtils.register(new DateLocaleConverter(), Date.class); 42 BeanUtils.copyProperties(user, formbean);//把表單的數(shù)據(jù)填充到j(luò)avabean中 43 user.setId(WebUtils.makeId());//設(shè)置用戶的Id屬性 44 IUserService service = new UserServiceImpl(); 45 //調(diào)用service層提供的注冊(cè)用戶服務(wù)實(shí)現(xiàn)用戶注冊(cè) 46 service.registerUser(user); 47 String message = String.format( 48 "注冊(cè)成功!!3秒后為您自動(dòng)跳到登錄頁(yè)面!!<meta http-equiv='refresh' content='3;url=%s'/>", 49 request.getContextPath()+"/servlet/LoginUIServlet"); 50 request.setAttribute("message",message); 51 request.getRequestDispatcher("/message.jsp").forward(request,response); 52 53 } catch (UserExistException e) { 54 formbean.getErrors().put("userName", "注冊(cè)用戶已存在!!"); 55 request.setAttribute("formbean", formbean); 56 request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response); 57 } catch (Exception e) { 58 e.printStackTrace(); // 在后臺(tái)記錄異常 59 request.setAttribute("message", "對(duì)不起,注冊(cè)失敗!!"); 60 request.getRequestDispatcher("/message.jsp").forward(request,response); 61 } 62 } 63 64 public void doPost(HttpServletRequest request, HttpServletResponse response) 65 throws ServletException, IOException { 66 doGet(request, response); 67 } 68 69 }? 用戶注冊(cè)時(shí)如果填寫的表單數(shù)據(jù)校驗(yàn)不通過,那么服務(wù)器端就將一個(gè)存儲(chǔ)了錯(cuò)誤提示消息和表單數(shù)據(jù)的formbean對(duì)象存儲(chǔ)到request對(duì)象中,然后發(fā)送回register.jsp頁(yè)面,因此我們需要在register.jsp頁(yè)面中取出request對(duì)象中formbean對(duì)象,然后將用戶填寫的表單數(shù)據(jù)重新回顯到對(duì)應(yīng)的表單項(xiàng)上面,將出錯(cuò)時(shí)的提示消息也顯示到form表單上面,讓用戶知道是哪些數(shù)據(jù)填寫不合法!
修改register.jsp頁(yè)面,代碼如下:
1 <%@ page language="java" pageEncoding="UTF-8"%>2 <!DOCTYPE HTML>3 <html>4 <head>5 <title>用戶注冊(cè)</title>6 </head>7 8 <body style="text-align: center;">9 <form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post"> 10 <table width="60%" border="1"> 11 <tr> 12 <td>用戶名</td> 13 <td> 14 <%--使用EL表達(dá)式${}提取存儲(chǔ)在request對(duì)象中的formbean對(duì)象中封裝的表單數(shù)據(jù)(formbean.userName)以及錯(cuò)誤提示消息(formbean.errors.userName)--%> 15 <input type="text" name="userName" value="${formbean.userName}">${formbean.errors.userName} 16 </td> 17 </tr> 18 <tr> 19 <td>密碼</td> 20 <td> 21 <input type="password" name="userPwd" value="${formbean.userPwd}">${formbean.errors.userPwd} 22 </td> 23 </tr> 24 <tr> 25 <td>確認(rèn)密碼</td> 26 <td> 27 <input type="password" name="confirmPwd" value="${formbean.confirmPwd}">${formbean.errors.confirmPwd} 28 </td> 29 </tr> 30 <tr> 31 <td>郵箱</td> 32 <td> 33 <input type="text" name="email" value="${formbean.email}">${formbean.errors.email} 34 </td> 35 </tr> 36 <tr> 37 <td>生日</td> 38 <td> 39 <input type="text" name="birthday" value="${formbean.birthday}">${formbean.errors.birthday} 40 </td> 41 </tr> 42 <tr> 43 <td> 44 <input type="reset" value="清空"> 45 </td> 46 <td> 47 <input type="submit" value="注冊(cè)"> 48 </td> 49 </tr> 50 </table> 51 </form> 52 </body> 53 </html>? 到此,用戶注冊(cè)功能就算是開發(fā)完成了!
下面測(cè)試一下開發(fā)好的用戶注冊(cè)功能:
輸入U(xiǎn)RL地址:http://localhost:8080/webmvcframework/servlet/RegisterUIServlet訪問register.jsp頁(yè)面,運(yùn)行效果如下:
如果輸入的表單項(xiàng)不符合校驗(yàn)規(guī)則,那么是無法進(jìn)行注冊(cè)的,運(yùn)行效果如下:
3.4.2、 開發(fā)登錄功能
1、在me.gacl.web.UI包下寫一個(gè)LoginUIServlet為用戶提供登錄界面
LoginUIServlet收到用戶請(qǐng)求后,就跳到login.jsp
LoginUIServlet的代碼如下:
1 package me.gacl.web.UI;2 3 import java.io.IOException;4 5 import javax.servlet.ServletException;6 import javax.servlet.http.HttpServlet;7 import javax.servlet.http.HttpServletRequest;8 import javax.servlet.http.HttpServletResponse;9 10 /** 11 * @author gacl 12 * LoginUIServlet負(fù)責(zé)為用戶輸出登陸界面 13 * 當(dāng)用戶訪問LoginUIServlet時(shí),就跳轉(zhuǎn)到WEB-INF/pages目錄下的login.jsp頁(yè)面 14 */ 15 public class LoginUIServlet extends HttpServlet { 16 17 public void doGet(HttpServletRequest request, HttpServletResponse response) 18 throws ServletException, IOException { 19 20 request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response); 21 } 22 23 public void doPost(HttpServletRequest request, HttpServletResponse response) 24 throws ServletException, IOException { 25 doGet(request, response); 26 } 27 28 }2、在/WEB-INF/pages/目錄下編寫用戶登錄的jsp頁(yè)面login.jsp
login.jsp頁(yè)面的代碼如下:
1 <%@ page language="java" pageEncoding="UTF-8"%>2 <!DOCTYPE HTML>3 <html>4 <head>5 <title>用戶登陸</title>6 </head>7 8 <body>9 <form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post"> 10 用戶名:<input type="text" name="username"><br/> 11 密碼:<input type="password" name="password"><br/> 12 <input type="submit" value="登陸"> 13 </form> 14 </body> 15 </html> login.jsp中的<form?action="${pageContext.request.contextPath}/servlet/LoginServlet"?method="post">指明表單提交后,交給LoginServlet進(jìn)行處理。
???? 3、在me.gacl.web.controller包下編寫用于處理用戶登錄的LoginServlet
LoginServlet的代碼如下:
1 package me.gacl.web.controller;2 3 import java.io.IOException;4 5 import javax.servlet.ServletException;6 import javax.servlet.http.HttpServlet;7 import javax.servlet.http.HttpServletRequest;8 import javax.servlet.http.HttpServletResponse;9 10 import me.gacl.domain.User; 11 import me.gacl.service.IUserService; 12 import me.gacl.service.impl.UserServiceImpl; 13 14 /** 15 * 處理用戶登錄的servlet 16 * @author gacl 17 * 18 */ 19 public class LoginServlet extends HttpServlet { 20 21 public void doGet(HttpServletRequest request, HttpServletResponse response) 22 throws ServletException, IOException { 23 24 //獲取用戶填寫的登錄用戶名 25 String username = request.getParameter("username"); 26 //獲取用戶填寫的登錄密碼 27 String password = request.getParameter("password"); 28 29 IUserService service = new UserServiceImpl(); 30 //用戶登錄 31 User user = service.loginUser(username, password); 32 if(user==null){ 33 String message = String.format( 34 "對(duì)不起,用戶名或密碼有誤!!請(qǐng)重新登錄!2秒后為您自動(dòng)跳到登錄頁(yè)面!!<meta http-equiv='refresh' content='2;url=%s'", 35 request.getContextPath()+"/servlet/LoginUIServlet"); 36 request.setAttribute("message",message); 37 request.getRequestDispatcher("/message.jsp").forward(request, response); 38 return; 39 } 40 //登錄成功后,就將用戶存儲(chǔ)到session中 41 request.getSession().setAttribute("user", user); 42 String message = String.format( 43 "恭喜:%s,登陸成功!本頁(yè)將在3秒后跳到首頁(yè)!!<meta http-equiv='refresh' content='3;url=%s'", 44 user.getUserName(), 45 request.getContextPath()+"/index.jsp"); 46 request.setAttribute("message",message); 47 request.getRequestDispatcher("/message.jsp").forward(request, response); 48 } 49 50 public void doPost(HttpServletRequest request, HttpServletResponse response) 51 throws ServletException, IOException { 52 doGet(request, response); 53 } 54 55 }到此,用戶登錄的功能就算是開發(fā)完成了。
下面測(cè)試一下開發(fā)好的用戶登錄功能,輸入U(xiǎn)RL地址:http://localhost:8080/webmvcframework/servlet/LoginUIServlet訪問login.jsp頁(yè)面,輸入正確的用戶名和密碼進(jìn)行登錄,運(yùn)行效果如下:
如果輸入的用戶名和密碼錯(cuò)誤,那么就無法登錄成功,運(yùn)行效果如下:
3.4.3、 開發(fā)注銷功能
在me.gacl.web.controller包下編寫用于處理用戶注銷的LogoutServlet
LogoutServlet的代碼如下:
1 package me.gacl.web.controller;2 3 import java.io.IOException;4 import java.text.MessageFormat;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 public class LogoutServlet extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 //移除存儲(chǔ)在session中的user對(duì)象,實(shí)現(xiàn)注銷功能 16 request.getSession().removeAttribute("user"); 17 //由于字符串中包含有單引號(hào),在這種情況下使用MessageFormat.format方法拼接字符串時(shí)就會(huì)有問題 18 //MessageFormat.format方法只是把字符串中的單引號(hào)去掉,不會(huì)將內(nèi)容填充到指定的占位符中 19 String tempStr1 = MessageFormat.format( 20 "注銷成功!!3秒后為您自動(dòng)跳到登錄頁(yè)面!!<meta http-equiv='refresh' content='3;url={0}'/>", 21 request.getContextPath()+"/servlet/LoginUIServlet"); 22 System.out.println(tempStr1);//輸出結(jié)果:注銷成功!!3秒后為您自動(dòng)跳到登錄頁(yè)面!!<meta http-equiv=refresh content=3;url={0}/> 23 System.out.println("---------------------------------------------------------"); 24 /** 25 * 要想解決"如果要拼接的字符串包含有單引號(hào),那么MessageFormat.format方法就只是把字符串中的單引號(hào)去掉,不會(huì)將內(nèi)容填充到指定的占位符中"這個(gè)問題, 26 * 那么可以需要使用單引號(hào)引起來的字符串中使用2個(gè)單引號(hào)引起來,例如:"<meta http-equiv=''refresh'' content=''3;url={0}''/>" 27 * 這樣MessageFormat.format("<meta http-equiv=''refresh'' content=''3;url={0}''/>","index.jsp")就可以正常返回 28 * <meta http-equiv=''refresh'' content=''3;url=index.jsp'/> 29 */ 30 String tempStr2 = MessageFormat.format( 31 "注銷成功!!3秒后為您自動(dòng)跳到登錄頁(yè)面!!<meta http-equiv=''refresh'' content=''3;url={0}''/>", 32 request.getContextPath()+"/servlet/LoginUIServlet"); 33 /** 34 * 輸出結(jié)果: 35 * 注銷成功!!3秒后為您自動(dòng)跳到登錄頁(yè)面!! 36 * <meta http-equiv='refresh' content='3;url=/webmvcframework/servlet/LoginUIServlet'/> 37 */ 38 System.out.println(tempStr2); 39 40 String message = String.format( 41 "注銷成功!!3秒后為您自動(dòng)跳到登錄頁(yè)面!!<meta http-equiv='refresh' content='3;url=%s'/>", 42 request.getContextPath()+"/servlet/LoginUIServlet"); 43 request.setAttribute("message",message); 44 request.getRequestDispatcher("/message.jsp").forward(request, response); 45 } 46 47 public void doPost(HttpServletRequest request, HttpServletResponse response) 48 throws ServletException, IOException { 49 doGet(request, response); 50 } 51 52 }用戶登錄成功后,會(huì)將登錄的用戶信息存儲(chǔ)在session中,所以我們要將存儲(chǔ)在session中的user刪除掉,這樣就可以實(shí)現(xiàn)用戶注銷了。
用戶登錄成功后就會(huì)跳轉(zhuǎn)到index.jsp頁(yè)面,在index.jsp頁(yè)面中放一個(gè)【退出登陸】按鈕,當(dāng)點(diǎn)擊【退出登陸】按鈕時(shí),就訪問LogoutServlet,將用戶注銷。
index.jsp的代碼如下:
1 <%@ page language="java" pageEncoding="UTF-8"%>2 <%--為了避免在jsp頁(yè)面中出現(xiàn)java代碼,這里引入jstl標(biāo)簽庫(kù),利用jstl標(biāo)簽庫(kù)提供的標(biāo)簽來做一些邏輯判斷處理 --%>3 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>4 <!DOCTYPE HTML>5 <html>6 <head>7 <title>首頁(yè)</title>8 <script type="text/javascript">9 function doLogout(){ 10 //訪問LogoutServlet注銷當(dāng)前登錄的用戶 11 window.location.href="${pageContext.request.contextPath}/servlet/LogoutServlet"; 12 } 13 </script> 14 </head> 15 16 <body> 17 <h1>孤傲蒼狼的網(wǎng)站</h1> 18 <hr/> 19 <c:if test="${user==null}"> 20 <a href="${pageContext.request.contextPath}/servlet/RegisterUIServlet" target="_blank">注冊(cè)</a> 21 <a href="${pageContext.request.contextPath}/servlet/LoginUIServlet">登陸</a> 22 </c:if> 23 <c:if test="${user!=null}"> 24 歡迎您:${user.userName} 25 <input type="button" value="退出登陸" onclick="doLogout()"> 26 </c:if> 27 <hr/> 28 </body> 29 </html>測(cè)試開發(fā)好的注銷功能,效果如下:
到此,所有的功能都開發(fā)完成了,測(cè)試也通過了。
四、開發(fā)總結(jié)
通過這個(gè)小例子,可以了解到mvc分層架構(gòu)的項(xiàng)目搭建,在平時(shí)的項(xiàng)目開發(fā)中,也都是按照如下的順序來進(jìn)行開發(fā)的:
1、搭建開發(fā)環(huán)境
1.1 創(chuàng)建web項(xiàng)目
1.2 導(dǎo)入項(xiàng)目所需的開發(fā)包
1.3 創(chuàng)建程序的包名,在java中是以包來體現(xiàn)項(xiàng)目的分層架構(gòu)的
2、開發(fā)domain
把一張要操作的表當(dāng)成一個(gè)VO類(VO類只定義屬性以及屬性對(duì)應(yīng)的get和set方法,沒有涉及到具體業(yè)務(wù)的操作方法),VO表示的是值對(duì)象,通俗地說,就是把表中的每一條記錄當(dāng)成一個(gè)對(duì)象,表中的每一個(gè)字段就作為這個(gè)對(duì)象的屬性。每往表中插入一條記錄,就相當(dāng)于是把一個(gè)VO類的實(shí)例對(duì)象插入到數(shù)據(jù)表中,對(duì)數(shù)據(jù)表進(jìn)行操作時(shí),都是直接把一個(gè)VO類的對(duì)象寫入到表中,一個(gè)VO類對(duì)象就是一條記錄。每一個(gè)VO對(duì)象可以表示一張表中的一行記錄,VO類的名稱要和表的名稱一致或者對(duì)應(yīng)。
3、開發(fā)dao
3.1 DAO操作接口:每一個(gè)DAO操作接口規(guī)定了,一張表在一個(gè)項(xiàng)目中的具體操作方法,此接口的名稱最好按照如下格式編寫:“I表名稱Dao”。
├DAO接口里面的所有方法按照以下的命名編寫:
├更新數(shù)據(jù)庫(kù):doXxx()
├查詢數(shù)據(jù)庫(kù):findXxx()或getXxx()
3.2 DAO操作接口的實(shí)現(xiàn)類:實(shí)現(xiàn)類中完成具體的增刪改查操作
├此實(shí)現(xiàn)類完成的只是數(shù)據(jù)庫(kù)中最核心的操作,并沒有專門處理數(shù)據(jù)庫(kù)的打開和關(guān)閉,因?yàn)檫@些操作與具體的業(yè)務(wù)操作無關(guān)。
4、開發(fā)service(service 對(duì)web層提供所有的業(yè)務(wù)服務(wù))
5、開發(fā)web層
點(diǎn)擊此處下載項(xiàng)目源碼
http://www.cnblogs.com/xdp-gacl/p/3902537.html
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电子元器件(说一说电子元器件的简介)
- 下一篇: 欧洲哥特式建筑有哪些(哥特式建筑代表作有