SpringBoot Thymeleaf Vue Mybatis 登录和注册的实现,以及使用Cookie实现七天免登录

5. 功能实现

5.1 用户注册和登录功能

解决办法就是将生成后的mapper.xml文件中的namespace与你的mapper接口路径比对一下,不同就改为mapper接口的路径。

原理:在mybatis中,映射文件中的namespace是用于绑定mapper接口的,即面向接口编程。 当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动帮你找到对应需要执行的SQL语句。Spring在动态代理时,就是需要一个mapper接口的一个实现类,所以当你的mapper.xml与mapper接口类未关联到一块的时候,就会出现上述异常。

前端页面
  • 登录页面login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" type="text/css" th:href="@{/css/mystyle.css}"/>
        <script type="text/javascript" th:src="@{/js/jquery-1.7.2.js}"></script>
        <script type="text/javascript" th:src="@{https://cdn.jsdelivr.net/npm/vue/dist/vue.js}" charset="UTF-8"></script><!-- 开发环境版本,包含了有帮助的命令行警告 -->
    
        <title>Login</title>
    </head>
    
    <body>
    <div id="container" style="width: 100%;">
        <div id="header" style="background-color88: azure;">
            <ul>
                <li><a class="active" href="#home">微微博</a></li>
                <li><a href="#found">发现</a></li>
                <li><a href="#about">关于</a></li>
                <li text-align="right"><a href="#about me">cxy</a></li>
            </ul>
        </div>
    </div>
    
    <div th:id="login" style="background-color: honeydew">
        <!-- 表单: 收集用户的信息,提交到后台服务器 -->
        <br>
    
        <h3 align="center">登录</h3>
        <form th:id="login_form" action="#" th:action="@{/user/login}" method="post">
            <p>用户名: <input type="text" name="username">
            <!--/*@thymesVar id="login_user" type="java.lang.String"*/-->
            <span th:text="${login_user}"></span></p>
            <p>&nbsp;&nbsp; 码: <input type="password" name="password"></p>
            <p><input type="submit" value="登录"></p>
            <p th:if="${login_user eq 'user has not registered'}" th:v-html="acount_uncreated"></p>
            <p><input type="checkbox" name="remember"  value="1"/>一周内免登陆</p>
        </form>
    
        <br>
    </div>
    
    <div id="footer" style="background-color: darksalmon;clear:both;text-align:center;">
        版权 © cxy.com</div>
    </div>
    
    <script type="text/javascript">
        new Vue({
            el:'#login',
            data: {
                acount_uncreated: '<span style="color: gray">没有账号?</span><span><a href="/user/toRegister">创建账号</a></span>'
            }
        });
    </script>
    </body>
    </html>
    
  • 登录成功页面welcome.html

    <!DOCTYPE html>
    <html>
    <html lang="en" xmlns:th="https://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <script type="text/javascript" th:src="@{/js/jquery-1.7.2.js}"></script>
        <title>Title</title>
    </head>
    <script>
        alert('欢迎您:<span th:text="${user.name}">确定</span>')
    </script>
    <body>
    
    注册或登录后才能看到的界面
    <h1 th:text="${session.msg}"></h1>
    <a href="/admin/logout">退出登录</a>
    <!--<a href="#" th:href="@{/admin/logout}" class="item">注销</a>-->
    </body>
    
    </html>
    
  • 注册页面register.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:v-on="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" type="text/css" th:href="@{/css/mystyle.css}"/>
        <script type="text/javascript" th:src="@{/js/jquery-1.7.2.js}"></script>
        <script type="text/javascript" th:src="@{http://static.runoob.com/assets/jquery-validation-1.14.0/lib/jquery.js}"></script>
        <script type="text/javascript" th:src="@{http://static.runoob.com/assets/jquery-validation-1.14.0/dist/jquery.validate.min.js}"></script>
        <script type="text/javascript" th:src="@{https://cdn.jsdelivr.net/npm/vue/dist/vue.js}" charset="UTF-8"></script><!-- 开发环境版本,包含了有帮助的命令行警告 -->
    
        <title>Register</title>
    </head>
    
    <body>
    
    <div id="container" style="width: 100%;">
        <div id="header" style="background-color88: azure;">
            <ul>
                <li><a class="active" href="#home">微微博</a></li>
                <li><a href="#found">发现</a></li>
                <li><a href="#about">关于</a></li>
                <li text-align="right"><a href="#about me">cxy</a></li>
            </ul>
        </div>
    </div>
    
    
    <div th:id="register" style="background-color: honeydew">
        <br>
    
        <!-- 表单: 收集用户的信息,提交到后台服务器 -->
        <form id="register_form" action="/user/register" method="post">
            <p>用户名: <input type="text" name="username" placeholder="username"><span th:text="${register_user}"></span></p>
            <p>&nbsp;&nbsp; 码: <input type="password" th:id="password" name="password" placeholder="password"></p>
            <p>确认密码: <input type="password" th:id="confirm_password" name="confirm_password" placeholder="confirm password"></p>
            <p>&nbsp;&nbsp; 龄: <input type="text" name="age" placeholder=""></p>
            <p>&nbsp;&nbsp; 别:
                <label for="man"></label>
                <input type="radio" id="man" value="man">
                <label for="woman"></label>
                <input type="radio" id="woman" value="woman">
            </p>
            <p>&nbsp;&nbsp; 箱:<input type="text" name="email" placeholder=""></p>
            <p>&nbsp;&nbsp; 话:<input type="text" name="tel" placeholder=""></p>
            <button v-on:click="submit">submit</button>
            <!--/*@thymesVar id="register_user" type=""*/-->
            <p th:if="${register_user eq 'user already registered'}" th:v-html="acount_already_created"></p>
        </form>
        <br>
        <br>
        <br>
    </div>
    
    
    <div id="footer" style="background-color: darksalmon;clear:both;text-align:center">
        版权 © cxy.com</div>
    </div>
    
    <script>
        jQuery.validator.setDefaults({
            debug: false,
            success: "valid"
        });
    
        $("#register_form").validate({
            rules:{
                username:"required",
                password: "required",
                confirm_password:{
                    equalTo: "#password"
                }
            }
        });
    </script>
    
    <script type="text/javascript">
        new Vue({
            el:'#register',
            data:{
                acount_already_created:'<span style="color: gray">已有账号?</span><span><a href="/user/toLogin">登录</a></span>'
            }
        })
    </script>
    </body>
    </html>
    
