您的位置:首页 > 其它

用户注册登录案例

2017-06-16 13:17 393 查看

综合案例

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



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


整个流程如下



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.getRequestDispatcher
response.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. 用户退出登录

销毁当前的session

重定向到登录界面

在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属性。数据也是空的,毫无意义。

看下截图

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



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



账号和密码不对应时



成功登录时候



by @sunhaiyu

2017.4.12
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: