javaweb學習總結(二十二)——基於Servlet+JSP+JavaBean開發模式的用戶登錄註冊

http://www.cnblogs.com/xdp-gacl/p/3902537.html

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的依賴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地址直接訪問的,

    

    在開發中如果項目中有一些敏感web資源不想被外界直接訪問,那麼可以考慮將這些敏感的web資源放到WEB-INF目錄下,這樣就可以禁止外界直接通過URL來訪問了。

  register.jsp頁面的代碼如下:

複製代碼
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <!DOCTYPE HTML>
 3 <html>
 4     <head>
 5         <title>用戶註冊</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>確認密碼</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="註冊">
48                     </td>
49                 </tr>
50             </table>
51         </form>
52     </body>
53 </html>
複製代碼

  register.jsp中的<form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post">指明表單提交後,交給RegisterServlet進行處理
     3、在me.gacl.web.controller包下編寫用於處理用戶註冊的RegisterServlet

    

    RegisterServlet擔任着以下幾個職責:
               1、接收客戶端提交到服務端的表單數據。

      2、校驗表單數據的合法性,如果校驗失敗跳回到register.jsp,並回顯錯誤信息。

      3、如果校驗通過,調用service層向數據庫中註冊用戶。

    爲了方便RegisterServlet接收表單數據和校驗表單數據,在此我設計一個用於校驗註冊表單數據RegisterFormbean,再寫WebUtils工具類,封裝客戶端提交的表單數據到formbean中。

  在me.gacl.web.formbean包下創建一個用於校驗註冊表單數據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  * 封裝的用戶註冊表單bean,用來接收register.jsp中的表單輸入項的值
 10  * RegisterFormBean中的屬性與register.jsp中的表單輸入項的name一一對應
 11  * RegisterFormBean的職責除了負責接收register.jsp中的表單輸入項的值之外還擔任着校驗表單輸入項的值的合法性
 12  * @author gacl
 13  *
 14  */
 15 public class RegisterFormBean {
 16 
 17     //RegisterFormBean中的屬性與register.jsp中的表單輸入項的name一一對應
 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      * 存儲校驗不通過時給用戶的錯誤提示信息
 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方法負責校驗表單輸入項
 45      * 表單輸入項校驗規則:
 46      *         private String userName; 用戶名不能爲空,並且要是3-8的字母 abcdABcd 
 47      *         private String userPwd; 密碼不能爲空,並且要是3-8的數字
 48      *         private String confirmPwd; 兩次密碼要一致
 49      *         private String email; 可以爲空,不爲空要是一個合法的郵箱 
 50      *         private String birthday; 可以爲空,不爲空時,要是一個合法的日期
 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位的數字!!");
 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; 可以爲空,不爲空要是一個合法的郵箱
 85         if (this.email != null && !this.email.trim().equals("")) {
 86             if (!this.email.matches("\\w+@\\w+(\\.\\w+)+")) {
 87                 isOk = false;
 88                 errors.put("email", "郵箱不是一個合法郵箱!!");
 89             }
 90         }
 91 
 92         // private String birthday; 可以爲空,不爲空時,要是一個合法的日期
 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", "生日必須要是一個日期!!");
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包下創建一個WebUtils工具類,該工具類的功能就是封裝客戶端提交的表單數據到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對象中的請求參數封裝到bean中
11  */
12 public class WebUtils {
13 
14     /**
15      * 將request對象轉換成T對象
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 }
複製代碼

  最後看一下負責處理用戶註冊的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  * 處理用戶註冊的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         //將客戶端提交的表單數據封裝到RegisterFormBean對象中
28         RegisterFormBean formbean = WebUtils.request2Bean(request,RegisterFormBean.class);
29         //校驗用戶註冊填寫的表單數據
30         if (formbean.validate() == false) {//如果校驗失敗
31             //將封裝了用戶填寫的表單數據的formbean對象發送回register.jsp頁面的form表單中進行顯示
32             request.setAttribute("formbean", formbean);
33             //校驗失敗就說明是用戶填寫的表單數據有問題,那麼就跳轉回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             // 註冊字符串到日期的轉換器
41             ConvertUtils.register(new DateLocaleConverter(), Date.class);
42             BeanUtils.copyProperties(user, formbean);//把表單的數據填充到javabean中
43             user.setId(WebUtils.makeId());//設置用戶的Id屬性
44             IUserService service = new UserServiceImpl();
45             //調用service層提供的註冊用戶服務實現用戶註冊
46             service.registerUser(user);
47             String message = String.format(
48                     "註冊成功!!3秒後爲您自動跳到登錄頁面!!<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", "註冊用戶已存在!!");
55             request.setAttribute("formbean", formbean);
56             request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response);
57         } catch (Exception e) {
58             e.printStackTrace(); // 在後臺記錄異常
59             request.setAttribute("message", "對不起,註冊失敗!!");
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 }
複製代碼

   用戶註冊時如果填寫的表單數據校驗不通過,那麼服務器端就將一個存儲了錯誤提示消息和表單數據的formbean對象存儲到request對象中,然後發送回register.jsp頁面,因此我們需要在register.jsp頁面中取出request對象中formbean對象,然後將用戶填寫的表單數據重新回顯到對應的表單項上面,將出錯時的提示消息也顯示到form表單上面,讓用戶知道是哪些數據填寫不合法!

  修改register.jsp頁面,代碼如下:

複製代碼
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <!DOCTYPE HTML>
 3 <html>
 4     <head>
 5         <title>用戶註冊</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表達式${}提取存儲在request對象中的formbean對象中封裝的表單數據(formbean.userName)以及錯誤提示消息(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>確認密碼</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="註冊">
48                     </td>
49                 </tr>
50             </table>
51         </form>
52     </body>
53 </html>
複製代碼

   到此,用戶註冊功能就算是開發完成了!

  下面測試一下開發好的用戶註冊功能:

    輸入URL地址:http://localhost:8080/webmvcframework/servlet/RegisterUIServlet訪問register.jsp頁面,運行效果如下:

    

  如果輸入的表單項不符合校驗規則,那麼是無法進行註冊的,運行效果如下:

    

3.4.2、 開發登錄功能

  1、在me.gacl.web.UI下寫一個LoginUIServlet爲用戶提供登錄界面

  

  LoginUIServlet收到用戶請求後,就跳到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負責爲用戶輸出登陸界面
13  * 當用戶訪問LoginUIServlet時,就跳轉到WEB-INF/pages目錄下的login.jsp頁面
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頁面login.jsp

  

  login.jsp頁面的代碼如下:

複製代碼
 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進行處理。
     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                     "對不起,用戶名或密碼有誤!!請重新登錄!2秒後爲您自動跳到登錄頁面!!<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         //登錄成功後,就將用戶存儲到session中
41         request.getSession().setAttribute("user", user);
42         String message = String.format(
43                 "恭喜:%s,登陸成功!本頁將在3秒後跳到首頁!!<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 }
複製代碼

  到此,用戶登錄的功能就算是開發完成了。

  下面測試一下開發好的用戶登錄功能,輸入URL地址:http://localhost:8080/webmvcframework/servlet/LoginUIServlet訪問login.jsp頁面,輸入正確的用戶名和密碼進行登錄,運行效果如下:

  

  如果輸入的用戶名和密碼錯誤,那麼就無法登錄成功,運行效果如下:

  

3.4.3、 開發註銷功能

  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         //移除存儲在session中的user對象,實現註銷功能
16         request.getSession().removeAttribute("user");
17         //由於字符串中包含有單引號,在這種情況下使用MessageFormat.format方法拼接字符串時就會有問題
18         //MessageFormat.format方法只是把字符串中的單引號去掉,不會將內容填充到指定的佔位符中
19         String tempStr1 = MessageFormat.format(
20                 "註銷成功!!3秒後爲您自動跳到登錄頁面!!<meta http-equiv='refresh' content='3;url={0}'/>", 
21                 request.getContextPath()+"/servlet/LoginUIServlet");
22         System.out.println(tempStr1);//輸出結果:註銷成功!!3秒後爲您自動跳到登錄頁面!!<meta http-equiv=refresh content=3;url={0}/>
23         System.out.println("---------------------------------------------------------");
24         /**
25          * 要想解決"如果要拼接的字符串包含有單引號,那麼MessageFormat.format方法就只是把字符串中的單引號去掉,不會將內容填充到指定的佔位符中"這個問題,
26          * 那麼可以需要使用單引號引起來的字符串中使用2個單引號引起來,例如:"<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秒後爲您自動跳到登錄頁面!!<meta http-equiv=''refresh'' content=''3;url={0}''/>", 
32                 request.getContextPath()+"/servlet/LoginUIServlet");
33         /**
34          * 輸出結果:
35          * 註銷成功!!3秒後爲您自動跳到登錄頁面!!
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秒後爲您自動跳到登錄頁面!!<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 }
複製代碼

  用戶登錄成功後,會將登錄的用戶信息存儲在session中,所以我們要將存儲在session中的user刪除掉,這樣就可以實現用戶註銷了。

  用戶登錄成功後就會跳轉到index.jsp頁面,在index.jsp頁面中放一個【退出登陸】按鈕,當點擊【退出登陸】按鈕時,就訪問LogoutServlet,將用戶註銷。

  index.jsp的代碼如下:

複製代碼
 1 <%@ page language="java"  pageEncoding="UTF-8"%>
 2 <%--爲了避免在jsp頁面中出現java代碼,這裏引入jstl標籤庫,利用jstl標籤庫提供的標籤來做一些邏輯判斷處理 --%>
 3 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>首頁</title>
 8      <script type="text/javascript">
 9         function doLogout(){
10             //訪問LogoutServlet註銷當前登錄的用戶
11             window.location.href="${pageContext.request.contextPath}/servlet/LogoutServlet";
12         }
13     </script>
14   </head>
15   
16   <body>
17     <h1>孤傲蒼狼的網站</h1>
18     <hr/>
19     <c:if test="${user==null}">
20         <a href="${pageContext.request.contextPath}/servlet/RegisterUIServlet" target="_blank">註冊</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>
複製代碼

  測試開發好的註銷功能,效果如下:

  

  到此,所有的功能都開發完成了,測試也通過了。

四、開發總結

  通過這個小例子,可以瞭解到mvc分層架構的項目搭建,在平時的項目開發中,也都是按照如下的順序來進行開發的:

  1、搭建開發環境

    1.1 創建web項目

    1.2 導入項目所需的開發包

    1.3 創建程序的包名,在java中是以包來體現項目的分層架構的

  2、開發domain

  把一張要操作的表當成一個VO類(VO類只定義屬性以及屬性對應的get和set方法,沒有涉及到具體業務的操作方法),VO表示的是值對象,通俗地說,就是把表中的每一條記錄當成一個對象,表中的每一個字段就作爲這個對象的屬性。每往表中插入一條記錄,就相當於是把一個VO類的實例對象插入到數據表中,對數據表進行操作時,都是直接把一個VO類的對象寫入到表中,一個VO類對象就是一條記錄。每一個VO對象可以表示一張表中的一行記錄,VO類的名稱要和表的名稱一致或者對應。

  3、開發dao

    3.1 DAO操作接口:每一個DAO操作接口規定了,一張表在一個項目中的具體操作方法,此接口的名稱最好按照如下格式編寫:“I表名稱Dao”。

      ├DAO接口裏面的所有方法按照以下的命名編寫:

        ├更新數據庫:doXxx()

        ├查詢數據庫:findXxx()getXxx()

    3.2 DAO操作接口的實現類:實現類中完成具體的增刪改查操作

      ├此實現類完成的只是數據庫中最核心的操作,並沒有專門處理數據庫的打開和關閉,因爲這些操作與具體的業務操作無關。

  4、開發service(service 對web層提供所有的業務服務)

  5、開發web層

  點擊此處下載項目源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章