后台登录和注册
  • 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.cxy.blog.dao.UserMapper">
    
        <select id="getUserByUsername" resultType="User">
            select id,username,password from t_user where username = #{username}
        </select>
    
        <select id="login" resultType="User">
            SELECT username,password FROM t_user where username = #{username} and password = #{password}
        </select>
    
        <insert id="register" parameterType="User" useGeneratedKeys="true" keyProperty="id">
            INSERT INTO t_user(username, password,gender,email) VALUES(#{username},#{password},#{gender},#{email})
        </insert>
    </mapper>
    
  • UserMapper.java

    如果没有在启动类上加@MapperScan注解则需要在每一个Mapper类上加上@Mapper注解

    @Repository
    public interface UserMapper {
     
        User getUserByUsername(String username);
     
        User login(String username,String password);
     
        int register(User user);
    }
    
  • UserService

    @Service
    public class UserService {
        @Autowired
        private UserMapper userMapper;
    
        public User getUserByUsername(String username) {
            return userMapper.getUserByUsername(username);
        }
    
        public User login(String username, String password) {
            //MD5加密
            //return userMapper.login(username, MD5Utils.code(password));
            //SHA256加密
            return userMapper.login(username, Sha256Util.getSHA256(password));
    
        }
    
        public int register(User user) {
            //MD5加密
            //user.setPassword(MD5Utils.code(user.getPassword()));
            //SHA256加密
            user.setPassword(Sha256Util.getSHA256(user.getPassword()));
            return userMapper.register(user);
        }
    }
    
  • UserController

    package com.cxy.blog.controller;
    
    import com.cxy.blog.beans.User;
    import com.cxy.blog.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @Controller
    @RequestMapping("/user")
    public class UserController {
        @Autowired
        private UserService userService;
    
        /**
         * 跳转注册页
         */
        @RequestMapping("/toRegister")
        public String toRegister(){
            return "user/register";
        }
    
        /**
         * 注册操作
         * @param user
         * @param model
         * @return
         */
        @RequestMapping(value = "/register",method = RequestMethod.POST)
        public String register(User user, Model model){
    
            String username = user.getUsername();
            if (userService.getUserByUsername(username) != null){
                System.out.println("该用户已经注册");
                model.addAttribute("register_user","user already registered");
                return "forward:/user/toRegister";
            }
    
            int res = userService.register(user);
            if (res == 0){
                System.out.println("注册失败");
                return "forward:/user/toRegister";
            }
            return "redirect:/user/toLogin";
        }
    
        /**
         * 跳转首页(登录页)
         */
        @RequestMapping("/toLogin")
        public String show(){
            return "user/login";
        }
    
        /**
         * 登录操作
         */
        @RequestMapping("/login")
        public String login(User user, HttpServletRequest request,Model model){
            String username = user.getUsername();
            String password = user.getPassword();
            if (userService.getUserByUsername(username) == null){
                model.addAttribute("login_user","user has not registered");
                return "forward:/user/toLogin";
            }
    
            User user1 = userService.login(username, password);
    
            if (user1==null){
                model.addAttribute("login_user","username or password is not true");
                return "forward:/user/toLogin";
            }else{
                //登录成功后将用户放入session中,用于拦截
                request.getSession().setAttribute("session_user",user);
                return "user/welcome";
            }
        }
    
        /**
         * 测试未登陆拦截页面
         */
        @RequestMapping("/welcome")
        public String welcome(){
            return "user/welcome";
        }
    
        /**
         * 退出登录
         */
        @RequestMapping("/logout")
        public void outUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
            request.getSession().removeAttribute("session_user");
            response.sendRedirect("/user/toLogin");
        }
    }
    
