用户注册登录案例

综合案例

实现用户注册、登录、列表显示的功能。符合MVC思想,使用javaee三层架构。如下图。

example_360%E5%8F%8D%E9%A6%88%E6%84%8F%E8%A7%81%E6%88%AA%E5%9B%BE1669080495122116.png

需要用到数据库驱动包以及BeanUtils包。就是这些commons-beanutils、commons-logging、mysql-connector-java

整个流程如下

example_360%E5%8F%8D%E9%A6%88%E6%84%8F%E8%A7%81%E6%88%AA%E5%9B%BE16581118487785.png

0. 数据库连接工具类

package utils;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBCUtil {
    private static String driver;
    private static String url;
    private static String user;
    private static String password;

    // 静态代码块,随着类的加载而加载,只加载一次
    static {
        try {
            Properties prop = new Properties();
            
            
            // 下面这个是本机使用的就填写项目所在位置,但是我们是要部署到服务器的,所以获取WEB-INF/classes目录下的,注意要加"/"
            // InputStream is = new FileInputStream("/example/src/jdbc_setting.properties");
            InputStream is = JDBCUtil.class.getResourceAsStream("/jdbc_setting.properties");
            // load()接收InputStream,所以向上转型
            prop.load(is);

            driver = prop.getProperty("ClassName");
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");
            Class.forName(driver);

            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, user, password);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("创建连接失败!");
        }
        return connection;
    }
    // 释放资源
    // 参数可能为空
    // 调用close要抛出异常,即使出现异常也能关闭
    public void close(Connection conn, Statement state, ResultSet result) {
        try {
            if (result != null) {          
                result.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (state != null) {
                state.close();
                }
            } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                     try {
                        if (conn != null) {
                            conn.close();
                        }
                    } catch (SQLException e) {
                        e.printStackTrace();
                }
            }
        }
    }
}

数据库配置文件

ClassName=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/example
user=root
password=admin

1. 用一个bean来封装注册用户的信息

package domain;

public class User {
    private int id;
    private String name;
    private String password;
    private String email;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", nameString=" + name + ", password=" + password + ", email=" + email + "]";
    }
    
    
}

2. 定义一个借口用来保存User

package dao;


import domain.User;

public interface UserDao {
    void save(User u);
    User getUserByName(String name);
}

2. 实现上述接口

主要实现了插入和查询功能

package dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import dao.UserDao;
import domain.User;
import utils.JDBCUtil;

public class UserDaoImple implements UserDao {

