JavaWeb學習 (二十一)————基於Servlet+JSP+JavaBean開發模式的使用者登入註冊
一、Servlet+JSP+JavaBean開發模式(MVC)介紹
Servlet+JSP+JavaBean模式(MVC)適合開發複雜的web應用,在這種模式下,servlet負責處理使用者請求,jsp負責資料顯示,javabean負責封裝資料。 Servlet+JSP+JavaBean模式程式各個模組之間層次清晰,web開發推薦採用此種模式。
這裡以一個最常用的使用者登入註冊程式來講解Servlet+JSP+JavaBean開發模式,通過這個使用者登入註冊程式綜合案例,把之前的學過的XML、Xpath、Servlet、jsp的知識點都串聯起來。
二、建立MVC架構的Web專案
在MyEclipse中新建立一個webmvcframework專案,匯入專案所需要的開發包(jar包),建立專案所需要的包,在java開發中,架構的層次是以包的形式體現出來的
專案所需要的開發包(jar包) | ||
序號 | 開發包名稱 | 描述 |
1 | dom4j-1.6.1.jar | dom4j用於操作XML檔案 |
2 | jaxen-1.1-beta-6.jar | 用於解析XPath表示式 |
3 | commons-beanutils-1.8.0.jar | 工具類,用於處理bean物件 |
4 | commons-logging.jar | commons-beanutils-1.8.0.jar |
5 | jstl.jar | jstl標籤庫和EL表示式依賴包 |
6 | standard.jar | jstl標籤庫和EL表示式依賴包 |
專案所需要的包 | |||
序號 | 包名 | 描述 | 所屬層次 |
1 | me.gacl.domain | 存放系統的JavaBean類(只包含簡單的屬性以及屬性對應的get和set方法,不包含具體的業務處理方法),提供給【資料訪問層】、【業務處理層】、【Web層】來使用 | domain(域模型)層 |
2 | me.gacl.dao | 存放訪問資料庫的操作介面類 | 資料訪問層 |
3 | me.gacl.dao.impl | 存放訪問資料庫的操作介面的實現類 | |
4 | me.gacl.service | 存放處理系統業務介面類 | 業務處理層 |
5 | me.gacl.service.impl | 存放處理系統業務介面的實現類 | |
6 | me.gacl.web.controller | 存放作為系統控制器的Servlet | Web層(表現層) |
7 | me.gacl.web.UI | 存放為使用者提供使用者介面的servlet(UI指的是user interface) | |
8 | me.gacl.web.filter | 存放系統的用到的過濾器(Filter) | |
9 | me.gacl.web.listener | 存放系統的用到的監聽器(Listener) | |
10 | me.gacl.util | 存放系統的通用工具類,提供給【資料訪問層】、【業務處理層】、【Web層】來使用 | |
11 | junit.test | 存放系統的測試類 |
一個良好的JavaWeb專案架構應該具有以上的11個包,這樣顯得層次分明,各個層之間的職責也很清晰明瞭,搭建JavaWeb專案架構時,就按照上面的1~11的序號順序建立包:domain→dao→dao.impl→service→service.impl→web.controller→web.UI→web.filter→web.listener→util→junit.test,包的層次建立好了,專案的架構也就定下來了,當然,在實際的專案開發中,也不一定是完完全全按照上面說的來建立包的層次結構,而是根據專案的實際情況,可能還需要建立其他的包,這個得根據專案的需要來定了
在src目錄(類目錄)下面,建立用於儲存使用者資料的xml檔案(DB.xml)
在WEB-INF目錄下建立一個pages目錄,pages目錄存放系統的一些受保護(不允許使用者直接通過URL地址訪問)的jsp頁面,使用者要想訪問這些受保護的jsp頁面,那麼只能通過me.gacl.web.UI這個包裡面的Servlet
建立好的專案如下圖(圖-1)所示:
圖-1
三、分層架構的程式碼編寫
分層架構的程式碼也是按照【域模型層(domain)】→【資料訪問層(dao、dao.impl)】→【業務處理層(service、service.impl)】→【表現層(web.controller、web.UI、web.filter、web.listener)】→【工具類(util)】→【測試類(junit.test)】的順序進行編寫的。
3.1、開發domain層
在me.gacl.domain包下建立一個User類
User類具體程式碼如下:
1 package me.gacl.domain; 2 3 import java.io.Serializable; 4 import java.util.Date; 5 /** 6 * @author gacl 7 * 使用者實體類 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、開發資料訪問層(dao、dao.impl)
在me.gacl.dao包下建立一個IUserDao介面類,對於開發介面類,我習慣以字母I作類的字首,這樣一眼就看出當前這個類是一個介面,這也算是一種良好的開發習慣吧,通過看類名就可以方便區分出是介面還是具體的實現類。
IUserDao介面的具體程式碼如下:
1 package me.gacl.dao; 2 3 import me.gacl.domain.User; 4 5 public interface IUserDao { 6 7 /** 8 * 根據使用者名稱和密碼來查詢使用者 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 /**根據使用者名稱來查詢使用者 22 * @param userName 23 * @return 查到到的使用者 24 */ 25 User find(String userName); 26 }
對於介面中的方法定義,這個只能是根據具體的業務來分析需要定義哪些方法了,但是無論是多麼複雜的業務,都離不開基本的CRUD(增刪改查)操作,Dao層是直接和資料庫互動的,所以Dao層的介面一般都會有增刪改查這四種操作的相關方法。
在me.gacl.dao.impl包下建立一個UserDaoImpl類
UserDaoImpl類是IUserDao介面的具體實現類,對於介面的實現類命名方式,我習慣以"介面名(去除字首I)+impl"形式或者"介面名+impl"形式來命名:IUserDao(介面)→UserDaoImpl(實現類)或者IUserDao(介面)→IUserDaoImpl(實現類),這也算是一些個人的程式設計習慣吧,平時看到的程式碼大多數都是以這兩種形式中的一種來來命名介面的具體實現類的,反正就是要能夠一眼看出介面對應的實現類是哪一個就可以了。
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介面的實現類 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表示式來操作XML節點 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"); //建立user結點,並掛到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、開發service層(service層對web層提供所有的業務服務)
在me.gacl.service包中建立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 * 提供註冊服務 10 * @param user 11 * @throws UserExistException 12 */ 13 void registerUser(User user) throws UserExistException; 14 15 /** 16 * 提供登入服務 17 * @param userName 18 * @param userPwd 19 * @return 20 */ 21 User loginUser(String userName, String userPwd); 22 }
在me.gacl.service.impl包中建立UserServiceImpl類
UserServiceImpl類為IUserService介面的具體實現類,具體程式碼如下:
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 //這裡拋編譯時異常的原因:是我想上一層程式處理這個異常,以給使用者一個友好提示 19 throw new UserExistException("註冊的使用者名稱已存在!!!"); 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、開發web層
3.4.1、 開發註冊功能
1、在me.gacl.web.UI包下寫一個RegisterUIServlet為使用者提供註冊介面
RegisterUIServlet收到使用者請求後,就跳到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 * 為使用者提供註冊的使用者介面的Servlet 11 * RegisterUIServlet負責為使用者輸出註冊介面 12 * 當用戶訪問RegisterUIServlet時,就跳轉到WEB-INF/pages目錄下的register.jsp頁面 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/目錄下編寫使用者註冊的jsp頁面register.jsp
凡是位於WEB-INF目錄下的jsp頁面是無法直接通過URL地址直接訪問的,