5.2 未登录拦截
  1. 定义拦截器

    package com.cxy.blog.intercepter;
    
    import com.cxy.blog.beans.User;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @Component
    public class UserInterceptor implements HandlerInterceptor {
    
        /*
         * 进入controller层之前拦截请求
         * 返回值:表示是否将当前的请求拦截下来  false:拦截请求,请求终止。true:请求不被拦截,继续执行
         * Object obj:表示被拦的请求的目标对象(controller中方法)
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
            System.out.println("执行到了preHandle方法");
            System.out.println(handler);
            User user = (User) request.getSession().getAttribute("session_user");
            if (user == null) {
                response.sendRedirect(request.getContextPath() + "/user/toLogin");//拦截后跳转的方法
                System.out.println("已成功拦截并转发跳转");
                return false;
            }
            System.out.println("合格不需要拦截,放行");
            return true;
        }
    
        /*
         * 处理请求完成后视图渲染之前的处理操作
         * 通过ModelAndView参数改变显示的视图,或发往视图的方法
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
            System.out.println("执行了postHandle方法");
        }
    
        /*
         * 视图渲染之后的操作
         */
        @Override
        public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
            System.out.println("执行到了afterCompletion方法");
        }
    }
    
  2. 注册拦截器

    package com.cxy.blog.intercepter;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author cxy
     * @create 2020-10-30-1:23 AM
     */
    @Configuration
    public class SessionInterceptor implements WebMvcConfigurer {
    
        /**
         * 注册拦截器,添加拦截路径和排除拦截路径
         * addPathPatterns():添加需要拦截的路径
         * excludePathPatterns():添加不需要拦截的路径
         */
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            List list = new ArrayList();
            list.add("/user/toLogin");
            list.add("/user/login");
            list.add("/user/toRegister");
            list.add("/user/register");
    
            registry.addInterceptor(new UserInterceptor())
                    .addPathPatterns("/user/**")
                    .excludePathPatterns(list)
                    .excludePathPatterns("/static");
    
        }
    }
    
