5.登录功能的开发

一、前端

1.1首页跳转到登录页面

登录页面是一个单独的页面,我们需要从项目的首页跳转到登录页面。具体实现非常简单,在首页的登录按钮添加点击事件就可以。

    <button id="loginBtn" class="btn btn-danger" type="button" onclick="location.href='user-login.html'"
            style="display: block;">
        登录
    </button>

在登录的标签中添加点击事件,其中location.href是 window.location 对象的一个属性。为它赋值可以使浏览器导航到指定的 URL 地址,在这里点击登录后,让浏览器导航到我们的登录界面。

1.2登录界面处理

在登录页面主要包含用户名和密码,以及登录按钮,其余皆为次要不需要设计。在这里我们需要对输入的登录信息进行处理,主要是点击登录后,将数据返回给后端进行处理,根据相应判断登录成功与否。
为登录按钮添加点击事件响应:

       <div class="mb-3 row px-5">
            <label class="col-2 col-form-label"></label>
            <div class="col-10">
                <button onclick="login()" type="button" class="form-control btn btn-danger btn-lg">登录</button>
            </div>
        </div>

点击按钮,调用login函数进行数据的处理。
下一步实现login函数:

       const login = async () => {
        const u_id = document.querySelector("#u_id").value;
        const u_pwd = document.querySelector("#u_pwd").value;
        if (u_id === "" || u_pwd === "") {
            
            console.log("错误", "账号或密码 不能为空!");
            return;
        }
        const loginObj={
            u_id:u_id,
            u_pwd:u_pwd
        }
        const url = "./user/login";
        //发送POST请求
        const req = await fetch(url, {
            method: "POST",
            headers: {'Content-Type': 'application/json'},//内容类型
            body: JSON.stringify(loginObj)//发送的请求体是json格式的字符串
        });
        if (req.ok) {
            const result = await req.json();
            console.log(result);
            if(result.success){
                
                console.log('成功',"登录成功");
                //延迟执行函数
                setTimeout(()=>{
                    location.href=`index.html`;
                },1200);
            }else{
                console.log('失败',result.message);
            }
        } else {
            console.log(`响应错误!错误代码:${req.status}`);
        }
    }

async说明这是一个有异步操作的函数,之前的内容有提到,这里不再复述。
定义两个变量用来存我们网页输入的登录信息,并进行判空处理,控制台打印输出信息,方便我们后期进行调试,
创建一个对象,用来将两个数据存入对象中,用来向后端发送。
创建变量用来存储路径,存储发送POST请求的路径
使用fetch函数向后端发起请求,可能你们会注意到这里的fetch函数的写法和之前的不同,在这里fetch函数我们定义了请求体.
method: "POST" 表示这是一个 POST 请求方法,是 POST类型,所以在这里我们向后端发送的是POST请求,而之前的我们没有定义请求体,它默认的是GET请求。
headers: {'Content-Type': 'application/json'} 设置了请求头中的 Content-Type 为 application/json,表明请求体的数据格式为 JSON 。
body: JSON.stringify(loginObj) 将一个名为 loginObj 的对象转换为 JSON 格式的字符串,并作为请求体发送。

返回响应的处理:
if (req.ok):检查响应是否成功(一般状态码在是200)。
const result = await req.json();:将响应体解析为 JSON 格式,并将结果存储在 result 变量中。
如果 result.success 为真,表示登录成功,会在 1200 毫秒后跳回到 index.html 页面。
如果 result.success 为假,会在控制台输出登录失败的消息 result.message 。
如果响应不成功(req.ok 为假),会在控制台输出响应错误的代码 req.status 。

到这里,关于前端的开发基本就完成了,接下来要实现后端的功能逻辑,来支持前端。

二、后端

2.1创建User实体类

创建User实体类,用来存放从数据库中查询回来的数据结果,用于返送给前端作为数据显示。
包含信息:用户名和昵称。
代码:

public class User {
    private String u_id;
    private String u_nickname;


    public String getU_id() {
        return u_id;
    }

    public void setU_id(String u_id) {
        this.u_id = u_id;
    }

    public String getU_nickname() {
        return u_nickname;
    }

    public void setU_nickname(String u_nickname) {
        this.u_nickname = u_nickname;
    }

}

一个简单的实体类,不多叙述。

2.2创建UserDto类

创建UserDto类,用来存放从前端发送过来的登录信息,用来从数据库中进行信息的查询。
包含对应的登录信息:用户名和密码
代码:

public class UserDto {
    private String u_id;
    private String u_pwd;

    public String getU_id() {
        return u_id;
    }

    public void setU_id(String u_id) {
        this.u_id = u_id;
    }

    public String getU_pwd() {
        return u_pwd;
    }

    public void setU_pwd(String u_pwd) {
        this.u_pwd = u_pwd;
    }
}

同理不多叙述。
接下来是核心的数据处理。

2.3创建UserServlet类

创建UserServlet类,用来处理前端返回的数据,查询数据发送往前端。
使用注解定义路径:

@WebServlet({
        "/user/login"
})

同理这个类一样继承了HttpServlet,重写doGet和doPost方法:

    @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 path = req.getServletPath();
        System.out.println("Content-Type:" + req.getContentType());
        switch (path) {
            case "/user/login":
                userLogin(req, resp);
                break;
        }
    }

