1.登陆功能基本思路

首先,在数据库中查询这条用户记录,如果不存在这条记录则表示身份验证失败,登录流程终止;如果存在这条记录,则表示身份验证成功,接下来则需要进行登录状态的存储和验证了,用户登录成功后我们将用户信息放到 session 对象中,之后再实现一个拦截器,在访问项目时判断 session 中是否有用户信息,有则放行请求,没有就跳转到登录页面。

2.登陆页面制作

2.1 Controller控制跳转

在 BBSUserController.java类中新增跳转功能。该方法用于处理 /login 请求,是登录页面的跳转处理方法,请求方法为 GET,在发起请求后会分别跳转到 templates 模板目录中 user 目录下的 login.html 中。

    /*** 登陆页面跳转* @return*/@GetMapping({"/login", "/login.html"})public String loginPage() {return "user/login";}

2.2 创建登陆页面

登录页面与注册页面非常类似,只是二者的功能有些区别而已。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="header::head-fragment('首页')">
</head>
<body>
<div th:replace="header::header-fragment"></div><div class="layui-container fly-marginTop"><div class="fly-panel fly-panel-user" pad20><div class="layui-tab layui-tab-brief" lay-filter="user"><ul class="layui-tab-title"><li class="layui-this">登入</li><li><a th:href="@{/register}">注册</a></li></ul><div class="layui-form layui-tab-content" id="LAY_ucm" style="padding: 20px 0;"><div class="layui-tab-item layui-show"><div class="layui-form layui-form-pane"><form method="post" id="loginForm" onsubmit="return false;" action="##"><div class="layui-form-item"><label for="loginName" class="layui-form-label">邮箱</label><div class="layui-input-inline"><input type="text" id="loginName" name="loginName" required lay-verify="required"autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><label for="password" class="layui-form-label">密码</label><div class="layui-input-inline"><input type="password" id="password" name="password" required lay-verify="required"autocomplete="off" class="layui-input"></div><div class="layui-form-mid layui-word-aux">6到20个字符</div></div><div class="layui-form-item"><label for="verifyCode" class="layui-form-label">验证码</label><div class="layui-input-inline"><input type="text" id="verifyCode" name="verifyCode" required lay-verify="required"placeholder="请输入验证码" autocomplete="off" class="layui-input"></div><div class="layui-form-mid"><span><img data-tooltip="看不清楚?换一张"th:src="@{/common/captcha}"onclick="this.src='/common/captcha?d='+new Date()*1"alt="单击图片刷新!"></span></div></div><div class="layui-form-item"><button class="layui-btn" lay-filter="*" lay-submit onclick="login()">立即登录</button><span style="padding-left:20px;"><a href="forget.html">忘记密码?</a></span></div></form></div></div></div></div></div>
</div><div class="fly-footer"><p>My-BBS社区 2021 &copy; <a href="" target="_blank">picacho</a></p>
</div><script th:src="@{/js/public.js}"></script>
<script th:src="@{/layui/layui.js}"></script>
<script type="text/javascript">layui.use(['layer', 'jquery'], function () {var layer = layui.layer;var $ = layui.$;window.login = function () {var loginName = $("#loginName").val();if (!validEmail(loginName)) {layer.alert('请输入正确的登录名!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});return false;}var password = $("#password").val();if (!validPassword(password)) {layer.alert('请输入正确的密码格式!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});return false;}var verifyCode = $("#verifyCode").val();if (!validLength(verifyCode, 5)) {layer.alert('请输入正确的验证码!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});return false;}var params = $("#loginForm").serialize();var url = '/login';$.ajax({type: 'POST',//方法类型url: url,data: params,success: function (result) {if (result.resultCode == 200) {window.location.href = '/index';} else {layer.msg(result.message);};},error: function () {layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});}});}});
</script>
</body>
</html>

3. 完成登陆功能

3.1 BBSUserController层代码

这里负责接收前端传来的用户登录相关参数,包括登录邮箱、密码等;接口的映射地址为 /login,请求方法为 POST。首先对参数进行校验,之后调用 bbsUserService 业务层代码查询用户输入的登录信息是否正确,最后根据业务层的结果来返回对应的 Result 对象。

    /*** 登陆功能* @param loginName* @param verifyCode* @param password* @param httpSession* @return*/@PostMapping("/login")@ResponseBodypublic Result login(@RequestParam("loginName") String loginName,@RequestParam("verifyCode") String verifyCode,@RequestParam("password") String password,HttpSession httpSession) {if (!StringUtils.hasLength(loginName)) {return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_NAME_NULL.getResult());}if (!PatternUtil.isEmail(loginName)) {return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_NAME_NOT_EMAIL.getResult());}if (!StringUtils.hasLength(password)) {return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_PASSWORD_NULL.getResult());}if (!StringUtils.hasLength(verifyCode)) {return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_VERIFY_CODE_NULL.getResult());}String kaptchaCode = httpSession.getAttribute(Constants.VERIFY_CODE_KEY) + "";if (!StringUtils.hasLength(kaptchaCode) || !verifyCode.equals(kaptchaCode)) {return ResultGenerator.genFailResult(ServiceResultEnum.LOGIN_VERIFY_CODE_ERROR.getResult());}String loginResult = bbsUserService.login(loginName, MD5Util.MD5Encode(password, "UTF-8"), httpSession);//登录成功if (ServiceResultEnum.SUCCESS.getResult().equals(loginResult)) {httpSession.removeAttribute(Constants.VERIFY_CODE_KEY);//删除session中的验证码return ResultGenerator.genSuccessResult();}//登录失败return ResultGenerator.genFailResult(loginResult);}

3.2 BBSUserServiceImpl业务层代码

首先根据登录名和密码查询数据库中是否有对应的用户记录,不存在则返回错误信息,如果存在则将用户信息保存到 session 对象中,最后返回登录成功的业务信息。

    /*** 用户登录** @param loginName* @param passwordMD5* @param httpSession* @return*/String login(String loginName, String passwordMD5, HttpSession httpSession);
    @Overridepublic String login(String loginName, String passwordMD5, HttpSession httpSession) {BBSUser user = bbsUserMapper.selectByLoginNameAndPasswd(loginName, passwordMD5);if (user != null && httpSession != null) {// 将用户信息存入session中httpSession.setAttribute(Constants.USER_SESSION_KEY, user);//修改最近登录时间user.setLastLoginTime(new Date());bbsUserMapper.updateByPrimaryKeySelective(user);return ServiceResultEnum.SUCCESS.getResult();}return ServiceResultEnum.LOGIN_ERROR.getResult();}

3.3 BBSUserMapper数据持久层

主要的 SQL 方法为 selectByLoginNameAndPasswd(),根据用户名和密码查询用户记录信息。接着updateByPrimaryKeySelective()修改登录时间。

    BBSUser selectByLoginNameAndPasswd(@Param("loginName") String loginName, @Param("password") String password);int updateByPrimaryKeySelective(BBSUser record);
    <!-- 通过用户名和密码查询用户--><select id="selectByLoginNameAndPasswd" resultMap="BaseResultMap">select<include refid="Base_Column_List"/>from tb_bbs_userwhere login_name = #{loginName} and password_md5 = #{password}</select><!-- 更新登陆时间--><update id="updateByPrimaryKeySelective" parameterType="top.picacho.bbs.entity.BBSUser">update tb_bbs_user<set><if test="loginName != null">login_name = #{loginName,jdbcType=VARCHAR},</if><if test="passwordMd5 != null">password_md5 = #{passwordMd5,jdbcType=VARCHAR},</if><if test="nickName != null">nick_name = #{nickName,jdbcType=VARCHAR},</if><if test="headImgUrl != null">head_img_url = #{headImgUrl,jdbcType=VARCHAR},</if><if test="gender != null">gender = #{gender,jdbcType=VARCHAR},</if><if test="location != null">location = #{location,jdbcType=VARCHAR},</if><if test="introduce != null">introduce = #{introduce,jdbcType=VARCHAR},</if><if test="userStatus != null">user_status = #{userStatus,jdbcType=TINYINT},</if><if test="lastLoginTime != null">last_login_time = #{lastLoginTime,jdbcType=TIMESTAMP},</if><if test="createTime != null">create_time = #{createTime,jdbcType=TIMESTAMP},</if></set>where user_id = #{userId,jdbcType=BIGINT}</update>

3.4 前后端交互

    layui.use(['layer', 'jquery'], function () {var layer = layui.layer;var $ = layui.$;window.login = function () {var loginName = $("#loginName").val();if (!validEmail(loginName)) {layer.alert('请输入正确的登录名!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});return false;}var password = $("#password").val();if (!validPassword(password)) {layer.alert('请输入正确的密码格式!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});return false;}var verifyCode = $("#verifyCode").val();if (!validLength(verifyCode, 5)) {layer.alert('请输入正确的验证码!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});return false;}var params = $("#loginForm").serialize();var url = '/login';$.ajax({type: 'POST',//方法类型url: url,data: params,success: function (result) {if (result.resultCode == 200) {window.location.href = '/index';} else {layer.msg(result.message);};},error: function () {layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});}});}});

1.首先是用 jQuery 语法将用户输入的字段获取到

2.使用正则表达式验证用户的输入字段是否符合规范
3.封装数据并向登录接口发送 Ajax 请求
4.请求成功后会跳转至首页 /index,如果想跳转到其他页面可以在这里更改路径
5.请求失败则提醒对应的错误信息

3.5 创建一个index.html首页

3.5.1 创建一个简单首页

这里只需要创建一个简单的页面验证登陆功能即可。

<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body>登陆成功!!!
</body>
</html>
3.5.2 Controller控制跳转
@Controller
public class IndexController {@GetMapping("/index")public String indexPage(){return "index";}
}

4.验证登陆功能

启动项目验证登陆功能,输入帐号 123456@qq.com,密码 123456,再输入正确的验证码,之后点击 “登录” 按钮就可以完成登录流程。效果如下展示:

5. 实现登陆拦截器

登录的目的是为了能够访问一些需要身份信息的页面,比如个人信息页面、添加文章页面,如果没有正确登录的话,是不允许正常的访问页面的,而是跳转至登录页面让用户完成登录才能够继续操作。

拦截器实现
定义一个 Interceptor 非常简单,方式也有几种,这里列举两种简单的实现:

  • 新建类实现 Spring 的 HandlerInterceptor 接口
  • 新建类继承实现了 HandlerInterceptor 接口的实现类,例如已经提供的实现了 HandlerInterceptor 接口的抽象类 HandlerInterceptorAdapter

HandlerInterceptor 方法介绍

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
  • preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理。
  • postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。
  • afterCompletion:在 DispatcherServlet 完全处理完请求后被调用,可用于清理资源等,返回处理(已经渲染了页面)。

5.1 实现HandlerInterceptor

新建 interceptor 包,在包中新建 MyBBSLoginIntercepto 类,该类需要实现 HandlerInterceptor 接口。

/*** 统一身份认证*/
@Component
public class MyBBSLoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {if (null == request.getSession().getAttribute(Constants.USER_SESSION_KEY)) {response.sendRedirect(request.getContextPath() + "/login");return false;} else {return true;}}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
}

5.2 配置拦截器

在实现拦截器的相关方法之后,我们需要对该拦截器进行配置才能使其生效。

强调一下: 在 Spring Boot 1.x 版本中通常会继承 WebMvcConfigurerAdapter 类,但是在 Spring Boot 2.x 版本中,WebMvcConfigurerAdapter 被弃用,虽然继承 WebMvcConfigurerAdapter 这个类比较便利,但在 Spring 5.0 里面已经被弃用了,官方文档也说了,WebMvcConfigurer 接口现在已经有了默认的空白方法,所以在 Spring Boot 2.x 版本下更好的做法还是实现 WebMvcConfigurer 接口。

新建 config 包,之后新建 MyBBSWebMvcConfigurer.java 类并实现 WebMvcConfigurer 接口。

@Configuration
public class MyBBSWebMvcConfigurer implements WebMvcConfigurer {@Autowiredprivate MyBBSLoginInterceptor myBBSLoginInterceptor;public void addInterceptors(InterceptorRegistry registry) {// 登陆拦截registry.addInterceptor(myBBSLoginInterceptor).excludePathPatterns("/register").excludePathPatterns("/login").addPathPatterns("/index");}
}

其中 excludePathPatterns() 方法是设置请求不被拦截器拦截,而 addPathPatterns() 方法则是设置拦截器对这些请求生效,因此上述代码中,对于注册请求和登录请求是放行的,也就是访问这两个地址是不会进行 session 中是否有登录用户对象的验证,而对于 /index 请求则会判断是否已经成功登录。

6.验证拦截器

在地址栏输入index会跳转到登陆界面。

至此登陆功能和登陆拦截器功能也实现完成了。
项目源码下载地址:项目源码下载

Spring Boot项目学习06之用户登陆模块与登录拦截器相关推荐

  1. Spring Boot干货系列:(六)静态资源和拦截器处理 | 掘金技术征文

    原本地址:Spring Boot干货系列:(六)静态资源和拦截器处理 博客地址:tengj.top/ 前言 本章我们来介绍下SpringBoot对静态资源的支持以及很重要的一个类WebMvcConfi ...

  2. Spring Boot项目学习之通用权限管理项目01

    权限管理系统是一个十分常见的系统,在这个系统中是基于角色访问控制的,用户是通过角色与权限进行关联.换句话说,就是一个用户拥有若干个角色,每一个角色拥有若干权限,这样就可以形成一个关系模型:用户-角色- ...

  3. Spring Boot项目学习15之我的主页和用户中心模块

    1.我的主页模块 index.html页面右上角个人信息按钮可以跳转至我的首页. 1.1 BBSUserController控制器 这里需要查询用户的基本信息,然后用户发过的帖子信息,以及收藏过的帖子 ...

  4. 使用Spring Initializer快速创建Spring Boot项目

    使用Spring Initializer快速创建Spring Boot项目 1.IDEA:使用 Spring Initializer快速创建项目 IDE都支持使用Spring的项目创建向导快速创建一个 ...

  5. SpringBoot番外篇(一):使用Spring Initializer快速创建Spring Boot项目(IDEA版)

    IDE都支持使用Spring的项目创建向导快速创建一个Spring Boot项目: 选择我们需要的模块:向导会联网创建Spring Boot项目: ps:需要联网 1.创建新项目时选择Spring I ...

  6. Spring Boot基础学习笔记22:自定义用户控制、登录与退出

    文章目录 零.学习目标 一.准备工作 (一)创建Spring Boot项目 - UserControlDemo01 (二)移植AuthenticationDemo的内容到当前项目 (三)启动应用,测试 ...

  7. Spring Boot基础学习笔记21:自定义用户认证

    文章目录 零.学习目标 一.Spring Security认证流程图 二.准备工作 (一)创建Spring Boot项目 - AuthenticationDemo (二)移植SpringSecurit ...

  8. 10个Spring Boot 优秀学习项目

    10个Spring Boot 优秀学习项目 10个SpringBoot项目分享(好像多了一个项目) 一.mall (虽然培训机构已经把电商推广了烂大街了,但技术还是可以学习的) 二.Cloud-Pla ...

  9. 开源的13个Spring Boot 优秀学习项目

    开源的13个Spring Boot 优秀学习项目!超53K星,一网打尽! 原创: 徐刘根 Java后端技术 5月19日 Spring Boot 算是目前 Java 领域最火的技术栈了,也是Java开发 ...

最新文章

  1. 言论丨十问陆奇:百度如何才能赢得AI的未来?
  2. SCDPM2012功能测试(4)—配置通知
  3. SQL SERVER 数据库实用SQL语句
  4. go build命令参数详解
  5. 聘用计算机高级职称,关于咨询高级职称聘用的问题
  6. 以独占方式锁定此配置文件失败.另一个正在运行_加速用例执行最有效的方法,手把手教你如何并行地运行自动化测试...
  7. matlab话pca的双标图biplot,r – 用ggplot2绘制pca biplot
  8. SAP 许可证审计流程 License Audit介绍
  9. JQuery的$.extend()的源码
  10. 有序关系中的极大元与极小元
  11. CSS基础选择器之类选择器(CSS、HTML)
  12. Access数据库解密方法大盘点
  13. 结对-人机对战象棋游戏-测试过程
  14. 索宝机器人_这些莞味十足的旅游商品获奖了!你尝过没?
  15. PIC单片机应用开发实践教程(三): MCU配置位与烧录
  16. java经典算法(六)---zws
  17. tar命令打包并压缩指定的文件夹并且排除指定的文件
  18. 【演讲之路】钱塘TMC互联网思维分享会
  19. 车金融|金融产品规则引擎的前世今生(中篇)
  20. Python学习笔记:part 1

热门文章

  1. 甜甜C语言——sscanf()函数
  2. C++实现控制台计算器
  3. 【tmux使用指南】不会tmux,就输了
  4. c语言题库anki,Anki
  5. Linux基本指令(二)
  6. android+屏幕色彩度,屏幕:PPI略低,节能技术影响色彩效果
  7. 金蝶软件K3和金蝶软件KIS有什么不同?K3和其他财务软件的最大不同是什么?
  8. Java从高德地图获取全国地铁站数据
  9. phyon学习第一天
  10. 思科交换机与华为交换机生成树兼容性问题