JavaEE 使用Servlet实现简单登录页面
平常我们浏览网页时,有很多情况需要先登录,今天我们就来编写一个简单的登录页面。
我们使用Tomcat服务器,用eclipse进行开发。整个登录流程很简单:
- 用户在登录页面(login.jsp)输入用户名和密码,点击登录;
- 服务器收到用户请求后,搜索数据库,如果用户名和密码匹配,则跳转到欢迎页面(welcome.jsp);否则在登录页面显示相应的错误信息。
效果
我们先来看下最终的效果:
1. 数据库:在数据库中创建一张user表,包括用户ID、用户名、登录密码、在线状态和上次登录时间这5个属性,如下图:

2. 登录页面:一个简单的form表单,包括用户名和密码,如下图:

如果登录时发生错误,则登录页面会显示错误信息,下图显示了密码错误的情况:

3. 欢迎页面:显示用户名和上次登录时间等,如下图:

如果在登录时,使用的用户名已经在线,则会提示如下信息:

思路
我们采用MVC架构,用JavaBean作为模型,jsp页面作为视图,Servlet作为控制器。用户和jsp页面交互,Servlet处理来自用户的请求和向用户发送响应,而真正的数据库操作则交由JavaBean来完成。
模型:JavaBean
由于要操作数据库,我们就先定义一个DBManager类来管理数据库连接(实际中建议使用DBCP):
// DBManager.java
public class DBManager {
private Properties prop;
private static DBManager instance;
public static DBManager getInstance() {
if(instance==null) {
synchronized(DBManager.class) {
if(instance==null)
instance=new DBManager();
}
}
return instance;
}
private DBManager() {
prop=new Properties();
prop.put("driver", "com.mysql.jdbc.Driver");
prop.put("url", "jdbc:mysql://localhost:3306/XXX");
prop.put("user", "XXX");
prop.put("password", "******");
prop.put("useUnicode", "true");
prop.put("characterEncoding", "UTF-8");
prop.put("useSSL", "true");
try {
Class.forName(prop.getProperty("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Connection connect() {
Connection conn=null;
String url=prop.getProperty("url");
try {
conn=DriverManager.getConnection(url, prop);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public void disconnect(Connection conn) {
try {
if(conn!=null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}DBManager类负责连接数据库,构造器方法中对数据库进行了相应配置,数据库我们使用MySQL。connect方法返回一个数据库连接,disconnect方法关闭一个数据库连接。
接下来,我们还需要提供一个LoginHelper类来帮助我们对数据库进行操作:
// LoginHelper.java
public class LoginHelper {
public enum LoginState {
LOG_IN_SUCCESS, // 登录成功
PASSWORD_ERROR, // 密码错误
USER_NOT_EXIST, // 用户不存在
USER_IS_EMPTY, // 用户名为空
PASSWORD_IS_EMPTY, // 密码为空
}
private static SimpleDateFormat sdf=
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static LoginState login(HttpSession session,
String name, String password) throws SQLException {
if(name==null || name.equals(""))
return LoginState.USER_IS_EMPTY;
if(password==null || password.equals(""))
return LoginState.PASSWORD_IS_EMPTY;
DBManager manager=DBManager.getInstance();
Connection conn=manager.connect();
try{
Statement state=conn.createStatement();
ResultSet result=state.executeQuery(
"select password, online, date "+
"from user where name='"+name+"';");
if(result.next()) {
if(result.getString(1).equals(password)) {
session.setAttribute("name", name);
session.setAttribute("online", result.getBoolean(2));
session.setAttribute("date", result.getString(3));
state.execute("update user set online=true, date='"+
sdf.format(new Date())+"' where name='"+name+"';");
return LoginState.LOG_IN_SUCCESS;
}
else
return LoginState.PASSWORD_ERROR;
}
else
return LoginState.USER_NOT_EXIST;
} finally {
manager.disconnect(conn);
}
}
}LoginHelper类的静态方法login将负责检验用户名和密码。如果用户名和密码匹配,则在session范围内设置name、online和date三个属性,这三个属性将会显示在欢迎页面,然后返回LOG_IN_SUCCESS标识。如果发生了错误,例如密码错误或用户不存在等,则返回相应的错误标识。
控制器:Servlet
在项目中新建一个Servlet,起名为LoginServlet,让它重写父类的service方法,并使用@WebServlet注解对它进行配置:
// LoginServlet.java
@WebServlet(name="LoginServlet", urlPatterns="/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("GBK");
String error=null;
RequestDispatcher dispatcher;
HttpSession session=request.getSession(true);
String user=request.getParameter("user");
String password=request.getParameter("password");
try {
switch(LoginHelper.login(session, user, password)) {
case LOG_IN_SUCCESS:
dispatcher=request.getRequestDispatcher("/welcome.jsp");
dispatcher.forward(request, response);
break;
case PASSWORD_ERROR:
error="密码错误!";
break;
case USER_NOT_EXIST:
error="用户不存在!";
break;
case USER_IS_EMPTY:
error="用户名不能为空!";
break;
case PASSWORD_IS_EMPTY:
error="密码不能为空!";
break;
default: break;
}
} catch (SQLException e) {
error=e.getMessage();
} finally {
if(error!=null) {
request.setAttribute("error", error);
dispatcher=request.getRequestDispatcher("/login.jsp");
dispatcher.forward(request, response);
}
}
}
}可以看到,service方法中主要就是对LoginHelper.login方法的返回值进行处理。如果是LOG_IN_SUCCESS的情况,则将用户请求转发到welcome.jsp页面;其它情况则将用户请求转发到login.jsp页面,并显示错误信息。
写到这,我们的工作已经差不多完成了,接来下只需要提供两个简单的jsp页面即可。
视图:jsp页面
就像我们上面所说的那样,用户是和jsp页面进行交互的。由于这只是一个简单的登录页面,我们就将jsp页面写简单点。首先是登录页面:
<!-- login.jsp -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>登录页</title>
</head>
<body>
<span style="color:red;font-weight:bold">
<%
if(request.getAttribute("error")!=null)
out.println(request.getAttribute("error")+"<br>");
%>
</span>
<form id="login" method="post" action="login">
用户名:<input type="text" name="user"><br>
密 码:<input type="text" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>login.jsp主要分为两部分,其一是判断是否有错误信息(由LoginServlet转发而来),其二是一个简单的form表单。用户点击登录后,用户请求将会发送到/login,即LoginServlet(由@WebServlet注解中的urlPatterns设置),LoginServlet作为控制器,将调用模型(LoginHelper)对数据库进行操作,再根据结果来显示相应的试图(login.jsp或welcome.jsp)。
下面是欢迎页面:
<!-- welcome.jsp -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>欢迎页</title>
</head>
<body>
<%
String name=(String) session.getAttribute("name");
boolean online=(Boolean) session.getAttribute("online");
String date=(String) session.getAttribute("date");
out.print("亲爱的"+name+",欢迎您!");
if(online)
out.println("您的账号于"+date+"在别处登录,如果不是您所为,建议您修改密码。");
else
out.println("上次登录时间为"+date+"。");
%>
</body>
</html>welcome.jsp页面会根据online的值来决定显示什么内容。如果当前只有一人在线,则简单显示上次登录时间;否则提醒用户账号不安全。
小结
借助这个简单的登录页面,我们展示了如何使用MVC架构来编写web应用。当然,这只是一个“玩具式”的程序,在此基础上,我们还可以设置cookie记忆用户名、使用filter对用户请求进行过滤、注册listener对session的整个生命周期进行监听(注意到我们并没有提供用户下线的功能)等等。
此项目已托管到github上:https:///jzyhywxz/WebDemo.git
