    @Override
    public void save(User u) {
        // 1. 获得连接
        Connection connection = JDBCUtil.getConnection();
        // 2. 准备sql语句
        String sql =  "INSERT INTO "+
                "`example`.`t_user` (`name`, `password`, `email`) "+
                            "VALUES "+
                              "(?, ?, ?);";
        
        // 3. 获得PreparedStatement对象,可防止sql注入
        PreparedStatement preStatement = null;
        try {
            // 先运送sql语句过去预编译
            preStatement = connection.prepareStatement(sql);
            // 4. 设置传送的参数,第一个参数是列数,从1开始
            preStatement.setString(1,  u.getName());
            preStatement.setString(2, u.getPassword());
            preStatement.setString(3, u.getEmail());
            //5. 执行sql
            int result = preStatement.executeUpdate();
            
            // 上面只对一行作用了,添加成功肯定是一行。若 != 1说明没有添加成功
            if(result != 1 ){
                throw new RuntimeException("保存用户失败!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6. 关闭资源
            JDBCUtil.close(connection, preStatement, null);
        }
    }

    @Override
    public User getUserByName(String name) {
        User user = null;
        // 1. 获得连接
        Connection connection = JDBCUtil.getConnection();
        // 2. 写sql语句
        String sql = "SELECT * FROM t_user WHERE name = ?";
        // 3. 获得PreparedStatement
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement(sql);
            // 4. 设置参数
            preparedStatement.setString(1, name);
            // 5. 执行查询
            ResultSet set =  preparedStatement.executeQuery();
            
            // 因为用户名唯一,结果集里只有一条,直接用if就好,可以不用while
            // 6. 将结果集封装到User
            if (set.next()) {
                user = new User();
                 user.setId(set.getInt("id"));
                user.setName(set.getString("name"));
                user.setPassword(set.getString("password"));
                user.setEmail(set.getString("email"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("查询用户失败");
        } finally {
            // 7. 关闭连接,返回User
            JDBCUtil.close(connection, preparedStatement, null);
        }
        return user;
    }

}

4. 用户注册

package service;

import dao.UserDao;
import dao.impl.UserDaoImple;
import domain.User;

public class UserService {
    
    private UserDao  userDao = new UserDaoImple();
    
    public void regist(User u) {
        // 检查用户名是否存在
        User exitsUser = userDao.getUserByName(u.getName());
        // 用户名已经被使用
        if (exitsUser != null) {
            throw new RuntimeException("用户名已经存在!");
        } else {
            // 如果这个名字没有使用,则保存
            userDao.save(u);
        }
    }   
}

5. 检查用户名和密码

package utils;

import java.util.HashMap;
import java.util.Map;

import domain.User;

public class CheckUtils {
    public static Map<String, String> checkUser(User u) {
        Map<String, String> map = new HashMap<>();
        // 验证用户名不为空,"".equals(u.getName())更好。,u.getName().equals("")如果u.getName()为null则不能调用.equals();
        if (u.getName() == null || "".equals(u.getName().trim())) {
            map.put("name", "用户名不能为空!");
        }
        // 验证密码不为空
        if (u.getPassword() == null || "".equals(u.getPassword().trim())) {
            map.put("password", "密码不能为空!");
        }
        return map;
    }
}

6. 注册的servlet

package web;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import domain.User;
import service.UserService;
import utils.CheckUtils;

@WebServlet("/RegistServlet")
public class RegistServlet extends HttpServlet {
    
    private UserService us= new UserService(); 
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1 封装参数到User对象
        User user = new User();
        try {
            // 表单参数封装到user
            BeanUtils.populate(user, request.getParameterMap());
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //  检查有没有错误
        Map<String, String> errors = CheckUtils.checkUser(user);
        // 如果有错误
        if (! errors.isEmpty()) {
            request.setAttribute("errors", errors);
            // 注意是转发而不是重定向,转发过去是一次请求,还是刚才jsp页面。才能收到错误信息。
            // 如果是重定向,重新加载jsp不会收到错误信息
            request.getRequestDispatcher("/regist.jsp").forward(request, response);
            return;
        }
        // 3. 调用Service保存
        try {
            // regist方法里面throw了很多异常,要捕获
            us.regist(user);
            // 4 根据结果,跳转到对应页面,失败就转发到注册页面
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("error", e.getMessage());
            request.getRequestDispatcher("/regist.jsp").forward(request, response);
            return;
        }
        // 成功重定向到登录页面。request.getContextPath()获得项目名/example
        response.sendRedirect(request.getContextPath()+"/login.jsp");
        
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

7. 注册界面和登录界面

注册

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'regist.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    <form action="/example/RegistServlet" method="post" name="form1">
        <table border="1" width="30%" >
        <tr>
            <th colspan="2" align="center" >
                 用户注册
            </th>
        </tr>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="name" /><font color="red" >${requestScope.errors.name }</font></td>
        </tr>
        
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" /><font color="red" >${requestScope.errors.password }</font></td>
        </tr>
        
        <tr>
            <td>邮箱:</td>
            <td><input type="text" name="email" /><font color="red" ></font></td>
        </tr>
        <tr>
            <td colspan="2" align="center" >
                <input type="submit" value="注册" />
            </td>
        </tr>
    </table>
</form>
<font color="red">${requestScope.error }</font>
  </body>
</html>

登录

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'login.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    <form action="/example/LoginServlet" method="post" name="form2">
        <table border="1" width="30%" >
        <tr>
            <th colspan="2" align="center" >
                 用户登录
            </th>
        </tr>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="name" /><font color="red" >${requestScope.errors.name }</font></td>
        </tr>
        
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" /><font color="red" >${requestScope.errors.password }</font></td>
        </tr>
             
        <tr>
            <td colspan="2" align="center" >
                <input type="submit" value="登录" />
            </td>
        </tr>
    </table>
</form>
<font color="red">${requestScope.error }</font>
  </body>
</html>

8. 用户登录

UserService新增用户登录方法

    // 用户登录
    public User login(User u){
        //1 根据用户名,调用dao获得User对象
        User existU = userDao.getUserByName(u.getName());
      // 为空说明还没注册
        if(existU==null){
            //没获得到=> 用户名不存在=> 抛出异常
            throw new RuntimeException("用户名不存在!");
        }
        //2 和数据库的账户密码比对密码是否一致
        if(!existU.getPassword().equals(u.getPassword())){
            //不一致=>密码不正确=>抛出异常
            throw new RuntimeException("密码不正确!");
        }
        //3 能执行到这儿说明已经注册且登录成功。返回的是数据库中User对象
        return existU;
    }

LoginServlet

package web;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import domain.User;
import service.UserService;
import utils.CheckUtils;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    
    private UserService us = new UserService();
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 避免乱码
        request.setCharacterEncoding("UTF-8");
        User u = new User();
        try {
            BeanUtils.populate(u, request.getParameterMap());
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 2.非空校验
    Map<String,String> errors = CheckUtils.checkUser(u);
        if(errors.size()>0){
            request.setAttribute("errors", errors);
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }
        // 3.调用Service
        User existU = null;
        try {
            existU= us.login(u);
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("error", e.getMessage());
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }
        // 4.向session中加入登录标识, 登录用session可以保持用户的状态,不掉线
        request.getSession().setAttribute("user", existU);
        // 5.重定向到列表显示servlet
        response.sendRedirect(request.getContextPath()+"/ListServlet");
    }
  
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

休息一下,看下request.getRequestDispatcherresponse.sendRedirect为什么一个是request的方法,一个是response的方法?

  • 转发是向服务器请求,然后服务器内部进行转发操作,因为是请求所以用request
  • 重定向是浏览器的动作,响应新的页面给用户。所以用的是response

9. 登录后显示用户数据列表

UserDao里新增接口方法

List<User> getAllUsers();

同时UserDaoImple去实现

@Override
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        // 1. 获得连接
        Connection connection = JDBCUtil.getConnection();
        // 2. 写sql语句
        String sql = "SELECT * FROM t_user";
        // 3. 获得PreparedStatement
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement(sql);
            ResultSet set = preparedStatement.executeQuery();

            // 因为用户名唯一,结果集里只有一条,直接用if就好,可以不用while
            // 6. 将结果集封装到User
            while (set.next()) {
                User user = new User();
                user.setId(set.getInt("id"));
                user.setName(set.getString("name"));
                user.setPassword(set.getString("password"));
                user.setEmail(set.getString("email"));
                users.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("查询用户列表失败");
        } finally {
            // 7. 关闭连接,返回User
            JDBCUtil.close(connection, preparedStatement, null);
        }
        return users;
    }

登录成功后的列表显示需要使用servlet从数据库取得用户数据,然后转发到list.jsp显示

package web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import domain.User;
import service.UserService;

@WebServlet("/ListServlet")
public class ListServlet extends HttpServlet {

    private UserService userService = new UserService();

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1. 校验用户是否已经登录
        User user = (User) request.getSession().getAttribute("user");
        // 如果用户下线了, 重定向到登录界面。这里就不是转发了。因为login里面无需接收诸如错误等信息
        if (user == null) {
//          response.sendRedirect(request.getContextPath()+"/login.jsp");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }
        // 调用Service获取所有用户
        List<User> userList = userService.getAllUsers();
        // 转发到jsp显示, 设置属性方便forEach遍历
        request.setAttribute("list", userList);
        request.getRequestDispatcher("WEB-INF/page/list.jsp").forward(request, response);;
        return;
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

lsit.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'list.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    <h1>用户列表</h1>
        <div>欢迎回来!${sessionScope.user.name}</div> <br>
        <a href="/example/LoginoutServlet">退出登录</a>
        <table border="1">
            <tr>
                <th>id</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
            <c:forEach items="${requestScope.list}" var="user" >
                <tr>
                    <td>${pageScope.user.id }</td>
                    <td>${pageScope.user.name }</td>
                    <td>${pageScope.user.email }</td>
                </tr>
            </c:forEach>
        </table>
  </body>
</html>

10. 用户退出登录

  1. 销毁当前的session
  2. 重定向到登录界面

在list.jsp中加入一句

<a href="/example/LoginoutServlet">退出登录</a>

新增一个LoginoutServlet,用户点击上面的超链接后,跳转到这个servlet

package web;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/LoginoutServlet")
public class LoginoutServlet extends HttpServlet {
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 销毁session
        request.getSession().invalidate();
        // 重定向到登录页面让其他用户进行登录
        response.sendRedirect(request.getContextPath() + "/login.jsp");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

至此,小案例完成。

题外话,lsit.jsp为什么不放在WebRoot下?

  • 放在根目录下,用户可以直接输入地址访问。而这时我们登录后才可以看到的界面。所以不能暴露出来让用户直接跳过登录步骤。
  • 就算是放在根目录下,因为没有servlet传过来的userList属性。数据也是空的,毫无意义。

看下截图

用户没有输入账号和密码时

example_360%E5%8F%8D%E9%A6%88%E6%84%8F%E8%A7%81%E6%88%AA%E5%9B%BE16600904213935.png

用户注册一个已经存在的用户名时

example_360%E5%8F%8D%E9%A6%88%E6%84%8F%E8%A7%81%E6%88%AA%E5%9B%BE16470418457663.png

账号和密码不对应时

example_360%E5%8F%8D%E9%A6%88%E6%84%8F%E8%A7%81%E6%88%AA%E5%9B%BE16410123468669.png

成功登录时候

example_360%E5%8F%8D%E9%A6%88%E6%84%8F%E8%A7%81%E6%88%AA%E5%9B%BE16490203302948.png


by @sunhaiyu

2017.4.12

转载于:https://www.cnblogs.com/sun-haiyu/p/7027016.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值