模块介绍
- 本实例为用户登录模块,采用Model2模式进行开发,展现了模型层(Model)、视图层(View)和控制层(Controller)。
- 视图层包括:用户注册登录页面(login.jsp)、用户注册页面(index.jdp)、注册成功页面(saveSuccess.html)、登录失败页面(login_error1.html),对于用户而言,通过这一层与程序进行交互,同时交互后的结果也是通过这一层回应给用户。
- 控制层包括:用户注册和退出Servlet(UserServlet)、用户登录Servlet(LoginServlet),用户对程序的请求以及程序对用户所作出的回应由控制层掌管,本实例中表现为Servlet。当用户发送一个请求时,Servlet将判断用户的请求类型,进而提供相应的业务逻辑处理方法进行处理;请求由程序处理完毕后,又由Servlet控制返回处理的结果信息。
- 模型层包括:封装用户对象(User)、封装用户数据库操作(UserDao)、数据库连接工具(DBUtil),主要由JavaBean组件来充当,为控制层提供服务。
本实例程序结构图如下图所示:
一、数据库设计
- 本实例只涉及一张数据表,名称为tb_user。此表为用户信息表,用于存放用户的注册信息,其结构如下图:
二、JavaBean设计
- 本实例涉及3个主要的JavaBean组件,分别为用户实例对象User、用户数据库操作对象UserDao类、数据库连接工具类DBUtil。
1、用户实体对象
-
Use类用于封装用户实体信息,提供了用户对象的详细信息以及相应的getXXX()与setXXX()方法,在src目录下创建JavaBean包,并在该包下面创建User实体类,代码如下:
-
代码位置:src/javabean/User.java
public class User {
public String username;//用户名
public String password;//密码
public String sex;//性别
public String question;//找回密码问题
public String answer;//找回密码问题答案
public String email;//电子邮箱
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
//省略部分getXXX()与setXXX()方法
2、数据库连接工具类
-
对于经常对数据库操作的一些方法,我们可以将其封装为一个类,在类中提供了相应的操作方法,从而增强了代码的重用性。实例中将繁琐的获取数据库的连接、用户对数据库查询方法、用户对数据库的增删改方法、关闭连接流方法、开启事物、提交事物、回滚事物方法封装到了DBUtil类中,代码如下:
-
代码位置:src/util/DBUtil.java
/**
* JDBC工具类,方便JDBC操作
*/
public class DBUtil {
public static final String Driver="com.mysql.jdbc.Driver";
public static final String URL = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8";
public static final String USERNAME = "hcz";
public static final String PASSWORD = "";
//工具类中的构造方法一般都是私有的,因为工具类中的方法都是静态的,不需要new对象
private DBUtil(){
}
//静态代码块中的程序在类加载的时候执行,只执行一次
static {
try {
Class.forName(Driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 连接数据库
* @return
*/
public static Connection getConnection(){
try {
return DriverManager.getConnection(URL,USERNAME,PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 关闭连接流方法
* @param connection
*/
public static void closeConnevtion(Connection connection){
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void closeConnevtion(Connection connection, PreparedStatement preparedStatement){
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void closeConnevtion(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 开启事物
* @param conn
* @throws SQLException
*/
public static void beginTransaction(Connection conn) throws SQLException {
if (conn!=null){
conn.setAutoCommit(false);
}
}
/**
* 提交事物
* @param conn
* @throws SQLException
*/
public static void commitTransaction(Connection conn) throws SQLException {
if (conn!=null){
conn.commit();
}
}
/**
* 回滚事物
* @param conn
*/
public static void rollbackTransaction(Connection conn){
if (conn!=null){
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
getConnection()方法用于获取数据库连接,返回Connection对象。closeConnevtion()、beginTransaction()、commitTransaction()、 rollbackTransaction()这些方法均为静态方法,可以直接调用。
3、用户对数据库的操作
-
与用户相关的数据库操作方法被封装到UserDao类中,此类中提供了用户登录用到的查询数据库方法和用户注册用到的数据添加到数据库方法。当用户提交注册信息后,需要对用户信息持久化,以保证用户凭其信息可以登录,关键代码如下:
-
代码位置:src/dao/UserDao.java
/**
* 用户注册方法
* @param user
* @return
*/
public int registerUser(User user) {
int count = 0;
//插入用户注册信息的SQL语句
String sql = "insert into tb_user(username,password,sex,question,answer,email) values(?,?,?,?,?,?)";
//通过实体类User获取用户信息
String username = user.getUsername();
String password = user.getPassword();
String sex = user.getSex();
String question = user.getQuestion();
String answer = user.getAnswer();
String email = user.getEmail();
String[] para = {username,password,sex,question,answer,email};
try {
//开启事物
DBUtil.beginTransaction(conn);
ps = conn.prepareStatement(sql);
//对SQL语句的占位符参数进行动态赋值
for (int i = 1; i <= para.length; i++) {
ps.setString(i,para[i-1]);
}
//执行更新操作
count = ps.executeUpdate();
//提交事物
DBUtil.commitTransaction(conn);
} catch (Exception e) {
//回滚事物
DBUtil.rollbackTransaction(conn);
e.printStackTrace();
}finally {
//DataBaseUtil.closeConnevtion(conn,ps);
}
return count;
}
注册成功后,用户即可通过注册的用户名以及密码进行登录。此操作的实质是根据用户所提供的用户名和密码进行查询,如果查询成功
证明在数据库中存在该信息,则登录成功,关键代码如下:
- 代码位置:src/dao/UserDao.java
/**
* 用户登录方法
* @param para
* @return
*/
public boolean loginUser(String[] para) {
//根据用户名和密码查询用户信息
String sql = "select * from tb_user where username=? and password=?";
//判断用户信息是否存在
boolean loginSuccess = false;
try {
//开启事物
DBUtil.beginTransaction(conn);
ps = conn.prepareStatement(sql);
//对SQL语句的占位符参数进行动态赋值
for (int i = 1; i <= para.length; i++) {
ps.setString(i,para[i-1]);
}
//执行查询获取结果集
rs = ps.executeQuery();
//判断结果集是否有效
if (rs.next()){
loginSuccess = true;
}
//提交事物
DBUtil.commitTransaction(conn);
} catch (SQLException e) {
//回滚事物
DBUtil.rollbackTransaction(conn);
e.printStackTrace();
}finally {
//DataBaseUtil.closeConnevtion(conn,ps,rs);
}
return loginSuccess;
}
三、Servlet层设计
- 本实例涉及两个Servlet对象,分别为处理用户注册(UserServlet.java)、退出的Servlet对象(ExitServlet.java)和用户登录的Servlet对象(LoginServlet.java)。
1、用户注册
-
创建名为UserServlet的类,通过doPost()方法对用户注册进行请求处理,关键代码如下:
-
代码位置:src/servlet/UserServlet.java
public class UserServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String type = request.getParameter("type");
/**
* 注册用户
*/
if (type.equals("register")){
register(request,response);
}
}
private void register(HttpServletRequest request, HttpServletResponse response) throws IOException {
//实例化User对象
User user=new User();
//通过获取页面的注册信息然后对user对象进行赋值
user.setUsername(request.getParameter("username"));
user.setPassword(request.getParameter("password"));
user.setSex(request.getParameter("sex"));
user.setQuestion(request.getParameter("question"));
user.setAnswer(request.getParameter("answer"));
user.setEmail(request.getParameter("email"));
//实例化UserDao对象
UserDao dao=new UserDao();
int count = dao.registerUser(user);
//保存成功跳转到成功页面
if(count == 1){
//转发
//request.getRequestDispatcher("/saveSuccess.html").forward(request, response);
//重定向
response.sendRedirect(request.getContextPath() + "/507/saveSuccess.html");
}
out.flush();
out.close();
}
}
处理工程中,首先通过request的getParameter() 方法获取用户注册信息,然后通过UserDao类的registerUser()方法写入数据库中。
2、用户登录
-
创建名为LoginServlet的类,通过doPost()方法对用户注册进行请求处理,关键代码如下:
-
代码位置:src/servlet/LoginServlet.java
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置字符编码
request.setCharacterEncoding("UTF-8");
//获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] para = {username,password};
//创建dao层并调用“用户登录方法”
UserDao dao=new UserDao();
boolean loginSuccess = dao.loginUser(para);
//登陆成功跳转到成功页面,失败跳转到失败页面
if (loginSuccess == true){
request.getSession().setAttribute("username",username);
response.sendRedirect(request.getContextPath()+"/507/login.jsp");
}else {
response.sendRedirect(request.getContextPath()+"/507/login_error.html");
}
}
}
获取用户名和密码后,通过UserDao类的loginUser()方法查询用户信息,如果查询信息存在则用户登录成功,将获取的用户对象的用户名写入Session中,否则进行相应的错误处理。
3、用户退出
-
创建名为ExitServlet的类,通过doGet()方法对用户注册进行请求处理,此操作需要将存放在Session中的User对象的用户名逐出,关键代码如下:
-
代码位置:src/servlet/ExitServlet.java
public class ExitServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String type = request.getParameter("type");
/**
* 退出用户
*/
if (type.equals("userexit")){
//将用户名逐出Session
request.getSession().removeAttribute("username");
//重定向
response.sendRedirect(request.getContextPath()+"/507/login.jsp");
}
}
}
四、视图层设计
- 本实例涉及两个JSP页面和两个HTML页面,JSP页面分别是注册登录管理页面(login.jsp)和注册页面(index.jsp),HTML页面分别是注册成功页面(saveSuccess.html)和登录失败页面(login_error.html)。
1、主页面(注册登录管理页面)
-
名称为login.jsp,在其中提供了用户注册和登录两种功能,关键代码如下:
-
代码位置:web/507/login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
<link href="admin_login.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="admin_login_wrap">
<h1 align="center">注册登录管理</h1>
<div class="adming_login_border">
<div class="admin_input">
<%
String username = (String) request.getSession().getAttribute("username");
if (username != null && !username.isEmpty()){
out.print("欢迎‘"+username+"’用户进入系统");
%>
<input type="button" value="退出" onclick="location.href='/ServletExercise/exitServlet?type=userexit'"/>
<%
}else {
%>
<form action="/ServletExercise/login" method="post">
<ul class="admin_items">
<li>
<label for="user">用户名:</label>
<input type="text" name="username" value="请输入用户名" onfocus="value=''" id="user" size="40" class="admin_input_style" />
</li>
<li>
<label for="pwd">密码:</label>
<input type="password" name="password" value="******" onfocus="value=''" id="pwd" size="40" class="admin_input_style" />
</li>
<li>
<input type="checkbox" name="tenDayAutoLoginFlag" value="ok">十天内免登录
</li>
<li>
<input type="submit" tabindex="3" value="登录" class="btn btn-primary" />
</li>
<li>
<input type="button" tabindex="3" value="注册" onclick="window.location.href='/ServletExercise/507/index.jsp'" class="btn btn-primary" />
</li>
</ul>
</form>
<%
}
%>
</div>
</div>
<p class="admin_copyright"><a tabindex="5" href="#">返回首页</a> © 2020 Powered by <a href="http://jscss.me" target="_blank">有主机上线</a></p>
</div>
</body>
</html>
若用户信息存在,进行直接登录,则此表单以post提交方式将请求发送到LoginServlet,LoginServlet类根据用户提供的用户名和密码进行相应的处理。
2、注册页面
-
名称为index.jsp,在其中提供了用户注册的表单,关键代码如下:
-
代码位置:web/507/index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>输入User类各属性的值</title>
</head>
<body>
<form action="/ServletExercise/userServlet" method="post">
<%--<input type="hidden" name="type" value="saveuser"/>--%>
<input type="hidden" name="type" value="register"/>
<table align="center" border="0">
<tr>
<th colspan="2">请输入注册信息</th>
</tr>
<tr align="center">
<td>用户名:</td>
<td><input type="text" name="username"/></td>
</tr>
<tr align="center">
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr align="center">
<td>性别:</td>
<td>
<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女">女
</td>
</tr>
<tr align="center">
<td>找回密码问题:</td>
<td><input type="text" name="question"></td>
</tr>
<tr align="center">
<td>找回密码问题答案:</td>
<td><input type="text" name="answer"></td>
</tr>
<tr align="center">
<td>邮箱:</td>
<td><input type="text" name="email"></td>
</tr>
<tr align="center">
<td colspan="2">
<input type="submit" value="注册">
<input type="reset" value="重置">
</td>
</tr>
</table>
</form>
</body>
</html>
此表单以post提交方式将请求发送到UserServlet,UserServlet类根据用户提供的信息进行相应的处理。
3、注册成功页面
-
名称为saveSuccess.html,但用户提交注册信息后,经过Servlet层处理后重定向到该页面,并提示用户重新进行登录操作,关键代码如下:
-
代码位置:web/507/saveSuccess.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>成功页面</title>
</head>
<body>
注册成功,请<a href="/ServletExercise/507/login.jsp">重新登录</a>
</body>
</html>
当注册成功后通过超链接到主页面进行登录操作。
4、登录错误页面
-
名称为login_error.html,当用户进行登录操作时输入用户名或者密码错误时重定向到该页面,关键代码如下:
-
代码位置:web/507/login_error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>失败页面</title>
</head>
<body>
登录失败,请<a href="/ServletExercise/507/login.jsp">重新登录</a>
</body>
</html>
当登录失败后重定向到该页面,然后通过超链接到主页面进行登录操作。
五、运行本实例代码
-
主页面
-
已经注册过的用户进行登录操作
-
当点击退出按钮时,销毁用户名退出系统转移到主页面
-
点击注册按钮,进行新用户注册操作
-
当注册成功重定向到注册成功页面
-
当点击重新登录时,如果输错用户名或者密码,则跳转到登录失败页面并提示重新登录
注意:完整代码可到个人博客下载资源里下载