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包)
序號開發包名稱描述
1dom4j-1.6.1.jardom4j用于操作XML文件
2jaxen-1.1-beta-6.jar用于解析XPath表達式
3commons-beanutils-1.8.0.jar工具類,用于處理bean對象
4commons-logging.jarcommons-beanutils-1.8.0.jar的依賴jar包
5jstl.jarjstl標簽庫和EL表達式依賴包
6standard.jarjstl標簽庫和EL表達式依賴包

?

  

  

?

?

?

?

?

項目所需要的包
序號包名描述所屬層次
1me.gacl.domain存放系統的JavaBean類(只包含簡單的屬性以及屬性對應的get和set方法,不包含具體的業務處理方法),提供給【數據訪問層】、【業務處理層】、【Web層】來使用?domain(域模型)層
2me.gacl.dao存放訪問數據庫的操作接口類數據訪問層
3me.gacl.dao.impl存放訪問數據庫的操作接口的實現類
4me.gacl.service存放處理系統業務接口類業務處理層
5me.gacl.service.impl存放處理系統業務接口的實現類
6me.gacl.web.controller存放作為系統控制器的ServletWeb層(表現層)
7me.gacl.web.UI存放為用戶提供用戶界面的servlet(UI指的是user interface)
8me.gacl.web.filter存放系統的用到的過濾器(Filter)
9me.gacl.web.listener存放系統的用到的監聽器(Listener)
10me.gacl.util存放系統的通用工具類,提供給【數據訪問層】、【業務處理層】、【Web層】來使用?
11junit.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 gacl7  * 用戶實體類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 gacl13  *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="退出登陸" οnclick="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層

  點擊此處下載項目源碼

?

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

轉載于:https://www.cnblogs.com/soundcode/p/6298502.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394110.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394110.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394110.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2018黃河獎設計大賽獲獎_宣布我們的freeCodeCamp 2018杰出貢獻者獎獲獎者

2018黃河獎設計大賽獲獎by Quincy Larson昆西拉爾森(Quincy Larson) 宣布我們的freeCodeCamp 2018杰出貢獻者獎獲獎者 (Announcing Our freeCodeCamp 2018 Top Contributor Award Winners) Over the past 3 years, freeCodeCamp.org has grown from a small open source proje…

Log4j配置詳解

來自: http://www.blogjava.net/zJun/archive/2006/06/28/55511.html Log4J的配置文件(Configuration File)就是用來設置記錄器的級別、存放器和布局的&#xff0c;它可接keyvalue格式的設置或xml格式的設置信息。通過配置&#xff0c;可以創建出Log4J的運行環境。1. 配置文件 …

cors數據類型_如何根據RTK的差分格式選擇千尋cors賬號的源節點進行設置?

千尋cors賬號的設置中源節點是根據使用的品牌RTK是為雙星儀器還是三星儀器選擇&#xff0c;但問題就在于我們看到的RTK的技術參數中一般很少見到標注儀器的衛星系統&#xff0c;更多的是差分格式。其實千尋cors賬號的源節點也可以根據RTK的差分格式進行選擇&#xff0c;不過這兩…

java swing 串口_ComTest 接收串口數據,并顯示在文本框內,通過JavaSwing實現 Develop 265萬源代碼下載- www.pudn.com...

文件名稱: ComTest下載 收藏√ [5 4 3 2 1 ]開發工具: Java文件大小: 3157 KB上傳時間: 2016-09-21下載次數: 0提 供 者: 韓坤詳細說明&#xff1a;接收串口數據&#xff0c;并顯示在文本框內&#xff0c;通過JavaSwing實現-Receive serial data, and displayed in the t…

leetcode329. 矩陣中的最長遞增路徑(dfs)

給定一個整數矩陣&#xff0c;找出最長遞增路徑的長度。對于每個單元格&#xff0c;你可以往上&#xff0c;下&#xff0c;左&#xff0c;右四個方向移動。 你不能在對角線方向上移動或移動到邊界外&#xff08;即不允許環繞&#xff09;。示例 1:輸入: nums [[9,9,4],[6,6,8…

SQL大圣之路筆記——PowerDesigner之新建table、view、proc

1. 新建table、view、proc 轉載于:https://www.cnblogs.com/allenzhang/p/6305564.html

用python繪制一條直線_python繪制直線的方法

本文實例為大家分享了python繪制直線的具體代碼&#xff0c;供大家參考&#xff0c;具體內容如下#!/usr/bin/env pythonimport vtk# 繪制通用方法def myshow(linepolydata):# Now well look at it.lineMapper vtk.vtkPolyDataMapper()if vtk.VTK_MAJOR_VERSION < 5:lineMap…

測試驅動開發 測試前移_我如何以及為什么認為測試驅動開發值得我花時間

測試驅動開發 測試前移by Ronauli Silva通過羅納利席爾瓦(Ronauli Silva) I first read about test driven development (TDD) in some technical reviews blog, but I barely read it (or thought about it). Why would people write tests first when they already knew the…

P2921 [USACO08DEC]在農場萬圣節Trick or Treat on the Farm

