javaweb实现用户登陆注册功能实现

  • Post author:
  • Post category:java


JavaWeb实现用户登录注册功能实例

2018年03月08日 17:13:40 阅读数:6822更多

个人分类:

java基础知识

转载自 https://blog.csdn.net/afanti222/article/details/79487167


一、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

创建好的项目如下图(图-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

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地址:

http://localhost:8080/webmvcframework/servlet/RegisterUIServlet

访问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地址:http://localhost:8080/webmvcframework/servlet/LoginUIServlet访问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标签库提供的标签来做一些逻辑判断处理 --%>


<%@ taglib uri=


"

http://java.sun.com/jsp/jstl/core

"


prefix=


"c"


%>


<!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层