5.3 七天内免登录

Cookie是由服务器端生成并储存在浏览器客户端上的数据

在javaweb开发中Cookie被当做java对象在web服务器端创建,并由web服务器通过Http协议,Header,body,line响应发送给特定浏览器客户端,并且WEB服务器可以向同一个浏览器客户端上同时发送多个Cookie,每一个Cookie对象都由name和value组成,name(cookie的name)和value(放入cookie的值)只能是字符串类型,浏览器接收到来自服务器的Cookie数据之后默认将其保存在浏览器缓存中(如果浏览器关闭,缓存消失,Cookie数据消失),只要浏览器不关闭,当我们下一次发送“特定”请求的时候,浏览器负责将Cookie数据发送给WEB服务器。我们还可以使用特殊的方法,将Cookie保存在客户端的硬盘上,永久性保存。这样关闭浏览器Cookie还是存在的,不会消失,比如:实现十天内自动登录。

Cookie 和 Session
  • Cookie
    • Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能。

    • Cookie的Domain和Path属性标识了这个Cookie是哪一个网站发送给浏览器的;Cookie的Expires属性标识了Cookie的有 效时间,当Cookie的有效时间过了之后,这些数据就被自动删除了。

    • 如果不设置过期时间,则表示这个Cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,Cookie就消失了。这种生命期为浏览会话期的 Cookie被称为会话Cookie。会话Cookie一般不保存在硬盘上而是保存在内存里。如果设置了过期时间,浏览器就会把Cookie保存到硬盘 上,关闭后再次打开浏览器,这些Cookie依然有效直到超过设定的过期时间。存储在硬盘上的Cookie可以在不同的浏览器进程间共享,比如两个IE窗 口。而对于保存在内存的Cookie,不同的浏览器有不同的处理方式。

  • Session

    Session是存放在服务器端的类似于HashTable结构(每一种Web开发技术的实现可能不一样,下文直接称为HashTable)来存放用户 数据。

    当浏览器第一次发送请求时,服务器自动生成了一个HashTable和一个Session ID用来唯一标识这个HashTable,并将其通过响应发送到浏览器。当浏览器第二次发送请求,会将前一次服务器响应中的Session ID放在请求中一并发送到服务器上,服务器从请求中提取出Session ID,并和保存的所有Session ID进行对比,找到这个用户对应的HashTable。

    一般情况下,服务器会在一定时间内(默认20分钟)保存这个HashTable,过了时间限制,就会销毁这个HashTable。在销毁之前,程序员可以 将用户的一些数据以Key和Value的形式暂时存放在这个HashTable中。当然,也有使用数据库将这个HashTable序列化后保存起来的,这 样的好处是没了时间的限制,坏处是随着时间的增加,这个数据库会急速膨胀,特别是访问量增加的时候。一般还是采取前一种方式,以减轻服务器压力。

  • 区别
    存储位置浏览器携带的数据量存储的数据类型安全性默认的有效路径数据的传输量
    Cookie浏览器只能是字符串较低当前目录及其子目录有限制4K,不能超过20个
    Session服务器少(只携带session-id)任意类型较高整站有效无限制
Cookie简介
  1. Cookie是什么? Cookie作用? Cookie保存在哪里?
    • 翻译过来:曲奇饼干
    • Cookie可以保存会话状态,但是这个会话状态是保留在客户端上
    • 只要Cookie清除,或者Cookie失效,这个会话状态就没有了
    • Cookie可以保存在浏览器的缓存中,浏览器关闭Cookie消失。
    • Cookie也可以保存在客户端的硬盘文件中,浏览器关闭Cookie还在,除非Cookie失效。
  2. Cookie只有在javaweb中有吗?
    • Cookie不止是在javaweb中存在。
    • 只要是web开发,只要是B/S架构的系统,只要是基于HTTP协议,就有Cookie的存在。
    • Cookie这种机制是HTTP协议规定的。
  3. Cookie实现的功能,常见的有哪些?
    • 保留购物车商品的状态在客户端上
    • 十天内免登录
  4. Cookie在现实生活中对应的场景图 在这里插入图片描述
  5. 在java程序中怎么创建Cookie?
