一、 案例需求
需求:
实现用户登录与退出登录功能,要求一个用户只能在一处登录。 完成对用户表的 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.Driverjdbc.url=jdbc:mysql://localhost:3306/bjsxt?useUnicode=true&characterEncoding=utf8jdbc.username=rootjdbc.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: 20878Date: 2022/1/23Time: 12:11To 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*/@Overridepublic 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);
}
}
}
