一、业务需求
实现用户登录和退出登录功能,要求一个用户只在一处登录。完成对用户表的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;
四、搭建环境
4.1 创建web项目
4.2 添加jar
用到数据库:MySQL驱动的jar
用到servlet:servlet-api.jar
页面中中使用jstl标签库:jstl标签库jar包
4.3 添加jstl标签库的约束文件
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
五、创建项目包以及工具类
5.1 创建项目包
5.2 创建POJO
package com.zj.pojo; public class User { private int userid; private String username; private String userpwd; private String usersex; private String phonenumber; private String qqnumber; public User() { } public User(int userid, String username, String userpwd, String usersex, String phonenumber, String qqnumber) { this.userid = userid; this.username = username; this.userpwd = userpwd; this.usersex = usersex; this.phonenumber = phonenumber; this.qqnumber = 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; } @Override public String toString() { return "User{" + "userid=" + userid + ", username='" + username + '\'' + ", userpwd='" + userpwd + '\'' + ", usersex='" + usersex + '\'' + ", phonenumber='" + phonenumber + '\'' + ", qqnumber='" + qqnumber + '\'' + '}'; } }
5.3 创建JDBC工具类
在src下创建db.properties属性文件
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=123456
package com.zj.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 password; //初始化数据库驱动,读取db.properties配置文件的信息(static中的资源只会加载一次) static { ResourceBundle resourceBundle = ResourceBundle.getBundle("db"); driver = resourceBundle.getString("jdbc.driver"); url = resourceBundle.getString("jdbc.url"); username = resourceBundle.getString("jdbc.username"); password = resourceBundle.getString("jdbc.password"); //加载数据库驱动 try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //获取连接 public static Connection getConnection(){ Connection con = null; try { con = DriverManager.getConnection(url, username, password); }catch (Exception e){ e.printStackTrace(); } return con; } //关闭连接 public static void closeConnection(Connection con){ try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } //事务回滚 public static void rollbackConnection(Connection con) { try { con.rollback(); } catch (SQLException e) { e.printStackTrace(); } } }
六、用户登录业务的实现
6.1 创建登录页面
将样式文件先复制到web目录下。
在web目录下创建login.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <meta http-equiv="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}); }) }); /*点击验证码图片生成验证码*/ function change() { $("#code").attr("src","ValidateCodeServlet.do?"+Math.random()) } </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"> ${requestScope.msg} <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="password" class="loginpwd" value="" onclick="JavaScript:this.value=''"/></li> <li class="yzm"> <span><input name="code" type="text" value="验证码" onclick="JavaScript:this.value=''"/></span><cite><img id="code" src="ValidateCodeServlet.do" onclick="change()"/></cite> </li> <li><input name="" type="submit" class="loginbtn" value="登录" onclick="javascript:window.location='main.html'"/></li> </ul> </form> </div> </div> </body> </html>
6.2 创建登录业务的持久层
在Dao包下创建UserLoginDao接口,在接口中创建抽象方法selectUserByUserNameAndPassword。
package com.zj.dao; import com.zj.pojo.User; public interface UserLoginDao { public User selectUserByUserNameAndPassword(String userName, String password); }
创建UserLoginDao接口的实现类UserLoginDaoImpl实现接口。
package com.zj.dao.impl; import com.zj.commons.jdbcUtils; import com.zj.dao.UserLoginDao; import com.zj.pojo.User; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; public class UserLoginDaoImpl implements UserLoginDao { /*用户登录实现*/ @Override public User selectUserByUserNameAndPassword(String userName, String password) { User user = null; Connection conn = null; try { conn = jdbcUtils.getConnection(); PreparedStatement ps = conn.prepareStatement("select * from users where username = ? and userpwd = ?"); ps.setString(1, userName); ps.setString(2, password); ResultSet resultSet = ps.executeQuery(); while (resultSet.next()) { user = new User(); user.setUsername(resultSet.getString("username")); user.setUserpwd(resultSet.getString("userpwd")); user.setUsersex(resultSet.getString("usersex")); user.setPhonenumber(resultSet.getString("phonenumber")); user.setQqnumber(resultSet.getString("qqnumber")); } }catch (Exception e) { e.printStackTrace(); } return user; } }
6.3 登录业务的业务层
在Service包下创建UserLoginService接口,在接口中创建抽象方法userLogin。
package com.zj.service; import com.zj.pojo.User; public interface UserLoginService { public User userLogin(String username, String password); }
创建UserLoginService接口的实现类UserLoginServiceImpl实现接口。
package com.zj.service.Impl; import com.zj.dao.UserLoginDao; import com.zj.dao.impl.UserLoginDaoImpl; import com.zj.exception.UserNotFoundException; import com.zj.pojo.User; import com.zj.service.UserLoginService; /*用户登录业务*/ public class UserLoginServiceImpl implements UserLoginService { @Override public User userLogin(String username, String password) { //创建持久层对象 UserLoginDao userLoginDao = new UserLoginDaoImpl(); User user = userLoginDao.selectUserByUserNameAndPassword(username, password); if (user == null) { throw new UserNotFoundException("用户名或密码有误!"); } return user; } }
同时创建异常类UserNotFoundException,当没有查到用户的信息的时候抛出异常,要继承RuntimeException 。
package com.zj.exception; /*用户登录状态的自定义异常*/ public class UserNotFoundException extends RuntimeException { public UserNotFoundException(){ } public UserNotFoundException(String message) { } public UserNotFoundException(String message, Throwable cause) { } }
6.4 创建登录业务的web层
在servlet包下创建UserLoginServlet 。
package com.zj.web.servlet; import com.zj.commons.Constants; import com.zj.exception.UserNotFoundException; import com.zj.pojo.User; import com.zj.service.Impl.UserLoginServiceImpl; import com.zj.service.UserLoginService; 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 doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); try { UserLoginService userLoginService = new UserLoginServiceImpl(); User user = userLoginService.userLogin(username, password); //如果存在user,建立客户端和服务端的会话状态。 HttpSession session = req.getSession(); session.setAttribute(Constants.USER_SESSION_KEY,user); //使用重定向跳转到首页,因为可以改变地址栏的地址 resp.sendRedirect("main.jsp"); }catch (UserNotFoundException e) {//这是我们关心的异常 //用户登陆失败跳转到登录页面 req.setAttribute("msg",e.getMessage()); req.getRequestDispatcher("login.jsp").forward(req,resp); }catch (Exception e) { //处理异常的最后一道防线,处理其他异常 //出现其他错误 resp.sendRedirect("error.jsp"); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
在工具包创建Constants 抽象类(不能被实例化)存放常量。
package com.zj.commons; /*常量抽象类,避免字符串硬编码。不允许被实例化*/ public abstract class Constants { public static String USER_SESSION_KEY = "user"; }
在web目录下创建main.jsp,作为登录成功跳转的页面。其中main.jsp是由index.jsp、left.jsp、footer.jsp构成。
<%@ 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> </html>