Cookie cookie = new Cookie(String cookieName,String cookieValue);
  1. Cookie在客户端的保存形式和有效时间
    • 服务器端默认创建的Cookie,发送到浏览器之后,浏览器默认将其保存在缓存中,当浏览器关闭之后Cookie消失。

    • 可以通过设置Cookie的有效时长,以保证Cookie保存在硬盘文件当中。但是这个有效时长必须是 >0 的。换句话说,只要设置Cookie的有效时长大于0,则该Cookie会被保存在客户端硬盘文件当中。有效时长过去之后,则硬盘文件当中的Cookie失效

    • 服务器创建Cookie对象之后,调用setMaxAge方法设置Cookie的有效时间。

      cookie.setMaxAge(60 * 60 * 24 * 10); //10天内有效

    如果这个有效时间 >0,则该Cookie对象发送给浏览器之后浏览器将其保存到硬盘文件中。
    如果这个有效时间 <0,则该Cookie对象也是被保存在浏览器缓存中,待浏览器关闭Cookie消失。
    如果这个有效时间 =0,则该Cookie从服务器端发过来的时候就已经是一个已过时的Cookie。

  2. 在浏览器客户端无论是硬盘文件中还是缓存中保存的Cookie,什么时候会再次发送给服务器呢?
    • 浏览器会不会提交发送这些Cookie给服务器,是和请求路径有关系的。
    • 请求路径和Cookie是紧密关联的
    • 不同的请求路径会发送提交不同的Cookie
  3. Cookie和请求路径之间的关系
    1. 每一个Cookie和请求路径是绑定在一起的,只有特定的路径才可以发送特定的Cookie。

      实际上浏览器是这样做的:浏览器在向web服务器发送请求的时候先去对应的请求路径下搜索是否有对应的Cookie,如果有Cookie,并且Cookie没有失效,则发送该Cookie或者多个Cookie到服务器端。请求路径和Cookie的关系是这样对应的:

      • 假如获取Cookie时的路径是 :http://localhost:8080/cxy/getCookie

      这时浏览器请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端。这个浏览器中的Cookie会默认和“cxy/”这个路径绑定在一起。也就是说,以后只要发送“cxy/”请求,Cookie一定会提交给服务器。

      将来发送Cookie的路径包括如下路径 :

      http://localhost:8080/cxy/getCookie(相同路径)
      http://localhost:8080/cxy/xxxx(同目录)
      http://localhost:8080/cxy/xxxx/xxxx/xxx(子目录)

      • 假如获取Cookie时的路径是 :http://localhost:8080/cxy/servlet/getCookie

      这时浏览器请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端。这个浏览器中的Cookie会默认和“servlet/”这个路径绑定在一起。也就是说,以后只要发送“servlet/”请求,Cookie一定会提交给服务器。

      将来发送Cookie的路径包括如下路径 :

      http://localhost:8080/cxy/servlet/getCookie(相同路径)
      http://localhost:8080/cxy/servlet/xxxxx(同目录)
      http://localhost:8080/cxy/servlet/xxxxx/xxxx(子目录)

    2. 其实路径是可以指定的,可以通过java程序进行设置,保证Cookie和某个特定的路径绑定在一起,例如:

    cookie.setPath("/cxy/king");
    
    • 那么Cookie将和 “/cxy/king” 路径绑定在一起,只有发送 “http://localhost:8080/cxy/king” 请求路径,浏览器才会提交Cookie给服务器。
  4. 浏览器是可以禁用 Cookie 什么意思?

    当浏览器禁用Cookie之后,服务器还是仍然会将Cookie发送给浏览器,只不过这次浏览器选择了不保存

  5. 浏览器提交Cookie给服务器,服务器怎么接收Cookie?
```java
//从request对象中获取所有提交的Cookie
Cookie[] cookies = request.getCookies();
//遍历cookie数组取出所有的cookie对象
if(cookies != null){
    for(Cookie cookie : cookies){
        String cookieName = cookie.getName();
        String cookieValue = cookie.getValue();
        System.out.println(cookieName + "=" + cookieValue);
    }
}
```
Cookie 的使用

1、创建 Cookie

// Cookie 为键值对数据格式
Cookie cookie_username = new Cookie("cookie_username", username);
12

2、设置 Cookie 持久时间

// 即:过期时间,单位是:秒(s)
cookie_username.setMaxAge(30 * 24 * 60 * 60);
12

3、设置 Cookie 共享路径

// 表示当前项目下都携带这个cookie
cookie_username.setPath(request.getContextPath());
12

4、向客户端发送 Cookie

// 使用 HttpServletResponse 对象向客户端发送 Cookie
response.addCookie(cookie_username);
12

5、销毁 Cookie

// 根据 key 将 value 置空
Cookie cookie_username = new Cookie("cookie_username", "");
// 设置持久时间为0
cookie_username.setMaxAge(0);
// 设置共享路径
cookie_username.setPath(request.getContextPath());
// 向客户端发送 Cookie
response.addCookie(cookie_username);
12345678
利用Cookie机制实现7天内免登录功能
一些网站的3天免登陆是如何做到的?

方式一:

首先想到的是使用cookie保存用户登录信息,设置有效期,在用户下次访问时免去登录环节,直接通过cookie获取用户信息。

方式二:

直接将session会话保存,用户下次访问时,继续使用这个session。相比之下session显得更加安全,但是,大家知道,session会随着浏览器的关闭而消失(确切的说,是在客户端消失,服务器端的session存活周期取决于相应配置),当用户下次启动浏览器,访问网站时,又会得到由网站自动分配的新的session。那么,问题来了:如何做到关闭浏览器后到下次登录时session仍然有效?

思路:

  1. 在用户登录成功时,创建session对象,保存用户信息
  2. 将此session的sessionid保存到cookie中
  3. 同时将sessionid于session对应关系存储到应用域中,以便后面可以根据sessionid来获取到session
  4. 在用户关闭浏览器,重新打开浏览器访问网站时,读取用户的cookie,得到sessionid
  5. 根据sessionid获取到第3步存储到应用域中的session对象
  6. 从session中读取用户信息

方式二不知道session存在哪里,且session有保存时间限制,所以采用第一种方式

注意:千万不能把用户的密码放到cookie中,哪怕是经过加密的

因为就算是加密后到cookie,有可能被攻击,获取了用户的密码。不安全,可能被监听,然后被猜出密码的加密方式之类的

下图是用Cookie机制来实现十天内免登录功能的流程图:
在这里插入图片描述

  1. Controller
package com.cxy.blog.controller;

import com.cxy.blog.beans.User;
import com.cxy.blog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;

/**
 * @author cxy
 * @create 2020-10-29-5:09 PM
 */

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    /**
     * 登录操作
     */
    @RequestMapping("/login")
    public String login(User user, Integer remenber,HttpServletRequest request,HttpServletResponse response,Model model){
        String username = user.getUsername();
        String password = user.getPassword();
        if (userService.getUserByUsername(username) == null){
            model.addAttribute("login_massage","user has not registered");
            System.out.println("user has not registered");
            return "forward:/user/toLogin";
        }

        if(remenber == null){
            Cookie cookie = new Cookie("token","");
            cookie.setMaxAge(0);   //Cookie从服务器端发过来的时候就已经是一个已过时的Cookie
            cookie.setPath(request.getContextPath());
            response.addCookie(cookie);
        }

        User user1 = userService.login(username, password);

        if(remenber != null){
            //如果该用户没有token 添加token到数据库。否则更新token
            String tokenUUID = UUID.randomUUID().toString();
            user1.setToken(tokenUUID);

            if (user1.getToken() == null){
                int i = userService.updateToken(user1);
                System.out.println(i+"账号或者密码不正确");
            }

            //添加刚才生成的token到网页Cookie中
            Cookie cookie = new Cookie("token",tokenUUID);
            cookie.setMaxAge(7*24*60*60);    //设置7天的过期时间
            cookie.setPath(request.getContextPath());//cookie在该路径下的网页起作用
            //添加cookie 到响应头,真正回到浏览器的时候才会被添加到浏览器的cookie
            response.addCookie(cookie);

        }
        if (user1==null){
            model.addAttribute("login_massage","username or password is not true");
            System.out.println("账号或者密码不正确");
            return "forward:/user/toLogin";
        }else{
            //登录成功后将用户放入session中,用于拦截
            request.getSession().setAttribute("login_user",user);
            System.out.println("首次登录,查询数据库用户名和密码无误,登录成功,设置cookie成功");
            return "user/welcome";
        }
    }

    /**
     * 退出登录
     */
    @RequestMapping("/logout")
    public void outUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.getSession().removeAttribute("session_user");

        Cookie[] cookies = request.getCookies();
        for(Cookie cookie:cookies){
            if("login_user".equals(cookie.getName())){
                System.out.println("退出登录时,cookie还没过期,清空cookie");
                cookie.setMaxAge(0);
                cookie.setValue(null);
                cookie.setPath(request.getContextPath());
                response.addCookie(cookie);
                break;
            }
        }
        //重定向到登录页面
        response.sendRedirect("/user/toLogin");
    }
}

注:在拦截器中已对携带Cookie的登录过的用户进行拦截和处理,所以Controller中处理的是初次登录的用户和未注册的用户

  1. Interceptor
  2. HandlerInterceptor

    package com.cxy.blog.intercepter;
    
    import com.cxy.blog.beans.User;
    import com.cxy.blog.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author cxy
     * @create 2020-11-11-2:49 PM
     * 对登录过,携带Cookie的用户进行拦截,在Controller中就是初次登录用户的处理
     */
    public class CookiendSessionInterceptor implements HandlerInterceptor {
    
        @Autowired
        private UserService userService;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            Object loginUser = request.getSession().getAttribute("login_user");
            if (loginUser != null){
                System.out.println("session域中获取到user,放行");
                return true;
            }
    
            System.out.println("进入拦截器");
            Cookie[] cookies = request.getCookies();
            if (cookies != null && cookies.length > 0) {
                for (Cookie cookie : cookies) {
                    System.out.println("cookie 遍历" + cookie.getName());
                    if ("token".equals(cookie.getName())) {
                        System.out.println("有名为token的cookie,并且cookie还没过期...");
                        //遍历cookie如果找到登录状态则返回true 继续执行原来请求url到controller中的方法
                        String token = cookie.getValue();
                        //是否存在对应的token对象
                        User user = userService.getToken(token);
                        System.out.println(user);
                        //存在表示cookie未失效 不拦截 否则拦截
                        if (user != null) {
                            request.getSession().setAttribute("login_user", user);
                        }
                        return true;
                    }
                }
            }
    
            request.setAttribute("msg", "没有权限,请先登录");
            System.out.println("没有权限,请先登录");
            response.sendRedirect("/user/toLogin");
    
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        }
    
    } 
    
  3. 注册HandlerInterceptor:WebMvcConfigurer
  ```java
  package com.cxy.blog.intercepter;
  
  import org.springframework.context.annotation.Configuration;
  import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  
  /**
   * @author cxy
   * @create 2020-10-30-1:23 AM
   */
  @Configuration
  public class WebConfig implements WebMvcConfigurer {
  
      /**
       * 注册拦截器,添加拦截路径和排除拦截路径
       * addPathPatterns():添加需要拦截的路径
       * excludePathPatterns():添加不需要拦截的路径
       */
  
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
  
          registry.addInterceptor(new CookiendSessionInterceptor())
                  .addPathPatterns("/user/**")
                  .excludePathPatterns("/", "/**/toLogin","/**/toRegister")
                  .excludePathPatterns("/static/**");
      }
  }
  ```
  1. Service
