欢迎来到我的主页:【一只认真写代码的程序猿】
本篇文章收录于专栏【JSP相关】
如果这篇文章对你有帮助,希望点赞收藏加关注啦~
本文所有内容相关代码都可在以下仓库中找到:
1 JSP实现Login
1.1 项目结构(分层架构)
为了防止出现过多bug,这里使用jdk11和tomcat8来完成。
注:这里用了手动导包(很不好的习惯,我个人主要是想熟悉一下手动导包的流程,仅此而已,实际开发请我完全按照标准开发流程使用maven进行包管理。),本项目的最终版本中,lib都是通过pom.xml进行导入的。
包结构:
com.ynu.edu/ ├── controller/ ├── entity/ ├── mapper/ ├── service/ ├── util/ ├── vo/ ├── resources/ ├── webapp/ │ ├── css/ │ ├── js/ │ ├── WEB-INF/ │ ├── jsp/ │ │ ├── index.jsp │ │ └── login.jsp │ └── Mv 编写逻辑.md └── test/
细分:
com.ynu.edu/ ├── controller/ │ ├── LogoutServlet.java │ └── UserServlet.java │ ├── entity/ │ └── User.java │ ├── mapper/ │ └── UserMapper.java │ ├── service/ │ └── UserService.java │ ├── util/ │ ├── GetSqlSession.java │ └── StringUtil.java │ ├── vo/ │ └── MessageModel.java │ ├── resources/ │ ├── com.ynu.edu.mapper/ │ │ ├── UserMapper.xml │ │ └── mybatis-config.xml │ └── mysql.properties │ ├── webapp/ │ ├── css/ │ ├── js/ │ │ └── jquery-3.4.1.js │ ├── WEB-INF/ │ │ ├── lib/ │ │ ├── web.xml │ │ └── index.jsp │ ├── login.jsp │ └── M+ 编写逻辑.md │ └── test/ ├── java/ │ └── TestSession.java └── resources/
1.2 配置文件
1.2.1 UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ynu.edu.mapper.UserMapper"> <select id="queryUserByName" parameterType="String" resultType="com.ynu.edu.entity.User"> SELECT * FROM user WHERE userName = #{userName} </select> </mapper>
1.2.2 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org/DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="mysql.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <package name="com.ynu.edu.mapper"/> </mappers> </configuration>
1.2.3 mysql.properties
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/user?useSSL=false&serverTimezone=UTC username=root password=mysql123
1.2.4 手动导入jar包(不规范)
手动导入jar包是十分不规范的,但是遇到一些极端情况我们只能这样做。这样仅供本人自己复习用,保证知识面的完整性。
实际使用maven进行包管理,操作如下:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency>
1.3 功能开发逻辑梳理
1. 数据库user表自行准备 2. 前台页面 登录页面: login.jsp 用户登录:JS校验 登录表单验证 1. 给登录按钮绑定点击事件 2. 获取uname和upwd 3. 判断是否为空(先姓名、后密码),span标签给出提示 4. 都不为空,手动提交表单 首页 3. 后台实现(一个优秀的后台代码是不能相信前台代码的) 登录功能 1. 接收客户端的请求(userName、pwd) 2. 既然不能相信前台代码,那就要做null判断 但是市面上我们发现有一些软件如果你有一项信息没填,会把你的所有已填的信息都清空,非常不好。 解释:注册时候填账号密码、邮箱等,邮箱没填,把你已经填好的账号密码也清空了,是因为后台做的是直接跳转回初始页面,导致你已填好的数据丢失。 所以这里我们要做数据回显。 如果参数为空,通过MessageModel返回结果(设置state(success or false)、提示信息、回显数据;直接return 将消息模型对象设置到Request作用域里面,做请求转发跳转登录页面。 3. 登录判断习惯:单独判断userName和pwd,不要出现“用户名或密码错误”这样的错误提示,非常不友好。具体原因请自行想象 代码编写思路: 1.接收客户端的请求(接收参数:姓名、密码) 2.参数的非空判断 if NULL 通过消息模型对象返回结果(设置状态、设置提示信息、回显数据) 将消息模型对象设置到request作用域中请求转发 跳转到登录页面 return 3.通过用户姓名查询用户对象 4.判断用户对象是否为空 if NULL 通过消息模型对象返回结果(设置状态、设置提示信息、回显数据) 将消息模型对象设置到request作用域中请求转发 跳转到登录页面 return 5.将数据库中查询到的用户密码与前台传递的密码作比较 if not equal 通过消息模型对象返回结果(设置状态、设置提示信息、回显数据) 将消息模型对象设置到request作用域中 请求转发跳转到登录页面 if equal 登录成功 将用户信息设置到session作用域中(因为你要知道是哪个用户登录,每个用户登录到不同的页面) 重定向跳转到首页 分层结构: Controller:接收请求、相应结果 1. 接受客户端请求(接收参数:name、pwd) 2. 调用Service层的方法,返回MessageModel 3. 判断MessageModel的状态码 if 失败:将消息模型对象设置到request作用域 if 成功:将消息模型中的用户信息设置到session中,重定向到index.jsp 4. 请求转发跳转到登录页面 Service:业务逻辑 1. 参数的非空判断 if NULL:状态码、提示信息、回显数据设置到MessageModel中,return 2. 调用dao层查询方法,通过uname查询用户对象 3. 判断用户对象是否为空 状态码、提示信息、回显数据设置到MessageModel中,return 4. 判断数据库中查询的和前台的uname和pwd进行对比 5. 登录成功:将success状态、提示信息、用户对象舍之道MessageModel对象中,return Mapper层(DAO): 定义对应的接口 4. 分层思想:高内聚低耦合 Controller层:接收请求、调用Service层、响应结果 Service层:业务逻辑判断 Mapper层:接口类、数据库相关操作、mapper.xml Entity(Po、Model):JAVABean实体 Util层:工具类 Test:测试类、方法
1.4 测试Session
1.4.1 User类:
package com.ynu.edu.entity; /** * @ClassName User * @Description 用户类 * @Author Echo-Nie * @Date 2025/1/17 2:28 * @Version V1.0 */ public class User { private Integer userId; private String userName; private String pwd; private int age; //getter and setter }
1.4.2 UserMapper:
package com.ynu.edu.mapper; import com.ynu.edu.entity.User; public interface UserMapper { User queryUserByName(String userName); }
1.4.3 GetSqlSession:
package com.ynu.edu.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * @ClassName GetSqlSession * @Description 获取数据库session * @Author Echo-Nie * @Date 2025/1/17 2:44 * @Version V1.0 */ public class GetSqlSession { public static SqlSession createSqlSession(){ SqlSessionFactory sqlSessionFactory = null; InputStream inpute = null; SqlSession session = null; try{ String resource = "mybatis-config.xml"; inpute= Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inpute); session = sqlSessionFactory.openSession(); return session; }catch (IOException e){ e.printStackTrace(); return null; } } }
1.4.4 测试SqlSession
import com.ynu.edu.entity.User; import com.ynu.edu.mapper.UserMapper; import com.ynu.edu.util.GetSqlSession; import org.apache.ibatis.session.SqlSession; import org.junit.jupiter.api.Test; /** * @ClassName TestSession * @Description 测试获取user * @Author Echo-Nie * @Date 2025/1/17 13:46 * @Version V1.0 */ public class TestSession { @Test public void Test1(){ SqlSession session = GetSqlSession.createSqlSession(); UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.queryUserByName("admin"); System.out.println(user); } //输出如下: //com.ynu.edu.entity.User@5c44c582 //Process finished with exit code 0 }
1.5 编写项目代码
1.5.1 消息模型对象
package com.ynu.edu.vo; /** * @ClassName MessageModel * @Description 消息模型对象,做数据响应的;200表示成功,400表示失败 * 用字符串表示 * 回显数据:Object * @Author Echo-Nie * @Date 2025/1/17 14:11 * @Version V1.0 */ public class MessageModel { private String code = "200";//状态码,200成功,400失败 private String msg = "成功"; private Object object; //getter setter }
1.5.2 编写Servlet
package com.ynu.edu.controller; import com.ynu.edu.service.UserService; import com.ynu.edu.vo.MessageModel; 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 java.io.IOException; /** * @ClassName UserServlet * @Description * @Author Echo-Nie * @Date 2025/1/17 14:15 * @Version V1.0 */ @WebServlet("/login") public class UserServlet extends HttpServlet { //实例化UserService对象 private UserService userService = new UserService(); /** * @return void * @Author Echo-Nie * @Description 用户登录: * 1. 接受客户端请求(接收参数:name、pwd) * 2. 调用Service层的方法,返回MessageModel * 3. 判断MessageModel的状态码 * if 失败:将消息模型对象设置到request作用域 * if 成功:将消息模型中的用户信息设置到session中,重定向到index.jsp * 4. 请求转发跳转到登录页面 * @Date 14:35 2025/1/17 * @Param [request, response] */ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 接受客户端请求(接收参数:name、pwd) String uname = request.getParameter("uname"); String upwd = request.getParameter("upwd"); // 2. 调用Service层的方法,返回MessageModel MessageModel messageModel = userService.userLogin(uname, upwd); // 3. 判断MessageModel的状态码 if (messageModel.getCode().equals("200")) {//成功 request.getSession().setAttribute("user", messageModel.getObject()); response.sendRedirect("index.jsp"); // 使用重定向 } else {//失败 request.setAttribute("messageModel", messageModel); request.getRequestDispatcher("login.jsp").forward(request, response); } } }
1.5.3 编写Service
package com.ynu.edu.service; import com.ynu.edu.entity.User; import com.ynu.edu.mapper.UserMapper; import com.ynu.edu.util.GetSqlSession; import com.ynu.edu.util.StringUtil; import com.ynu.edu.vo.MessageModel; import org.apache.ibatis.session.SqlSession; /** * @ClassName UserService * @Description 登录页面的业务逻辑层 * @Author Echo-Nie * @Date 2025/1/17 14:14 * @Version V1.0 */ public class UserService { /** * @Author Echo-Nie * @Description 1. 参数的非空判断 if NULL:状态码、提示信息、回显数据设置到MessageModel中,return 2. 调用dao层查询方法,通过uname查询用户对象 3. 判断用户对象是否为空 状态码、提示信息、回显数据设置到MessageModel中,return 4. 判断数据库中查询的和前台的uname和pwd进行对比 5. 登录成功:将success状态、提示信息、用户对象舍之道MessageModel对象中,return * @Date 14:43 2025/1/17 * @Param [uname, upwd] * @return com.ynu.edu.vo.MessageModel **/ public MessageModel userLogin(String uname, String upwd) { MessageModel messageModel = new MessageModel(); // 数据回显 User u = new User(); u.setUserName(uname); u.setPwd(upwd); messageModel.setObject(u); // 1. 参数的非空判断 if(StringUtil.isEmpty(uname)||StringUtil.isEmpty(upwd)){ // if NULL:状态码、提示信息、回显数据设置到MessageModel中,return messageModel.setCode("400"); messageModel.setMsg("用户名和密码不能为空!!"); } // 2. 调用dao层查询方法,通过uname查询用户对象 SqlSession session = GetSqlSession.createSqlSession(); UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.queryUserByName(uname); // 3. 判断用户对象是否为空 if(user==null){ messageModel.setCode("400"); messageModel.setMsg("用户不存在"); return messageModel; } // 4. 判断数据库中查询的和前台的uname和pwd进行对比 if(!upwd.equals(user.getPwd())){ messageModel.setCode("400"); messageModel.setMsg("密码错误!"); return messageModel; } messageModel.setObject(user); return messageModel; } }
1.5.4 login.jsp(不含css)
<%-- User: Echo-Nie Date: 2025/1/17 Time: 1:51 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>用户登录</title> <link rel="stylesheet" type="text/css" href="css/login.css"> </head> <body> <div id="loginForm"> <form action="login" method="post"> <div class="form-group"> <label for="uname">姓名:</label> <input type="text" id="uname" name="uname" value="${messageModel.object.userName}"> </div> <div class="form-group"> <label for="upwd">密码:</label> <input type="password" id="upwd" name="upwd" value="${messageModel.object.pwd}"> </div> <span id="msg" style="font-size: 12px;color: red">${messageModel.msg}</span><br> <button type="submit" id="loginBtn">登录</button> <button type="button">注册</button> </form> </div> <script type="text/javascript" src="js/jquery-3.4.1.js"></script> <script type="text/javascript"> <%-- 登录表单验证 1. 给登录按钮绑定点击事件 2. 获取uname和upwd 3. 判断是否为空(先姓名、后密码),span标签给出提示 4. 都不为空,手动提交表单 --%> $("#loginBtn").click(function () { //获取uname和pwd var uname = $("#uname").val(); var upwd = $("#upwd").val(); if (isEmpty(uname)) { $("#msg").html("用户名为空!"); return; } if (isEmpty(upwd)) { $("#msg").html("密码为空!"); return; } //都不为空才能登录 $("#loginForm").submit(); }); /* 判断字符串是否为空 * */ function isEmpty(str) { return str == null || str.trim() === ""; } </script> </body> </html>