可能有些人是和我写的是相反的,是在doPost方法里面调用doGet方法,最后代码一样能跑,可能会有疑问(其实是我一开始没想明白,哈哈哈)。
其实这个地方都是对前端发起请求的处理,无论那种写法,最后都会运行核心的数据处理代码,无非是一个直接处理请求调用数据处理方法,另一个处理请求在调用另一位请求处理的方法在调用数据处理的方法。可能我说的有点抽象。试着举一个列子就容易理解了。
通过请求处理最终会进行路径的判断,根据req.getServletPath()获取的不同路径执行不同的方法,当然目前这里只有一个路径。最后调用userLogin方法。
所以下一步:
创建userLogin方法,实现数据的处理。

private void userLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        UserDto loginUser = MyWeb.getBeanFromRequest4Json(UserDto.class, req);
        String sql = "select * from t_user where u_id = ? and u_pwd = ?";
        User user = DaoCreater.currentDao().queryUniqueBean(User.class, sql, loginUser.getU_id(), loginUser.getU_pwd());
        if (user != null) {
            //将查询的用户信息放入Session中(每一个用户浏览器对应在服务器中的唯一容器)
            //用于判断用户是否已登录
            req.getSession().setAttribute("CurrUser", user);
            MyWeb.printJson(resp, R.OK());
        } else {
            MyWeb.printJson(resp, R.err("账号或密码错误!"));
        }
    }
}

MyWeb.getBeanFromRequest4Json(UserDto.class, req)从前端发来的请求中获取以 JSON 格式提交的用户数据,并将其转换为 UserDto 类型的对象 loginUser。这样从前端输入的登录信息就获取到了。
定义SQL语句,用来从数据库中查询数据。
DaoCreater.currentDao().queryUniqueBean(User.class, sql, loginUser.getU_id(), loginUser.getU_pwd())会执行sql语句,查询唯一匹配的记录,返回在user对象中。
如果对象不为空,说明用户存在,那么将用户数据存在Session中,以便后续判断用户是否已登录以及其他功能的实现。
MyWeb.printJson(resp, R.OK())将一个表示成功的响应(R.OK())以 JSON 格式输出到给定的 HttpServletResponse 对象 resp 中,用于前端从中获取响应的状态判断是否登录成功。

到这里前后端若没有问题,那么基本上实现了登录的开发。启动项目进行测试。

三、效果演示

,启动项目,点击登录,在跳转后的登录页面我们什么也不做直接点登录,此时用户名和密码皆为空,我们可以在开发人员工具的控制台看到打印出的信息:
在这里插入图片描述
输入错误的信息:
在这里插入图片描述在控制台同样打印输出了相关信息。
最后我们输入正确的登录信息:实际上也打印了登录成功的信息,后面又很快跳转回首页,就没有截图了
至此,登录功能基本实现完成。但是这样的信息提示在控制台,我们要让它在页面上进行提示,所以下一步引入轻提示组件:

四、轻提示组件

<div class="toast-container position-fixed top-0 start-50 translate-middle-x mt
1">
    <div id="toast" class="toast opacity-100 bg-white" >
        <div class="toast-header">
            <strong class="me-auto"></strong>
            <button type="button" class="btn-close"  data-bs-dismiss="toast" >
            </button>
        </div>
        <div class="toast-body"></div>
    </div>
</div>

这是一个组件,我们要转变成变量对象才可以使用。
创建对象和函数:

   const toastObj = new bootstrap.Toast(document.querySelector("#toast"),{delay:2600});
    const toast =(title ="提示",msg="")=>{
        document.querySelector("#toast .me-auto").innerHTML=title;
        document.querySelector("#toast .toast-body").innerHTML=msg;
        toastObj.show();
    }

toastObj是一个 bootstrap.Toast 实例,创建来初始化页面中 id 为 “toast” 的元素。
然后toast函数,先查找 id 为 “toast” 的元素内部的两个子元素,一个是 .me-auto 类的元素,用于设置标题;另一个是 .toast-body 类的元素,用于设置消息内容,会把接收的参数也就是标题和信息赋值给对应元素。在调用显示方法。

最后修改前端的login函数,将信息不在控制台打印,通过组件来显示:
console.log('成功',"登录成功");修改为toast('成功',"登录成功");,这样就可以了。
代码:

    const login = async () => {
        const u_id = document.querySelector("#u_id").value;
        const u_pwd = document.querySelector("#u_pwd").value;
        if (u_id === "" || u_pwd === "") {
            toast("错误", "账号或密码 不能为空!");
            return;
        }
        const loginObj={
            u_id:u_id,
            u_pwd:u_pwd
        }
        const url = "./user/login";
        //发送POST请求
        const req = await fetch(url, {
            method: "POST",
            headers: {'Content-Type': 'application/json'},//内容类型
            body: JSON.stringify(loginObj)//发送的请求体是json格式的字符串
        });
        if (req.ok) {
            const result = await req.json();
            console.log(result);
            if(result.success){
                toast('成功',"登录成功");
                //延迟执行函数
                setTimeout(()=>{
                    location.href=`index.html`;
                },1200);
            }else{
                toast('失败',result.message);
            }
        } else {
            toast(`响应错误!错误代码:${req.status}`);
        }
    }

最终效果:
在这里插入图片描述

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值