JavaWeb - 黑马旅游网(3):登录与退出

项目课程链接:https://www.bilibili.com/video/BV1CE411E7h4
完整课程连接:https://www.bilibili.com/video/BV1uJ411k7wy

1 业务描述

接上篇黑马旅游网(2):用户注册,本篇博客将分析和实现用户登录与退出。登录是后台获取当前访客身份的方式,也是提供个性化服务的基础。

执行登录时:用户在访问网站的任意页面时均可点击 <header></header> 区域中的登录按钮跳转到登录页面进行登录操作。相应的前端页面如下方H5页面所示:

在这里插入图片描述
登录页面的主要操作在右侧的一系列输入栏完成,用户根据前端提供的引导信息,在对应的输入栏内填写自己在注册时预留的 账号密码验证码,然后后点击 登录 按钮后完成身份信息提交。后端经一些列身份核验逻辑后向前端反馈登陆结果。

在这里插入图片描述

执行退出时:用户只需点击 <header></header> 区域中的退出按钮即可实现退出登陆的功能。

另外,登录页面中还预留了自动登录功能,但是课程中并没有讲如何实现。笔者在完成全部的课上内容后也将这个功能实现了。这个功能不算难,需要额外添加的代码也非常少,但是思考并实现这个功能的过程还是蛮值得回味的。我打算在后面单独写一篇博客分析这个功能,届时也分享一下自己对 Session 和 Cookie 的理解吧。

2 业务分析

2.1 业务流程抽象

2.1.1 登录信息核验

登录需要用户在前端页面中填充个人身份信息和验证码并提交。这些内容在前端被 <form></form> 标签包裹。为 登录 绑定一个单机事件,当用户点击 登录 时,向后端发送一个 AJAX 形式的 POST 请求将表单数据提交至后端处理。

后端在接收到请求数据后,首先做 验证码 校验,在本案例中,验证码由后端生成并完成校验。然后再核对其它身份信息,核对方式为:

  1. 将表单信息作为数据库查询条件向 tab_user 表中查询记录
  2. 若能从数据库中查询到用户信息,则后端会获取一个 User 对象,否则会获取 null,登录失败,在登陆页面反馈失败信息。
  3. 获取 User 对象后,还要进一步核验其 status 属性是否为 Y 状态(激活):是则,将 User 对象加入到 Session 对象中,登录成功;否则登录失败,在登陆页面反馈失败信息。

2.1.2 用户信息展示

在登录成功的情况下,会在网站中任意页面的 <header> 标签中显示登录用户的个人信息。前端的代码中已经将 <header> 部分单独定义在一个 header.html 文件中,每个页面都会加载这个文件来渲染页面信息。

可以在 <header> 标签中定义一个 AJAX 形式的 GET 请求,后端专门定义一个查询方法 findOne() 来负责此请求,该方法可以直接从 Session 对象中获取登录用户对象,并将用户的信息回写给前端。前端在收到用户信息后,将页面渲染切换至已登录状态的渲染形式。

2.1.2 退出登录

对于此功能,将前端的 <header> 标签中的 退出 文本使用 <a> 标签包围。点击 退出 时会向后端发送一个 GET 请求,在后端定义一个退出方法 exit() 负责此请求,该方法会从 Session 对象中删除 User 对象,并重定向至登录页面。

2.2 可能的技术难点与解决策略

登录状态判定逻辑链

在这里插入图片描述

3 代码实现

3.1 登录信息校验

在这里插入图片描述

3.1.1 前端

$(function () {
	// 1.给登录按钮绑定事件
	$("#btn_sub").click(function () {
		// 2.发送ajax请求,提交表单数据
		$.post("user/login", $("#loginForm").serialize(), function (resultInfo) {
			// resultInfo: {flag:true/false, errorMsg, "..."}
			// 3.处理响应结果
			if (resultInfo["flag"]) {		// 登陆成功
				location.href = "index.html";
			} else {				// 登陆失败
				$("#errorMsg").html(resultInfo["errorMsg"]);
			}
		});
	});
});

