JavaServerPages篇03 —— 手搓Login

欢迎来到我的主页:【一只认真写代码的程序猿

本篇文章收录于专栏【JSP相关

如果这篇文章对你有帮助,希望点赞收藏加关注啦~

 本文所有内容相关代码都可在以下仓库中找到:

GitHub - Echo-Nie/JSPLearn


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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值