對于一個牛&#xff0c;它存在兩種狀態&#xff1a;1.處于聯通分量 2.不處于聯通分量。對于處于聯通分量的牛&#xff0c;求出聯通分量的大小&#xff1b;對于不處于聯通分量的牛&#xff0c;求出其距離聯通分量的路程聯通分量大小。 不同的聯通分量&#xff0c;染上不同的顏色…

ASP.NET MVC5+EF6+EasyUI 后臺管理系統(1)-前言與目錄(持續更新中...)

開發工具&#xff1a;VS2015(2012以上)SQL2008R2以上數據庫 您可以有償獲取一份最新源碼聯系QQ:729994997 價格 666RMB 升級后界面效果如下&#xff1a; 日程管理 http://www.cnblogs.com/ymnets/p/7094914.html 任務調度系統界面 http://www.cnblogs.com/ymnets/p/5065154.h…

leetcode106. 從中序與后序遍歷序列構造二叉樹(dfs)

根據一棵樹的中序遍歷與后序遍歷構造二叉樹。注意: 你可以假設樹中沒有重復的元素。例如&#xff0c;給出中序遍歷 inorder [9,3,15,20,7] 后序遍歷 postorder [9,15,7,20,3] 返回如下的二叉樹&#xff1a;3/ \9 20/ \15 7解題思路 根據后序遍歷的最后一個元素是父節點&…

【FRDM-K64F學習筆記】使用ARM mbed和Keil MDK下載你的第一個程序

FRDM-K64F開發平臺采用MK64FN1M0VLL12微控制器。該控制器包含一個帶有浮點單元的ARM Cortex-M4內核。其最高工作頻率為120MHz&#xff0c;具有256KB的RAM、1MB閃存以及許多其他外設。它非常適合大多數可以采用以太網、SD卡存儲以及板載模擬-數字轉換器的IoT應用。但是&#xff…

php 實時更新內容_億級視頻內容如何實時更新?優酷視頻背后的技術揭秘

簡介&#xff1a; 優酷視頻內容數據天然呈現巨大的網絡結構&#xff0c;各類數據實體連接形成了數十億頂點和百億條邊的數據量&#xff0c;面對巨大的數據量&#xff0c;傳統關系型數據庫往往難以處理和管理&#xff0c;圖數據結構更加貼合優酷的業務場景&#xff0c;圖組織使用…

ios集成firebase_如何使用Firebase將Google Login集成到Ionic應用程序中

ios集成firebaseby Ryan Gordon通過瑞安戈登(Ryan Gordon) 如何使用Firebase將Google Login集成到Ionic應用程序中 (How to integrate Google Login into an Ionic app with Firebase) A lot of apps these days need to maintain some form of user authentication. This hel…

面向對象三大核心特點,封裝、繼承和多態

封裝 封裝其實是一種思想&#xff0c;將事物狀態和功能裝進一個容器&#xff0c;那么這個容器在python中就是類&#xff0c;由這個類產生的對象都擁有類的屬性和功能 在面向對象的思想中&#xff0c;推崇將具有某些共同特征的事物歸為一類&#xff0c;那么這些事物就可以看做是…

java編寫某計算器控制臺程序_用java程序編寫一個計算器

點擊查看用java程序編寫一個計算器具體信息答&#xff1a;給你一個參考&#xff0c;希望不要被百度吞了當晚餐 import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.text.Decimal…

物聯網商機迸發 LPWAN芯片現身 本文轉自d1net(轉載)

聯發科技發表首款NB-IoT系統單芯片MT2625。來源&#xff1a;MediaTeK 物聯網(IoT)帶動的龐大商機吸引各方業者積極投入&#xff0c;尤其是各種聯網技術不斷現身&#xff0c;爭奪各式各樣極富發展潛力的應用領域。 根據IDC的調查報告&#xff0c;物聯網市場在2017年聲勢看漲&…

jquery之stop()的用法

工作中遇到過的實際案例&#xff1a; 1、我在項目里做的一個下拉菜單&#xff0c;當鼠標移上去的時候就菜單顯示&#xff0c;當鼠標離開的時候菜單隱藏 如果我快速不斷地將鼠標移入移出菜單&#xff08;即&#xff0c;當菜單下拉動畫未完成時&#xff0c;鼠標又移出了菜單&…

leetcode1123. 最深葉節點的最近公共祖先(dfs)

給你一個有根節點的二叉樹&#xff0c;找到它最深的葉節點的最近公共祖先。 回想一下&#xff1a; 葉節點 是二叉樹中沒有子節點的節點 樹的根節點的 深度 為 0&#xff0c;如果某一節點的深度為 d&#xff0c;那它的子節點的深度就是 d1 如果我們假定 A 是一組節點 S 的 最近…

sed空格替換成回車_【一題試水平】 利用sed命令將test.txt中所有的回車替換成空格?...

題目背景&#xff0c;這個題也很有年頭了&#xff0c;看似簡單&#xff0c;實則坑很大&#xff0c;good luck! 先不要看答案 看看自己能寫出多少方法.方法1 把每一行內容追加到Hold Space中&#xff0c;最后1行弄回到Pattern space中.然后進行替換基礎版[rootoldboyedu-show01 …