文章目录
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>密 码: <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>密 码: <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>年 龄: <input type="text" name="age" placeholder=""></p> <p>性 别: <label for="man">男</label> <input type="radio" id="man" value="man"> <label for="woman">女</label> <input type="radio" id="woman" value="woman"> </p> <p>邮 箱:<input type="text" name="email" placeholder=""></p> <p>电 话:<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 未登录拦截
-
定义拦截器
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方法"); } }
-
注册拦截器
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简介
-
Cookie是什么? Cookie作用? Cookie保存在哪里?
- 翻译过来:曲奇饼干
- Cookie可以保存会话状态,但是这个会话状态是保留在客户端上。
- 只要Cookie清除,或者Cookie失效,这个会话状态就没有了。
- Cookie可以保存在浏览器的缓存中,浏览器关闭Cookie消失。
- Cookie也可以保存在客户端的硬盘文件中,浏览器关闭Cookie还在,除非Cookie失效。
-
Cookie只有在javaweb中有吗?
- Cookie不止是在javaweb中存在。
- 只要是web开发,只要是B/S架构的系统,只要是基于HTTP协议,就有Cookie的存在。
- Cookie这种机制是HTTP协议规定的。
-
Cookie实现的功能,常见的有哪些?
- 保留购物车商品的状态在客户端上
- 十天内免登录
- …
-
Cookie在现实生活中对应的场景图
-
在java程序中怎么创建Cookie?
Cookie cookie = new Cookie(String cookieName,String cookieValue);
-
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。 -
-
在浏览器客户端无论是硬盘文件中还是缓存中保存的Cookie,什么时候会再次发送给服务器呢?
- 浏览器会不会提交发送这些Cookie给服务器,是和请求路径有关系的。
- 请求路径和Cookie是紧密关联的
- 不同的请求路径会发送提交不同的Cookie
-
Cookie和请求路径之间的关系
-
每一个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(子目录) -
其实路径是可以指定的,可以通过java程序进行设置,保证Cookie和某个特定的路径绑定在一起,例如:
cookie.setPath("/cxy/king");
- 那么Cookie将和 “/cxy/king” 路径绑定在一起,只有发送 “http://localhost:8080/cxy/king” 请求路径,浏览器才会提交Cookie给服务器。
-
-
浏览器是可以禁用 Cookie 什么意思?
当浏览器禁用Cookie之后,服务器还是仍然会将Cookie发送给浏览器,只不过这次浏览器选择了不保存
-
浏览器提交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天内免登录功能
方式一:
首先想到的是使用cookie保存用户登录信息,设置有效期,在用户下次访问时免去登录环节,直接通过cookie获取用户信息。
方式二:
直接将session会话保存,用户下次访问时,继续使用这个session。相比之下session显得更加安全,但是,大家知道,session会随着浏览器的关闭而消失(确切的说,是在客户端消失,服务器端的session存活周期取决于相应配置),当用户下次启动浏览器,访问网站时,又会得到由网站自动分配的新的session。那么,问题来了:如何做到关闭浏览器后到下次登录时session仍然有效?
思路:
- 在用户登录成功时,创建session对象,保存用户信息
- 将此session的sessionid保存到cookie中
- 同时将sessionid于session对应关系存储到应用域中,以便后面可以根据sessionid来获取到session
- 在用户关闭浏览器,重新打开浏览器访问网站时,读取用户的cookie,得到sessionid
- 根据sessionid获取到第3步存储到应用域中的session对象
- 从session中读取用户信息
方式二不知道session存在哪里,且session有保存时间限制,所以采用第一种方式
因为就算是加密后到cookie,有可能被攻击,获取了用户的密码。不安全,可能被监听,然后被猜出密码的加密方式之类的
下图是用Cookie机制来实现十天内免登录功能的流程图:
-
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中处理的是初次登录的用户和未注册的用户
-
Interceptor
-
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 { } }
-
注册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/**");
}
}
```
-
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);
}
}
-
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);
}
-
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>
-
前端界面
<!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>密 码: <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>