package com.cxy.blog.service;

import com.cxy.blog.beans.User;
import com.cxy.blog.dao.UserMapper;
import com.cxy.blog.utils.Sha256Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


/**
 * @author cxy
 * @create 2020-10-29-5:09 PM
 */


@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    //查询用户名是否存在
    public User getUserByUsername(String username) {
        return userMapper.getUserByUsername(username);
    }

    //登录
    public User login(String username, String password) {
        //SHA256加密
        return userMapper.login(username, Sha256Util.getSHA256(password));

    }

    //读取数据库中的token
    public User getToken(String token){
        return userMapper.getToken(token);
    }

    //更新数据库中的token
    public int updateToken(User user){
        return userMapper.updateToken(user);
    }

    //注册
    public int register(User user) {
        //SHA256加密
        user.setPassword(Sha256Util.getSHA256(user.getPassword()));
        return userMapper.register(user);
    }
}
  1. Dao
package com.cxy.blog.dao;
import com.cxy.blog.beans.User;
import org.springframework.stereotype.Repository;
 

@Repository
public interface UserMapper {
 
    User getUserByUsername(String username);
 
    User login(String username,String password);
 
    int register(User user);

    User getToken(String token);

    int updateToken(User user);
}
  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.cxy.blog.dao.UserMapper">

    <select id="getUserByUsername" resultType="User">
        select id,username,password from t_user WHERE username = #{username}
    </select>

    <select id="login" resultType="User">
        SELECT username,password FROM t_user WHERE username = #{username} and password = #{password}
    </select>

    <select id="getToken" resultType="User">
        SELECT username,token FROM t_user WHERE token = #{token}
    </select>

    <select id="updateToken">
        UPDATE t_user SET token = #{token},updated_time = CURRENT_TIMESTAMP WHERE username = #{username}
    </select>


    <insert id="register" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO t_user(username, password,gender,email,updated_time) VALUES(#{username},#{password},#{gender},#{email},CURRENT_TIMESTAMP)
    </insert>

</mapper>
  1. 前端界面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" th:href="@{/css/mystyle.css}"/>
    <script type="text/javascript" th:src="@{/js/jquery-1.7.2.js}"></script>
    <script type="text/javascript" th:src="@{https://cdn.jsdelivr.net/npm/vue/dist/vue.js}" charset="UTF-8"></script><!-- 开发环境版本,包含了有帮助的命令行警告 -->

    <title>Login</title>
</head>

<body>
<div id="container" style="width: 100%;background-color: azure">
    <div id="header" style="background-color88: azure;">
        <ul>
            <li><a class="active" href="#home">微微博</a></li>
            <li><a href="#found">发现</a></li>
            <li><a href="#about">关于</a></li>
            <li text-align="right"><a href="#about me">cxy</a></li>
        </ul>
    </div>
</div>


<div th:id="login" style="background-color: honeydew">
    <!-- 表单: 收集用户的信息,提交到后台服务器 -->
    <br>

    <h3 align="center">登录</h3>
    <form th:id="login_form" action="#" th:action="@{/user/login}" method="post">
        <p>用户名: <input type="text" name="username"><span th:text="${login_massage}"></span></p>

        <p>&nbsp;&nbsp; 码: <input type="password" name="password"></p>
        <p><input type="submit" value="登录"></p>
        <!--/*@thymesVar id="login_massage" type="java.lang.String"*/-->
        <p><span th:if="${login_massage eq 'user has not registered'}" th:v-html="acount_uncreated"></span></p>
        <p><input type="checkbox" name="remember"  value="1"/>一周内免登陆</p>
    </form>

    <br>
</div>


<div id="footer" style="background-color: darksalmon;clear:both;text-align:center;">
    版权 © cxy.com</div>
</div>

<script type="text/javascript">
    new Vue({
        el:'#login',
        data: {
            acount_uncreated: '<span style="color: gray">没有账号?</span><span><a href="/user/toRegister">创建账号</a></span>'
        }
    });

</script>


</body>
</html>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值