一、 案例需求
需求:
实现用户登录与退出登录功能,要求一个用户只能在一处登录。 完成对用户表的 CRUD 操作。 使用技术: JSP、Servlet、Filter、Listener、JDBC、MySQL
创建数据库表
CREATE TABLE `users` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(30) DEFAULT NULL,
`userpwd` varchar(30) DEFAULT NULL,
`usersex` varchar(2) DEFAULT NULL,
`phonenumber` varchar(30) DEFAULT NULL,
`qqnumber` varchar(20) DEFAULT NULL,
PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
搭建环境
添加jar包
创建包
com.bjsxt
-commons 工具类
-exception 自定义异常
-pojo 实体
-dao 访问数据库持久层代码(Date Access Object)
-service 业务层代码
-web web组件
-filter
-servlet
-listener
创建POJO(实体)
package com.bjsxt.pojo;
public class Users {
private int userid;
private String username;
private String userpwd;
private String usersex;
private String phonenumber;
private String qqnumber;
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
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 getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
public String getPhonenumber() {
return phonenumber;
}
public void setPhonenumber(String phonenumber) {
this.phonenumber = phonenumber;
}
public String getQqnumber() {
return qqnumber;
}
public void setQqnumber(String qqnumber) {
this.qqnumber = qqnumber;
}
}
创建JDBC工具类
配置文件 db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bjsxt?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=yang1234
JdbcUtils JDBC连接工具类
package com.bjsxt.commons;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ResourceBundle;
public class JdbcUtils {
private static String driver;
private static String url;
private static String username;
private static String userpwd;
static {
//1、解析db配置文件
ResourceBundle resourceBundle = ResourceBundle.getBundle("db");
//2、读取配置文件中4个基本信息
driver = resourceBundle.getString("jdbc.driver");
url = resourceBundle.getString("jdbc.url");
username = resourceBundle.getString("jdbc.username");
userpwd = resourceBundle.getString("jdbc.password");
//3、加载mysql驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接的方法
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(url,username,userpwd);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 断开连接的方法
*/
public static void closeConnection(Connection conn){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
二、业务实现
用户登录
创建用户登录页面
login.jsp登录页面
<%--
Created by IntelliJ IDEA.
User: 20878
Date: 2022/1/23
Time: 12:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv=n"Content-Type" content="text/html; charset=utf-8" />
<title>欢迎登录后台管理系统</title>
<link href="css/style.css" rel="stylesheet" type="text/css" />
<script language="JavaScript" src="js/jquery.js"></script>
<script src="js/cloud.js" type="text/javascript"></script>
<script language="javascript">
if(window.parent.length>0){
window.parent.location="login.jsp";
}
$(function(){
$('.loginbox').css({'position':'absolute','left':($(window).width()-692)/2});
$(window).resize(function(){
$('.loginbox').css({'position':'absolute','left':($(window).width()-692)/2});
})
});
</script>
</head>
<body style="background-color:#1c77ac; background-image:url(images/light.png); background-repeat:no-repeat; background-position:center top; overflow:hidden;">
<div id="mainBody">
<div id="cloud1" class="cloud"></div>
<div id="cloud2" class="cloud"></div>
</div>
<div class="logintop">
<ul>
<li><a href="#">回首页</a></li>
<li><a href="#">帮助</a></li>
<li><a href="#">关于</a></li>
</ul>
</div>
<div class="loginbody">
<div class="loginbox loginbox2">
<form action="login.do" method="post">
<ul>
<li><input name="username" type="text" class="loginuser" value="admin" onclick="JavaScript:this.value=''"/></li>
<li><input name="userpwd" type="text" class="loginpwd" value="密码" onclick="JavaScript:this.value=''"/></li>
<li class="yzm">
<span><input name="" type="text" value="验证码" onclick="JavaScript:this.value=''"/></span><cite>X3D5S</cite>
</li>
<li><input name="" type="submit" class="loginbtn" value="登录" onclick="javascript:window.location='main.html'" /></li>
</ul>
</form>
</div>
</div>
</body>
</html>
创建业务持久层(数据库操作)
UserLoginDao接口
package com.bjsxt.dao;
import com.bjsxt.pojo.Users;
public interface UserLoginDao {
public Users SelectUsersByUserNameAndUserPwd(String username,String userpwd);
}
用户登录的数据库查询
package com.bjsxt.dao;
import com.bjsxt.commons.JdbcUtils;
import com.bjsxt.pojo.Users;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserLoginDaoImp1 implements UserLoginDao{
/**
* 用户登录的数据库查询
* @param username
* @param userpwd
* @return
*/
@Override
public Users SelectUsersByUserNameAndUserPwd(String username, String userpwd) {
Users users = null;
Connection conn = null;
try {
//1、获取数据库的连接
conn = JdbcUtils.getConnection();
//2、预编译sql语句,返回PrepareStatement的实例
PreparedStatement ps = conn.prepareStatement
("select * from users where username=? and userpwd = ?");
//3、填充占位符
ps.setString(1,username);
ps.setString(1,userpwd);
//4、执行
ResultSet resultSet = ps.executeQuery();
//5、将查询结果放入users对象
while (resultSet.next()){
users = new Users();
users.setUsername(resultSet.getString("username"));
users.setUserpwd(resultSet.getString("userpwd"));
users.setUserid(resultSet.getInt("userid"));
users.setUsersex(resultSet.getString("usersex"));
users.setQqnumber(resultSet.getString("qqnumber"));
users.setPhonenumber(resultSet.getString("phonenumber"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
}
return users;
}
}
创建登录业务的业务层
创建自定义异常
package com.bjsxt.exception;
/**
* 用户登录状态的自定义异常
*/
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException() {
}
public UserNotFoundException(String message) {
super(message);
}
public UserNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
创建业务层
public interface UserLoginService {
Users userLogin(String username,String userpwd);
}
package com.bjsxt.service;
import com.bjsxt.dao.UserLoginDao;
import com.bjsxt.dao.UserLoginDaoImp1;
import com.bjsxt.exception.UserNotFoundException;
import com.bjsxt.pojo.Users;
/**
* 用户登录业务
*/
public class UserLoginServiceImp1 implements UserLoginService {
@Override
public Users userLogin(String username, String userpwd) {
//实例化业务持久层类
UserLoginDao userLoginDao = new UserLoginDaoImp1();
//调用业务持久层查询方法
Users users = userLoginDao.SelectUsersByUserNameAndUserPwd(username, userpwd);
if (users==null){
throw new UserNotFoundException("用户名或密码有误!");
}
return users;
}
}
创建登录业务的 web 层
创建 Servlet
package com.bjsxt.web.servlet;
import com.bjsxt.exception.UserNotFoundException;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UserLoginService;
import com.bjsxt.service.UserLoginServiceImp1;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login.do")
public class UserLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取参数
String username = req.getParameter("username");
String userpwd = req.getParameter("userpwd");
try {
UserLoginService userLoginService = new UserLoginServiceImp1();
Users users = userLoginService.userLogin(username, userpwd);
//建立客户端服务端会话状态
HttpSession session = req.getSession();
session.setAttribute("users",users);
//使用重定向跳转首页
resp.sendRedirect("main.jsp");
} catch (UserNotFoundException e) {
//users未找到时 请求跳转 通过jsp页面响应错误信息
req.setAttribute("msg",e.getMessage());
req.getRequestDispatcher("login.jsp").forward(req,resp);
}catch (Exception e){
//使用重定向跳转页面
resp.sendRedirect("error.jsp");
}
}
}
添加登录后的首页
<%--
Created by IntelliJ IDEA.
User: 20878
Date: 2022/1/23
Time: 17:15
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>信息管理系统界面</title>
</head>
<frameset rows="*,31" cols="*" frameborder="no" border="0" framespacing="0">
<frameset cols="187,*" frameborder="no" border="0" framespacing="0">
<frame src="left.jsp" name="leftFrame" scrolling="No" noresize="noresize" id="leftFrame" title="leftFrame" />
<frame src="index.jsp" name="rightFrame" id="rightFrame" title="rightFrame" />
</frameset>
<frame src="footer.jsp" name="bottomFrame" scrolling="No" noresize="noresize" id="bottomFrame" title="bottomFrame" />
</frameset>
<noframes><body>
</body></noframes>
</html>
创建登录业务的Filter
package com.bjsxt.web.filter;
import com.bjsxt.commons.Constants;
import com.bjsxt.pojo.Users;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 判断当前客户端浏览器是否登录的 Filter
*/
@WebFilter(urlPatterns = {"*.do","*.jsp"})
public class UserLoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
//获取请求信息的url
StringBuffer url = httpServletRequest.getRequestURL();
//如果url为登录界面则放行,否则通过session的属性是否含有user判断是否放行
if (url.indexOf("login.jsp")!=-1||url.indexOf("login.do")!=-1){
filterChain.doFilter(servletRequest,servletResponse);
}else {
HttpSession session = httpServletRequest.getSession();
Users user = (Users) session.getAttribute(Constants.USER_SESSION_KEY);
if (user!=null){
//过滤器通行
filterChain.doFilter(servletRequest,servletResponse);
}else {
httpServletRequest.setAttribute(Constants.REQUEST_MSG,"不登陆不好使!");
httpServletRequest.getRequestDispatcher("login.jsp").forward(servletRequest,servletResponse);
}
}
}
@Override
public void destroy() {
}
}
用户只能在一处登录
修改处理登录请求的 Servlet
package com.bjsxt.web.servlet;
import com.bjsxt.exception.UserNotFoundException;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UserLoginService;
import com.bjsxt.service.UserLoginServiceImp1;
import javax.servlet.ServletContext;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login.do")
public class UserLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取参数
String username = req.getParameter("username");
String userpwd = req.getParameter("userpwd");
try {
UserLoginService userLoginService = new UserLoginServiceImp1();
Users users = userLoginService.userLogin(username, userpwd);
//建立客户端服务端会话状态
HttpSession session = req.getSession();
session.setAttribute("users",users);
/**
* 实现用户只能在一处登录
*/
//获取全局容器
ServletContext servletContext = this.getServletContext();
//全局容器中存放 属性(Userid,session) ,登录之前通过Userid获取session
// [菜鸟雷区]:同一个用户在不同浏览器的session会不一样
HttpSession temp = (HttpSession)servletContext.getAttribute(users.getUserid() + "");
//如果temp不为null,表明用户已经在另一处登录
if(temp!=null){
//将servletContext对应属性删除
servletContext.removeAttribute(users.getUserid()+"");
//将对应session销毁
temp.invalidate();
}
//然后往 全局容器中添加(Userid,session)属性
servletContext.setAttribute(users.getUserid()+"",session);
//使用重定向跳转首页
resp.sendRedirect("main.jsp");
} catch (UserNotFoundException e) {
//users未找到时 请求跳转 通过jsp页面响应错误信息
req.setAttribute("msg",e.getMessage());
req.getRequestDispatcher("login.jsp").forward(req,resp);
}catch (Exception e){
e.printStackTrace();
//使用重定向跳转页面
resp.sendRedirect("error.jsp");
}
}
}
解决 HttpSession 超时销毁时的异常问题
package com.bjsxt.web.listener;
import com.bjsxt.commons.Constants;
import com.bjsxt.pojo.Users;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 解决 HttpSession 被反复销毁的问题
*/
@WebListener
public class HttpSessionLifeCycleListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
//监听session销毁
HttpSession session = se.getSession();
//获取 ServletContext
ServletContext servletContext = session.getServletContext();
//获取session的Users属性
Users users = (Users) session.getAttribute(Constants.USER_SESSION_KEY);
//删除即将销毁session对应的servletContext,防止二次销毁session报错
servletContext.removeAttribute(users.getUserid()+"");
}
}
用户退出登录
package com.bjsxt.web.servlet;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout.do")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//退出登录则销毁Session
HttpSession session = req.getSession();
session.invalidate();
//重定向到登录界面
resp.sendRedirect("login.jsp");
}
}
添加用户业务
创建添加用户持久层
package com.bjsxt.dao;
import com.bjsxt.pojo.Users;
public interface UserManageDao {
void insertUser(Users users);
}
package com.bjsxt.dao;
import com.bjsxt.commons.JdbcUtils;
import com.bjsxt.pojo.Users;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 用户管理持久层
*/
public class UserManageDaoImpl implements UserManageDao {
@Override
public void insertUser(Users users) {
//获取数据库连接
Connection conn = JdbcUtils.getConnection();
//
try {
PreparedStatement ps = conn.prepareStatement("insert into Users values(default ,?,?,?,?,?,)");
//关闭事务自动提交(此处代码删除无影响,数据库操作要注意事务)
conn.setAutoCommit(false);
ps.setString(1,users.getUsername());
ps.setString(2,users.getUserpwd());
ps.setString(3,users.getUsersex());
ps.setString(4,users.getPhonenumber());
ps.setString(5,users.getQqnumber());
ps.execute();
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
JdbcUtils.rollbackConnection(conn);
}finally {
JdbcUtils.closeConnection(conn);
}
}
}