一、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表達式依賴包 |
一個良好的JavaWeb項目架構應該具有以上的11個包,這樣顯得層次分明,各個層之間的職責也很清晰明了,搭建JavaWeb項目架構時,就按照上面的1~11的序號順序創建包:domain→dao→dao.impl→service→service.impl→web.controller→web.UI→web.filter→web.listener→util→junit.test,包的層次創建好了,項目的架構也就定下來了,當然,在實際的項目開發中,也不一定是完完全全按照
項目所需要的包 | |||
序號 | 包名 | 描述 | 所屬層次 |
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 | 存放系統的測試類 |
上面說的來創建包的層次結構,而是根據項目的實際情況,可能還需要創建其他的包,這個得根據項目的需要來定了
在src目錄(類目錄)下面,創建用於保存用戶數據的xml文件(DB.xml)
在WEB-INF目錄下創建一個pages目錄,pages目錄存放系統的一些受保護(不允許用戶直接通過URL地址訪問)的jsp頁面,用戶要想訪問這些受保護的jsp頁面,那么只能通過me.gacl.web.UI這個包里面的Servlet
三、分層架構的代碼編寫
分層架構的代碼也是按照【域模型層(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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package
me.gacl.domain;
import
java.io.Serializable;
import
java.util.Date;
/**
* @author gacl
* 用戶實體類
*/
public
class
User
implements
Serializable {
private
static
final
long
serialVersionUID = -L;
// 用戶ID
private
String id;
// 用戶名
private
String userName;
// 用戶密碼
private
String userPwd;
// 用戶郵箱
private
String email;
// 用戶生日
private
Date birthday;
public
String getId() {
return
id;
}
public
void
setId(String id) {
this
.id = id;
}
public
String getUserName() {
return
userName;
}
public
void
setUserName(String userName) {
this
.userName = userName;
}
public
String getUserPwd() {
return
userPwd;
}
public
void
setUserPwd(String userPwd) {
this
.userPwd = userPwd;
}
public
String getEmail() {
return
email;
}
public
void
setEmail(String email) {
this
.email = email;
}
public
Date getBirthday() {
return
birthday;
}
public
void
setBirthday(Date birthday) {
this
.birthday = birthday;
}
}
|
3.2、開發數據訪問層(dao、dao.impl)
在me.gacl.dao包下創建一個IUserDao接口類,對於開發接口類,我習慣以字母I作類的前綴,這樣一眼就看出當前這個類是一個接口,這也算是一種良好的開發習慣吧,通過看類名就可以方便區分出是接口還是具體的實現類。
IUserDao接口的具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
me.gacl.dao;
import
me.gacl.domain.User;
public
interface
IUserDao {
/**
* 根據用戶名和密碼來查找用戶
* @param userName
* @param userPwd
* @return 查到到的用戶
*/
User find(String userName, String userPwd);
/**
* 添加用戶
* @param user
*/
void
add(User user);
/**根據用戶名來查找用戶
* @param userName
* @return 查到到的用戶
*/
User find(String userName);
}
|
對於接口中的方法定義,這個只能是根據具體的業務來分析需要定義哪些方法了,但是無論是多么復雜的業務,都離不開基本的CRUD(增刪改查)操作,Dao層是直接和數據庫交互的,所以Dao層的接口一般都會有增刪改查這四種操作的相關方法。
在me.gacl.dao.impl包下創建一個UserDaoImpl類
UserDaoImpl類是IUserDao接口的具體實現類,對於接口的實現類命名方式,我習慣以"接口名(去除前綴I)+impl"形式或者"接口名+impl"形式來命名:IUserDao(接口)→UserDaoImpl(實現類)或者IUserDao(接口)→IUserDaoImpl(實現類),這也算是一些個人的編程習慣吧,平時看到的代碼大多數都是以這兩種形式中的一種來來命名接口的具體實現類的,反正就是要能夠一眼看出接口對應的實現類是哪一個就可以了。
UserDaoImpl類的具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
package
me.gacl.dao.impl;
import
java.text.SimpleDateFormat;
import
org.domj.Document;
import
org.domj.Element;
import
me.gacl.dao.IUserDao;
import
me.gacl.domain.User;
import
me.gacl.util.XmlUtils;
/**
* IUserDao接口的實現類
* @author gacl
*/
public
class
UserDaoImpl
implements
IUserDao {
@Override
public
User find(String userName, String userPwd) {
try
{
Document document = XmlUtils.getDocument();
//使用XPath表達式來操作XML節點
Element e = (Element) document.selectSingleNode(
"//user[@userName='"
+userName+
"' and @userPwd='"
+userPwd+
"']"
);
if
(e==
null
){
return
null
;
}
User user =
new
User();
user.setId(e.attributeValue(
"id"
));
user.setEmail(e.attributeValue(
"email"
));
user.setUserPwd(e.attributeValue(
"userPwd"
));
user.setUserName(e.attributeValue(
"userName"
));
String birth = e.attributeValue(
"birthday"
);
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyy-MM-dd"
);
user.setBirthday(sdf.parse(birth));
return
user;
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
@SuppressWarnings
(
"deprecation"
)
@Override
public
void
add(User user) {
try
{
Document document = XmlUtils.getDocument();
Element root = document.getRootElement();
Element user_node = root.addElement(
"user"
);
//創建user結點,並掛到root
user_node.setAttributeValue(
"id"
, user.getId());
user_node.setAttributeValue(
"userName"
, user.getUserName());
user_node.setAttributeValue(
"userPwd"
, user.getUserPwd());
user_node.setAttributeValue(
"email"
, user.getEmail());
SimpleDateFormat sdf=
new
SimpleDateFormat(
"yyyy-MM-dd"
);
user_node.setAttributeValue(
"birthday"
, sdf.format(user.getBirthday()));
XmlUtils.writeXml(document);
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
@Override
public
User find(String userName) {
try
{
Document document = XmlUtils.getDocument();
Element e = (Element) document.selectSingleNode(
"//user[@userName='"
+userName+
"']"
);
if
(e==
null
){
return
null
;
}
User user =
new
User();
user.setId(e.attributeValue(
"id"
));
user.setEmail(e.attributeValue(
"email"
));
user.setUserPwd(e.attributeValue(
"userPwd"
));
user.setUserName(e.attributeValue(
"userName"
));
String birth = e.attributeValue(
"birthday"
);
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyy-MM-dd"
);
user.setBirthday(sdf.parse(birth));
return
user;
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
}
|
3.3、開發service層(service層對web層提供所有的業務服務)
在me.gacl.service包中創建IUserService接口類
IUserService接口的具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package
me.gacl.service;
import
me.gacl.domain.User;
import
me.gacl.exception.UserExistException;
public
interface
IUserService {
/**
* 提供注冊服務
* @param user
* @throws UserExistException
*/
void
registerUser(User user)
throws
UserExistException;
/**
* 提供登錄服務
* @param userName
* @param userPwd
* @return
*/
User loginUser(String userName, String userPwd);
}
|
在me.gacl.service.impl包中創建UserServiceImpl類
UserServiceImpl類為IUserService接口的具體實現類,具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package
me.gacl.service.impl;
import
me.gacl.dao.IUserDao;
import
me.gacl.dao.impl.UserDaoImpl;
import
me.gacl.domain.User;
import
me.gacl.exception.UserExistException;
import
me.gacl.service.IUserService;
public
class
UserServiceImpl
implements
IUserService {
private
IUserDao userDao =
new
UserDaoImpl();
@Override
public
void
registerUser(User user)
throws
UserExistException {
if
(userDao.find(user.getUserName())!=
null
) {
//checked exception
//unchecked exception
//這里拋編譯時異常的原因:是我想上一層程序處理這個異常,以給用戶一個友好提示
throw
new
UserExistException(
"注冊的用戶名已存在!!!"
);
}
userDao.add(user);
}
@Override
public
User loginUser(String userName, String userPwd) {
return
userDao.find(userName, userPwd);
}
}
|
3.4、開發web層
3.4.1、 開發注冊功能
1、在me.gacl.web.UI包下寫一個RegisterUIServlet為用戶提供注冊界面
RegisterUIServlet收到用戶請求后,就跳到register.jsp
RegisterUIServlet的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package
me.gacl.web.UI;
import
java.io.IOException;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
/**
* @author gacl
* 為用戶提供注冊的用戶界面的Servlet
* RegisterUIServlet負責為用戶輸出注冊界面
* 當用戶訪問RegisterUIServlet時,就跳轉到WEB-INF/pages目錄下的register.jsp頁面
*/
public
class
RegisterUIServlet
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
request.getRequestDispatcher(
"/WEB-INF/pages/register.jsp"
).forward(request, response);
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
2、在/WEB-INF/pages/目錄下編寫用戶注冊的jsp頁面register.jsp
凡是位於WEB-INF目錄下的jsp頁面是無法直接通過URL地址直接訪問的,
在開發中如果項目中有一些敏感web資源不想被外界直接訪問,那么可以考慮將這些敏感的web資源放到WEB-INF目錄下,這樣就可以禁止外界直接通過URL來訪問了。
register.jsp頁面的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
<%@ page language=
"java"
pageEncoding=
"UTF-"
%>
<!DOCTYPE HTML>
<html>
<head>
<title>用戶注冊</title>
</head>
<body style=
"text-align: center;"
>
<form action=
"${pageContext.request.contextPath}/servlet/RegisterServlet"
method=
"post"
>
<table width=
"%"
border=
""
>
<tr>
<td>用戶名</td>
<td>
<input type=
"text"
name=
"userName"
>
</td>
</tr>
<tr>
<td>密碼</td>
<td>
<input type=
"password"
name=
"userPwd"
>
</td>
</tr>
<tr>
<td>確認密碼</td>
<td>
<input type=
"password"
name=
"confirmPwd"
>
</td>
</tr>
<tr>
<td>郵箱</td>
<td>
<input type=
"text"
name=
"email"
>
</td>
</tr>
<tr>
<td>生日</td>
<td>
<input type=
"text"
name=
"birthday"
>
</td>
</tr>
<tr>
<td>
<input type=
"reset"
value=
"清空"
>
</td>
<td>
<input type=
"submit"
value=
"注冊"
>
</td>
</tr>
</table>
</form>
</body>
</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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
package
me.gacl.web.formbean;
import
java.util.HashMap;
import
java.util.Map;
import
org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
/**
* 封裝的用戶注冊表單bean,用來接收register.jsp中的表單輸入項的值
* RegisterFormBean中的屬性與register.jsp中的表單輸入項的name一一對應
* RegisterFormBean的職責除了負責接收register.jsp中的表單輸入項的值之外還擔任着校驗表單輸入項的值的合法性
* @author gacl
*
*/
public
class
RegisterFormBean {
//RegisterFormBean中的屬性與register.jsp中的表單輸入項的name一一對應
//<input type="text" name="userName"/>
private
String userName;
//<input type="password" name="userPwd"/>
private
String userPwd;
//<input type="password" name="confirmPwd"/>
private
String confirmPwd;
//<input type="text" name="email"/>
private
String email;
//<input type="text" name="birthday"/>
private
String birthday;
/**
* 存儲校驗不通過時給用戶的錯誤提示信息
*/
private
Map<String, String> errors =
new
HashMap<String, String>();
public
Map<String, String> getErrors() {
return
errors;
}
public
void
setErrors(Map<String, String> errors) {
this
.errors = errors;
}
/*
* validate方法負責校驗表單輸入項
* 表單輸入項校驗規則:
* private String userName; 用戶名不能為空,並且要是-的字母 abcdABcd
* private String userPwd; 密碼不能為空,並且要是-的數字
* private String confirmPwd; 兩次密碼要一致
* private String email; 可以為空,不為空要是一個合法的郵箱
* private String birthday; 可以為空,不為空時,要是一個合法的日期
*/
public
boolean
validate() {
boolean
isOk =
true
;
if
(
this
.userName ==
null
||
this
.userName.trim().equals(
""
)) {
isOk =
false
;
errors.put(
"userName"
,
"用戶名不能為空!!"
);
}
else
{
if
(!
this
.userName.matches(
"[a-zA-Z]{,}"
)) {
isOk =
false
;
errors.put(
"userName"
,
"用戶名必須是-位的字母!!"
);
}
}
if
(
this
.userPwd ==
null
||
this
.userPwd.trim().equals(
""
)) {
isOk =
false
;
errors.put(
"userPwd"
,
"密碼不能為空!!"
);
}
else
{
if
(!
this
.userPwd.matches(
"\\d{,}"
)) {
isOk =
false
;
errors.put(
"userPwd"
,
"密碼必須是-位的數字!!"
);
}
}
// private String password; 兩次密碼要一致
if
(
this
.confirmPwd !=
null
) {
if
(!
this
.confirmPwd.equals(
this
.userPwd)) {
isOk =
false
;
errors.put(
"confirmPwd"
,
"兩次密碼不一致!!"
);
}
}
// private String email; 可以為空,不為空要是一個合法的郵箱
if
(
this
.email !=
null
&& !
this
.email.trim().equals(
""
)) {
if
(!
this
.email.matches(
"\\w+@\\w+(\\.\\w+)+"
)) {
isOk =
false
;
errors.put(
"email"
,
"郵箱不是一個合法郵箱!!"
);
}
}
// private String birthday; 可以為空,不為空時,要是一個合法的日期
if
(
this
.birthday !=
null
&& !
this
.birthday.trim().equals(
""
)) {
try
{
DateLocaleConverter conver =
new
DateLocaleConverter();
conver.convert(
this
.birthday);
}
catch
(Exception e) {
isOk =
false
;
errors.put(
"birthday"
,
"生日必須要是一個日期!!"
);
}
}
return
isOk;
}
public
String getUserName() {
return
userName;
}
public
void
setUserName(String userName) {
this
.userName = userName;
}
public
String getUserPwd() {
return
userPwd;
}
public
void
setUserPwd(String userPwd) {
this
.userPwd = userPwd;
}
public
String getConfirmPwd() {
return
confirmPwd;
}
public
void
setConfirmPwd(String confirmPwd) {
this
.confirmPwd = confirmPwd;
}
public
String getEmail() {
return
email;
}
public
void
setEmail(String email) {
this
.email = email;
}
public
String getBirthday() {
return
birthday;
}
public
void
setBirthday(String birthday) {
this
.birthday = birthday;
}
}
|
在me.gacl.util包下創建一個WebUtils工具類,該工具類的功能就是封裝客戶端提交的表單數據到formbean中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package
me.gacl.util;
import
java.util.Enumeration;
import
java.util.UUID;
import
javax.servlet.http.HttpServletRequest;
import
org.apache.commons.beanutils.BeanUtils;
/**
* @author gacl
* 把request對象中的請求參數封裝到bean中
*/
public
class
WebUtils {
/**
* 將request對象轉換成T對象
* @param request
* @param clazz
* @return
*/
public
static
<T> T requestBean(HttpServletRequest request,Class<T> clazz){
try
{
T bean = clazz.newInstance();
Enumeration<String> e = request.getParameterNames();
while
(e.hasMoreElements()){
String name = (String) e.nextElement();
String value = request.getParameter(name);
BeanUtils.setProperty(bean, name, value);
}
return
bean;
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
/**
* 生成UUID
* @return
*/
public
static
String makeId(){
return
UUID.randomUUID().toString();
}
}
|
最后看一下負責處理用戶注冊的RegisterServlet完整代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package
me.gacl.web.controller;
import
java.io.IOException;
import
java.util.Date;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.apache.commons.beanutils.BeanUtils;
import
org.apache.commons.beanutils.ConvertUtils;
import
org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
import
me.gacl.domain.User;
import
me.gacl.exception.UserExistException;
import
me.gacl.service.IUserService;
import
me.gacl.service.impl.UserServiceImpl;
import
me.gacl.util.WebUtils;
import
me.gacl.web.formbean.RegisterFormBean;
/**
* 處理用戶注冊的Servlet
* @author gacl
*
*/
public
class
RegisterServlet
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
//將客戶端提交的表單數據封裝到RegisterFormBean對象中
RegisterFormBean formbean = WebUtils.requestBean(request,RegisterFormBean.
class
);
//校驗用戶注冊填寫的表單數據
if
(formbean.validate() ==
false
) {
//如果校驗失敗
//將封裝了用戶填寫的表單數據的formbean對象發送回register.jsp頁面的form表單中進行顯示
request.setAttribute(
"formbean"
, formbean);
//校驗失敗就說明是用戶填寫的表單數據有問題,那么就跳轉回register.jsp
request.getRequestDispatcher(
"/WEB-INF/pages/register.jsp"
).forward(request, response);
return
;
}
User user =
new
User();
try
{
// 注冊字符串到日期的轉換器
ConvertUtils.register(
new
DateLocaleConverter(), Date.
class
);
BeanUtils.copyProperties(user, formbean);
//把表單的數據填充到javabean中
user.setId(WebUtils.makeId());
//設置用戶的Id屬性
IUserService service =
new
UserServiceImpl();
//調用service層提供的注冊用戶服務實現用戶注冊
service.registerUser(user);
String message = String.format(
"注冊成功!!秒后為您自動跳到登錄頁面!!<meta http-equiv='refresh' content=';url=%s'/>"
,
request.getContextPath()+
"/servlet/LoginUIServlet"
);
request.setAttribute(
"message"
,message);
request.getRequestDispatcher(
"/message.jsp"
).forward(request,response);
}
catch
(UserExistException e) {
formbean.getErrors().put(
"userName"
,
"注冊用戶已存在!!"
);
request.setAttribute(
"formbean"
, formbean);
request.getRequestDispatcher(
"/WEB-INF/pages/register.jsp"
).forward(request, response);
}
catch
(Exception e) {
e.printStackTrace();
// 在后台記錄異常
request.setAttribute(
"message"
,
"對不起,注冊失敗!!"
);
request.getRequestDispatcher(
"/message.jsp"
).forward(request,response);
}
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
用戶注冊時如果填寫的表單數據校驗不通過,那么服務器端就將一個存儲了錯誤提示消息和表單數據的formbean對象存儲到request對象中,然后發送回register.jsp頁面,因此我們需要在register.jsp頁面中取出request對象中formbean對象,然后將用戶填寫的表單數據重新回顯到對應的表單項上面,將出錯時的提示消息也顯示到form表單上面,讓用戶知道是哪些數據填寫不合法!
修改register.jsp頁面,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
<%@ page language=
"java"
pageEncoding=
"UTF-"
%>
<!DOCTYPE HTML>
<html>
<head>
<title>用戶注冊</title>
</head>
<body style=
"text-align: center;"
>
<form action=
"${pageContext.request.contextPath}/servlet/RegisterServlet"
method=
"post"
>
<table width=
"%"
border=
""
>
<tr>
<td>用戶名</td>
<td>
<%--使用EL表達式${}提取存儲在request對象中的formbean對象中封裝的表單數據(formbean.userName)以及錯誤提示消息(formbean.errors.userName)--%>
<input type=
"text"
name=
"userName"
value=
"${formbean.userName}"
>${formbean.errors.userName}
</td>
</tr>
<tr>
<td>密碼</td>
<td>
<input type=
"password"
name=
"userPwd"
value=
"${formbean.userPwd}"
>${formbean.errors.userPwd}
</td>
</tr>
<tr>
<td>確認密碼</td>
<td>
<input type=
"password"
name=
"confirmPwd"
value=
"${formbean.confirmPwd}"
>${formbean.errors.confirmPwd}
</td>
</tr>
<tr>
<td>郵箱</td>
<td>
<input type=
"text"
name=
"email"
value=
"${formbean.email}"
>${formbean.errors.email}
</td>
</tr>
<tr>
<td>生日</td>
<td>
<input type=
"text"
name=
"birthday"
value=
"${formbean.birthday}"
>${formbean.errors.birthday}
</td>
</tr>
<tr>
<td>
<input type=
"reset"
value=
"清空"
>
</td>
<td>
<input type=
"submit"
value=
"注冊"
>
</td>
</tr>
</table>
</form>
</body>
</html>
|
到此,用戶注冊功能就算是開發完成了!
下面測試一下開發好的用戶注冊功能:
輸入URL地址,訪問register.jsp頁面,
如果輸入的表單項不符合校驗規則,那么是無法進行注冊的
3.4.2、 開發登錄功能
1、在me.gacl.web.UI包下寫一個LoginUIServlet為用戶提供登錄界面
LoginUIServlet收到用戶請求后,就跳到login.jsp
LoginUIServlet的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
me.gacl.web.UI;
import
java.io.IOException;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
/**
* @author gacl
* LoginUIServlet負責為用戶輸出登陸界面
* 當用戶訪問LoginUIServlet時,就跳轉到WEB-INF/pages目錄下的login.jsp頁面
*/
public
class
LoginUIServlet
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
request.getRequestDispatcher(
"/WEB-INF/pages/login.jsp"
).forward(request, response);
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
2、在/WEB-INF/pages/目錄下編寫用戶登錄的jsp頁面login.jsp
login.jsp頁面的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<%@ page language=
"java"
pageEncoding=
"UTF-"
%>
<!DOCTYPE HTML>
<html>
<head>
<title>用戶登陸</title>
</head>
<body>
<form action=
"${pageContext.request.contextPath }/servlet/LoginServlet"
method=
"post"
>
用戶名:<input type=
"text"
name=
"username"
><br/>
密碼:<input type=
"password"
name=
"password"
><br/>
<input type=
"submit"
value=
"登陸"
>
</form>
</body>
</html>
|
login.jsp中的<form action="${pageContext.request.contextPath}/servlet/LoginServlet" method="post">指明表單提交后,交給LoginServlet進行處理。
3、在me.gacl.web.controller包下編寫用於處理用戶登錄的LoginServlet
LoginServlet的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package
me.gacl.web.controller;
import
java.io.IOException;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
me.gacl.domain.User;
import
me.gacl.service.IUserService;
import
me.gacl.service.impl.UserServiceImpl;
/**
* 處理用戶登錄的servlet
* @author gacl
*
*/
public
class
LoginServlet
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
//獲取用戶填寫的登錄用戶名
String username = request.getParameter(
"username"
);
//獲取用戶填寫的登錄密碼
String password = request.getParameter(
"password"
);
IUserService service =
new
UserServiceImpl();
//用戶登錄
User user = service.loginUser(username, password);
if
(user==
null
){
String message = String.format(
"對不起,用戶名或密碼有誤!!請重新登錄!秒后為您自動跳到登錄頁面!!<meta http-equiv='refresh' content=';url=%s'"
,
request.getContextPath()+
"/servlet/LoginUIServlet"
);
request.setAttribute(
"message"
,message);
request.getRequestDispatcher(
"/message.jsp"
).forward(request, response);
return
;
}
//登錄成功后,就將用戶存儲到session中
request.getSession().setAttribute(
"user"
, user);
String message = String.format(
"恭喜:%s,登陸成功!本頁將在秒后跳到首頁!!<meta http-equiv='refresh' content=';url=%s'"
,
user.getUserName(),
request.getContextPath()+
"/index.jsp"
);
request.setAttribute(
"message"
,message);
request.getRequestDispatcher(
"/message.jsp"
).forward(request, response);
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
到此,用戶登錄的功能就算是開發完成了。
下面測試一下開發好的用戶登錄功能,輸入URL地址訪問login.jsp頁面,輸入正確的用戶名和密碼進行登錄
如果輸入的用戶名和密碼錯誤,那么就無法登錄成功
3.4.3、 開發注銷功能
在me.gacl.web.controller包下編寫用於處理用戶注銷的LogoutServlet
LogoutServlet的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package
me.gacl.web.controller;
import
java.io.IOException;
import
java.text.MessageFormat;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
LogoutServlet
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
//移除存儲在session中的user對象,實現注銷功能
request.getSession().removeAttribute(
"user"
);
//由於字符串中包含有單引號,在這種情況下使用MessageFormat.format方法拼接字符串時就會有問題
//MessageFormat.format方法只是把字符串中的單引號去掉,不會將內容填充到指定的占位符中
String tempStr = MessageFormat.format(
"注銷成功!!秒后為您自動跳到登錄頁面!!<meta http-equiv='refresh' content=';url={}'/>"
,
request.getContextPath()+
"/servlet/LoginUIServlet"
);
System.out.println(tempStr);
//輸出結果:注銷成功!!秒后為您自動跳到登錄頁面!!<meta http-equiv=refresh content=;url={}/>
System.out.println(
"---------------------------------------------------------"
);
/**
* 要想解決"如果要拼接的字符串包含有單引號,那么MessageFormat.format方法就只是把字符串中的單引號去掉,不會將內容填充到指定的占位符中"這個問題,
* 那么可以需要使用單引號引起來的字符串中使用個單引號引起來,例如:"<meta http-equiv=''refresh'' content='';url={}''/>"
* 這樣MessageFormat.format("<meta http-equiv=''refresh'' content='';url={}''/>","index.jsp")就可以正常返回
* <meta http-equiv=''refresh'' content='';url=index.jsp'/>
*/
String tempStr = MessageFormat.format(
"注銷成功!!秒后為您自動跳到登錄頁面!!<meta http-equiv=''refresh'' content='';url={}''/>"
,
request.getContextPath()+
"/servlet/LoginUIServlet"
);
/**
* 輸出結果:
* 注銷成功!!秒后為您自動跳到登錄頁面!!
* <meta http-equiv='refresh' content=';url=/webmvcframework/servlet/LoginUIServlet'/>
*/
System.out.println(tempStr);
String message = String.format(
"注銷成功!!秒后為您自動跳到登錄頁面!!<meta http-equiv='refresh' content=';url=%s'/>"
,
request.getContextPath()+
"/servlet/LoginUIServlet"
);
request.setAttribute(
"message"
,message);
request.getRequestDispatcher(
"/message.jsp"
).forward(request, response);
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
用戶登錄成功后,會將登錄的用戶信息存儲在session中,所以我們要將存儲在session中的user刪除掉,這樣就可以實現用戶注銷了。
用戶登錄成功后就會跳轉到index.jsp頁面,在index.jsp頁面中放一個【退出登陸】按鈕,當點擊【退出登陸】按鈕時,就訪問LogoutServlet,將用戶注銷。
index.jsp的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<%@ page language=
"java"
pageEncoding=
"UTF-"
%>
<%--為了避免在jsp頁面中出現java代碼,這里引入jstl標簽庫,利用jstl標簽庫提供的標簽來做一些邏輯判斷處理 --%>
<!DOCTYPE HTML>
<html>
<head>
<title>首頁</title>
<script type=
"text/javascript"
>
function doLogout(){
//訪問LogoutServlet注銷當前登錄的用戶
window.location.href=
"${pageContext.request.contextPath}/servlet/LogoutServlet"
;
}
</script>
</head>
<body>
<h>孤傲蒼狼的網站</h>
<hr/>
<c:
if
test=
"${user==null}"
>
<a href=
"${pageContext.request.contextPath}/servlet/RegisterUIServlet"
target=
"_blank"
>注冊</a>
<a href=
"${pageContext.request.contextPath}/servlet/LoginUIServlet"
>登陸</a>
</c:
if
>
<c:
if
test=
"${user!=null}"
>
歡迎您:${user.userName}
<input type=
"button"
value=
"退出登陸"
onclick=
"doLogout()"
>
</c:
if
>
<hr/>
</body>
</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層