3.1.2 Servlet

/**
 * 用户登陆方法
 */
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ResultInfo resultInfo = new ResultInfo();
    HttpSession session = request.getSession();
    // 0.验证码核对
    String checkCode_browser = request.getParameter("check");               // 获取客户端浏览器提交的验证码
    String checkCode_server = (String) session.getAttribute("CheckCode_Server");     // 获取服务器生成的验证码
    if (!checkCode_server.equalsIgnoreCase(checkCode_browser)) {    // 验证失败
        resultInfo.setFlag(false);
        resultInfo.setErrorMsg("验证码错误!");
        // 回写客户端浏览器
        this.writeValue(resultInfo, response);
        return;
    }   // else 验证通过
    // 1.获取用户信息
    Map<String, String[]> parameterMap = request.getParameterMap();
    // 2.封装 User Bean 对象
    User user = new User();
    try {
        BeanUtils.populate(user, parameterMap);
    } catch (IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }
    // 3.调用service查询user
    User loginUser = service.login(user);
    // 4.判断用户是否存在
    if (loginUser == null) {    // 用户不存在
        resultInfo.setFlag(false);
        resultInfo.setErrorMsg("用户名或密码错误!");
    }   // else 用户存在
    // 5.判断用户是否激活
    if (loginUser != null && !"Y".equals(loginUser.getStatus())) {   // 用户未激活
        resultInfo.setFlag(false);
        resultInfo.setErrorMsg("您尚未未激活,请激活。");
    }   // else 用户已激活
    // 6.用户名和密码正确且已激活,跳转网站首页
    if (loginUser != null && "Y".equals(loginUser.getStatus())) {
        resultInfo.setFlag(true);
        session.setAttribute("user", loginUser);
    }
    this.writeValue(resultInfo, response);
}

3.1.3 Service

/**
 * 登录用户
 * @param user 用户名
 * @return
 *      true:激活成功
 *      false:激活失败
 */
@Override
public User login(User user) {
    return userDao.findByUsernameAndPassword(user.getUsername(), user.getPassword());
}

3.1.4 Dao

/**
 * 根据用户名和密码查询用户信息
 *      登陆验证
 * @param username String 用户名
 * @param password String 密码
 * @return
 *      查询成功:User Bean 对象
 *      查询失败:null
 */
@Override
public User findByUsernameAndPassword(String username, String password) {
    User user = null;
    try {
        String sql = "SELECT * FROM tab_user WHERE username = ? AND password = ?";
        user = template.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), username, password);
    } catch (DataAccessException e) {
        e.printStackTrace();
    }
    return user;
}

3.2 用户信息展示

在这里插入图片描述

3.2.1 前端

/**
 * 查询用户信息
 */
$.get("user/findOne", {}, function (user) {
    // user: {uid:...,username:...}
    let msg = "欢迎回来," + user["username"];
    $("#span_username").html(msg);
});

3.2.2 Servlet

/**
 * 查询登录用户信息方法,查询结果在index.html中的header上显示
 */
public void findOne(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 从session中获取登录用户
    User user = (User) request.getSession().getAttribute("user");
    // 将user写回客户端
    this.writeValue(user, response);
}

3.3 退出登录

在这里插入图片描述

3.3.1 前端

header.html

<!-- 登录状态  -->
<div class="login">
    <span id="span_username"></span>
    <a href="myfavorite.html" class="collection">我的收藏</a>
    <a href="user/exit">退出</a>	  <!--向后端发送退出登录请求-->
</div>

3.3.2 Servlet

/**
 * 退出登录方法
 */
public void exit(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 1.销毁session
    request.getSession().invalidate();
    // 2.跳转至登陆页面
    response.sendRedirect(request.getContextPath() + "/login.html");
}

部分代码并未完全展示,完整代码可以参考我的 GitHub 仓库

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值