Cookie与Session 实现登录操作
Cookie
Cookie
是网络编程中使用最广泛的一项技术,主要用于辨识用户身份。
客户端(浏览器)与网站服务端通讯的过程如下图所示:
从图中看,服务端既要返回 Cookie
给客户端,也要读取客户端提交的 Cookie
。所以本节课主要学习服务端 Spring
工程是如何使用 Cookie
的,有读、写两种操作。
浏览器如何使用
Cookie
,在《Java 网络编程》课程中讲解。
读 Cookie
为 control
类的方法增加一个 HttpServletRequest
参数,通过 request.getCookies()
取得 cookie
数组。然后再循环遍历数组即可。(下列演示代码省略循环代码)
系统会自动传入方法参数所需要的
HttpServletRequest
对象哦
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;@RequestMapping("/songlist")
public Map index(HttpServletRequest request) {Map returnData = new HashMap();returnData.put("result", "this is song list");returnData.put("author", songAuthor);Cookie[] cookies = request.getCookies();returnData.put("cookies", cookies);return returnData;
}
请看代码演示:
从浏览器输出结果可以看到,打印出了所有的 Cookie
数据。
cookie 有很多属性值,各属性值的作用请 点击查看文档
使用注解读取 cookie
如果知道 cookie
的名字,就可以通过注解的方式读取,不需要再遍历 cookie
数组了,更加方便。
为 control
类的方法增加一个 @CookieValue("xxxx") String xxxx
参数即可,注意使用时要填入正确的 cookie
名字。
系统会自动解析并传入同名的
cookie
import org.springframework.web.bind.annotation.CookieValue;@RequestMapping("/songlist")
public Map index(@CookieValue("JSESSIONID") String jSessionId) {Map returnData = new HashMap();returnData.put("result", "this is song list");returnData.put("author", songAuthor);returnData.put("JSESSIONID", jSessionId);return returnData;
}
请看代码演示:
注意:如果系统解析不到指定名字的 cookie,使用此注解就会报错。必须谨慎使用。
写 Cookie
同样,也很简单。为 control
类的方法增加一个 HttpServletResponse
参数,调用 response.addCookie()
方法添加 Cookie
实例对象即可。
系统会自动传入方法参数所需要的
HttpServletResponse
对象哦
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;@RequestMapping("/songlist")
public Map index(HttpServletResponse response) {Map returnData = new HashMap();returnData.put("result", "this is song list");returnData.put("name", songName);Cookie cookie = new Cookie("sessionId","CookieTestInfo");// 设置的是 cookie 的域名,就是会在哪个域名下生成 cookie 值cookie.setDomain("youkeda.com");// 是 cookie 的路径,一般就是写到 / ,不会写其他路径的cookie.setPath("/");// 设置cookie 的最大存活时间,-1 代表随浏览器的有效期,也就是浏览器关闭掉,这个 cookie 就失效了。cookie.setMaxAge(-1);// 设置是否只能服务器修改,浏览器端不能修改,安全有保障cookie.setHttpOnly(false);response.addCookie(cookie);returnData.put("message", "add cookie successful");return returnData;
}
Cookie 的各个属性的作用,注意看代码注释哦
注意,Cookie
类的构造函数,第一个参数是 cookie 名称,第二个参数是 cookie 值。而且其他的属性,需要根据实际情况和具体的业务需求决定。
Spring Session API
Cookie
放在客户端,可以存储用户登录信息,主要用于辨识用户身份。
但如果真的把用户ID、登录状态等重要信息放入 cookie
,会带来安全隐患,因为网络上很不安全,cookie
可能会拦截、甚至伪造。
采用 Session
会话机制可以解决这个问题,用户ID、登录状态等重要信息不存放在客户端,而是存放在服务端,从而避免安全隐患。
使用会话机制时,Cookie
作为 session id
的载体与客户端通信。上一节课演示代码中,Cookie
中的 JSESSIONID
就是这个作用。
名字为 JSESSIONID 的 cookie,是专门用来记录用户session的。JSESSIONID 是标准的、通用的名字。
在了解 Session
与 Cookie
之间的关系后,我们来学习如何使用 Session
,也分为读、写两种操作。
读操作
与 cookie
相似,从 HttpServletRequest
对象中取得 HttpSession
对象,使用的语句是 request.getSession()
。
但不同的是,返回结果不是数组,是对象。在 attribute
属性中用 key -> value 的形式存储多个数据。
假设存储登录信息的数据 key
是 userLoginInfo
,那么语句就是 session.getAttribute("userLoginInfo")
。
登录信息类
登录信息实例对象因为要在网络上传输,就必须实现序列化接口 Serializable
,否则不实现的话会报错。
登录信息类需要根据具体的需要设计属性字段。下列代码的两个属性仅供演示。
import java.io.Serializable;public class UserLoginInfo implements Serializable {private String userId;private String userName;
}
操作代码
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;@RequestMapping("/songlist")
public Map index(HttpServletRequest request, HttpServletResponse response) {Map returnData = new HashMap();returnData.put("result", "this is song list");// 取得 HttpSession 对象HttpSession session = request.getSession();// 读取登录信息UserLoginInfo userLoginInfo = (UserLoginInfo)session.getAttribute("userLoginInfo");if (userLoginInfo == null) {// 未登录returnData.put("loginInfo", "not login");} else {// 已登录returnData.put("loginInfo", "already login");}return returnData;
}
这里实际上取不到数据,因为还没有写入。
写操作
假设登录成功,怎么记录登录信息到 Session
呢?
既然从 HttpSession
对象中读取登录信息用的是 getAttribute()
方法,那么写入登录信息就用 setAttribute()
方法。
下列代码演示了使用 Session
完成登录的过程,略去了校验用户名和密码的步骤(实际项目中需要):
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;@RequestMapping("/loginmock")
public Map loginMock(HttpServletRequest request, HttpServletResponse response) {Map returnData = new HashMap();// 假设对比用户名和密码成功// 仅演示的登录信息对象UserLoginInfo userLoginInfo = new UserLoginInfo();userLoginInfo.setUserId("12334445576788");userLoginInfo.setUserName("ZhangSan");// 取得 HttpSession 对象HttpSession session = request.getSession();// 写入登录信息session.setAttribute("userLoginInfo", userLoginInfo);returnData.put("message", "login successful");return returnData;
}
额外知识点
Cookie
存放在客户端,一般不能超过 4kb
,要特别注意,放太多的内容会导致出错;而 Session
存放在服务端,没有限制,不过基于服务端的性能考虑也不能放太多的内容。
Spring Session 配置
上面学了Session
的操作,在操作中,没有涉及到 cookie
。系统会自动把默认的 JSESSIONID
放在默认的 cookie
中。
但 Cookie
作为 session id
的载体,也可以修改属性。
前置知识点:配置
第 6 章我们讲了 application.properties
是 SpringBoot
的标准配置文件,配置一些简单的属性。同时,SpringBoot
也提供了编程式的配置方式,主要用于配置 Bean
。
基本格式:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class SpringHttpSessionConfig {@Beanpublic TestBean testBean() {return new TestBean();}
}
在类上添加 @Configuration
注解,就表示这是一个配置类,系统会自动扫描并处理。
在方法上添加 @Bean
注解,表示把此方法返回的对象实例注册成 Bean
。
跟
@Service
等写在类上的注解一样,都表示注册Bean
。
Session 配置
依赖库
先在 pom.xml
文件中增加依赖库:
<!-- spring session 支持 -->
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-core</artifactId>
</dependency>
配置类
在类上额外添加一个注解:@EnableSpringHttpSession
,开启 session
。然后,注册两个 bean
:
CookieSerializer
:读写 Cookies 中的 SessionId 信息MapSessionRepository
:Session 信息在服务器上的存储仓库。
import org.springframework.session.MapSessionRepository;
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;import java.util.concurrent.ConcurrentHashMap;@Configuration
@EnableSpringHttpSession
public class SpringHttpSessionConfig {@Beanpublic CookieSerializer cookieSerializer() {DefaultCookieSerializer serializer = new DefaultCookieSerializer();serializer.setCookieName("JSESSIONID");// 用正则表达式配置匹配的域名,可以兼容 localhost、127.0.0.1 等各种场景serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");serializer.setCookiePath("/");serializer.setUseHttpOnlyCookie(false);// 最大生命周期的单位是秒serializer.setCookieMaxAge(24 * 60 * 60);return serializer;}// 当前存在内存中@Beanpublic MapSessionRepository sessionRepository() {return new MapSessionRepository(new ConcurrentHashMap<>());}
}
想必大家已经了解了 Cookie
各属性值的作用,这里就不赘述了。
这段代码有些长,是 Spring 官方推荐的比较标准的写法:点此阅读官方文档。当前的重点是学习如何使用。
Spring Request 拦截器
在上节课的练习中我们模拟了用户登录以及提供了查询登录状态的方法。
在实际的项目中,会有大量的页面功能是需要判断用户是否登录的。例如电商的网站,订单、购物车、管理收货地址等等,都需要登录。那么让每一个页面都判断是否登录、未登录跳转到登录页,就太繁琐了,也不利于维护。
所以需要一种统一处理相同逻辑的机制,Spring
提供了 HandlerInterceptor
(拦截器)满足这种场景的需求。
实现拦截器也不同负责,有三个步骤:
一、创建拦截器
拦截器必须实现 HandlerInterceptor
接口。可以在三个点进行拦截:
- Controller方法执行之前。这是最常用的拦截点。例如是否登录的验证就要在
preHandle()
方法中处理。 - Controller方法执行之后。例如记录日志、统计方法执行时间等,就要在
postHandle()
方法中处理。 - 整个请求完成后。不常用的拦截点。例如统计整个请求的执行时间的时候用,在
afterCompletion
方法中处理。
请看下列示例代码:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class InterceptorDemo implements HandlerInterceptor {// Controller方法执行之前@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 只有返回true才会继续向下执行,返回false取消当前请求return true;}//Controller方法执行之后@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {}// 整个请求完成后(包括Thymeleaf渲染完毕)@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
preHandle()` 方法的参数中有 `HttpServletRequest` 和 `HttpServletResponse`,可以像 `control` 中一样使用 `Session
二、实现 WebMvcConfigurer
创建一个类实现 WebMvcConfigurer
,并实现 addInterceptors()
方法。这个步骤用于管理拦截器。
注意:实现类要加上
@Configuration
注解,让框架能自动扫描并处理。
管理拦截器,比较重要的是为拦截器设置拦截范围。常用 addPathPatterns("/**")
表示拦截所有的 URL
。
当然也可以调用 excludePathPatterns()
方法排除某些 URL
,例如登录页本身就不需要登录,需要排除。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebAppConfigurerDemo implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 多个拦截器组成一个拦截器链// 仅演示,设置所有 url 都拦截registry.addInterceptor(new UserInterceptor()).addPathPatterns("/**");}
}
学习拦截器,要注意理解和体会 拦截器 与 管理拦截器 分开的思想。思考一下:如果不分开处理,由拦截器本身决定在什么情况下进行拦截,是否更好?
通常拦截器,会放在一个包(例如interceptor
)里。而用于管理拦截器的配置类,会放在另一个包(例如config
)里。
这种按功能划分子包的方式,可以让阅读者比较直观、清晰的了解各个类的作用。
相关文章:

Cookie与Session 实现登录操作
Cookie Cookie 是网络编程中使用最广泛的一项技术,主要用于辨识用户身份。 客户端(浏览器)与网站服务端通讯的过程如下图所示: 从图中看,服务端既要返回 Cookie 给客户端,也要读取客户端提交的 Cookie。所…...

通过IEC104转MQTT网关轻松接入阿里云平台
随着智能电网和物联网技术的飞速发展,电力系统中的传统IEC 104协议设备正面临向现代化、智能化转型的迫切需求。阿里云作为全球领先的云计算服务提供商,其强大的物联网平台为IEC 104设备的接入与数据处理提供了强大的支持。本文将深入探讨钡铼网关在MQTT…...
lua 游戏架构 之 游戏 AI (五)ai_autofight_find_way
这段Lua脚本定义了一个名为 ai_autofight_find_way 的类,继承自 ai_base 类。 lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客文章浏览阅读238次。定义了一套接口和属性,可以基于这个基础类派生出具有特定行为的AI组件。例如&…...

vue3+openLayers点击标记事件
<template><!--地图--><div class"distributeMap" id"distributeMap"></div> </template> <script lang"ts" setup> import { onMounted, reactive } from "vue"; import { Feature, Map, View }…...

深入分析 Android ContentProvider (三)
文章目录 深入分析 Android ContentProvider (三)ContentProvider 的高级使用和性能优化1. 高级使用场景1.1. 数据分页加载示例:分页加载 1.2. 使用 Loader 实现异步加载示例:使用 CursorLoader 加载数据 1.3. ContentProvider 与权限管理示例࿱…...

养宠浮毛异味双困扰?性价比高的宠物空气净化器推荐
家里养了两只银渐层,谁懂啊!一下班打开家门就看到家里飘满了猫浮毛雪,空气中还传来隐隐约约的异味。每天不是在吸毛的路上,就是在洗猫砂盆的路上,而且空气中的浮毛还很难清理干净,这是最让人头疼的问题。 …...

maven项目容器化运行之3-优雅的利用Jenkins和maven使用docker插件调用远程docker构建服务并在1Panel中运行
一.背景 在《maven项目容器化运行之1》中,我们开启了1Panel环境中docker构建服务给到了局域网。在《maven项目容器化运行之2》中,我们基本实现了maven工程创建、远程调用docker构建镜像、在1Panel选择镜像运行容器三大步骤。 但是,存在一个问…...

docker 打包orbbec
docker pull humble容器 sudo docker run -it osrf/ros:humble-desktop docker 启动容器 sudo docker run -u root --device/dev/bus/usb:/dev/bus/usb -it -v /home/wl:/share --name wl4 osrf/ros:humble-desktop /bin/bash新开一个终端 查看本地存在的容器:…...

无涯·问知财报解读,辅助更加明智的决策
财报解读就像是给公司做一次全面的体检,是理解公司内部运作机制和市场表现的一把钥匙,能够有效帮助投资者、分析师、管理层以及所有市场参与者判断一家公司的健康程度和发展潜力。 星环科技无涯问知的财经库内置了企业年报及财经类信息,并对…...

【Apache Doris】数据副本问题排查指南
【Apache Doris】数据副本问题排查指南 一、问题现象二、问题定位三、问题处理 本文主要分享Doris中数据副本异常的问题现象、问题定位以及如何处理此类问题。 一、问题现象 问题日志 查询报错 Failed to initialize storage reader, tablet{tablet_id}.xxx.xxx问题说明 查…...

【HarmonyOS】关于鸿蒙消息推送的心得体会(二)
【HarmonyOS】关于鸿蒙消息推送的心得体会(二) 前言 推送功能的开发与传统功能开发还是有很大区别。首先最大的区别点就在于需要多部门之间的协同,作为鸿蒙客户端开发,你需要和产品,运营,以及后台开发一起…...

零基础入门:创建一个简单的Python爬虫管理系统
摘要: 本文将手把手教你,从零开始构建一个简易的Python爬虫管理系统,无需编程基础,轻松掌握数据抓取技巧。通过实战演练,你将学会设置项目、编写基本爬虫代码、管理爬取任务与数据,为个人研究或企业需求奠…...

【Node.js基础04】node.js模块化
一:什么是模块化 在Node.js中,每个文件都可视为一个独立的模块。模块化提高了代码的复用性,按需加载,具有独立的作用域 二:如何实现多个文件间导入和导出 1 CommonJS标准(默认)-导入和导出 …...

数据库——单表查询
一、建立数据库mydb8_worker mysql> use mydb8_worker; 二、建立表 1.创建表 mysql> create table t_worker(department_id int(11) not null comment 部门号,-> worder_id int(11) primary key not null comment 职工号,-> worker_date date not null comment…...
dsa加训
refs: OI Wiki - OI Wiki (oi-wiki.org) 1. 枚举 POJ 2811 熄灯问题 refs : OpenJudge - 2811:熄灯问题 如果要枚举每个灯开或者不开的情况,总计2^30种情况,显然T。 不过我们可以发现:若第i行的某个灯亮了,那么有且仅有第i行和第…...

SpringBoot源码(1)ApplicationContext和BeanFactory
1、调用getBean方法 SpringBootApplication public class SpringBootDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext applicationContext SpringApplication.run(SpringBootDemoApplication.class, args);applicationContext.get…...

CANoe编程实例--TCP/IP通信
1、简介 本实例将使用目前常用的开发工具C#来开发服务器端,以CANoe端作为客户端。服务器端和客户端,通过TCP/IP连接,实现数据交换。 首先在服务器端建立一个监听Socket,自动创建一个监听线程,随时监听是否有客户端的连…...

Neuron协议网关的北向应用插件开发
目录 概述 指令处理层开发 应用层开发 .open .close .init .uninit .start .stop .setting .request 插件设置文件 适配华为的思路 概述 最近研究了一段时间的Neuron协议网关,前面的博文也提到它虽然能够把数据发到华为的IoT平台上…...

【BUG】已解决:You are using pip version 10.0.1, however version 21.3.1 is available.
You are using pip version 10.0.1, however version 21.3.1 is available. 目录 You are using pip version 10.0.1, however version 21.3.1 is available. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#…...

electron-builder打包vue2项目不显示element-ui图标
1、使用版本 vue ^2.6.14element-ui ^2.15.14vue-cli-plugin-electron-builder 2.1.1 2、解决办法 1) 如果是简单的图标可以使用图片代替(这种对于elementui组件的图标还是不会显示) 2)在vue.config.js配置 const { defineCon…...

controller层-请求格式为json-请求方法为get
前置条件 get请求映射,内容和PostMapping一致,需要请求参数更换为get数据 请求过程:用户请求--初始化DispatcherServlet及对接和分发用户请求--controller--service 用户请求:http://ip:port/user/getinfo 请求方法:ge…...

【Linux】网络通信基础:应用层协议、HTTP、序列化与会话管理
文章目录 前言1. 应用层自定义协议与序列化1.1 什么是应用层?1.2 再谈 "协议"1.3 序列化 和 反序列化 2. HTTP 协议3. 认识 URL(统一资源定位符)4. urlencode和urldecode5. HTTP 协议请求与响应格式5.1 HTTP 请求5.2 HTTP 响应 6. HTTP 的方法6.1 GET 方法…...

@NotNull、@NotEmpty 和 @NotBlank 区别
NotNull、NotEmpty 和 NotBlank 是 Java Bean Validation (JSR 380) 规范中定义的注解,通常用于验证对象的属性是否满足特定的条件。这些注解常用于后端验证,确保接收到的数据符合预期。 NotNull 用途:验证一个对象是否不为null。 注意&#…...

大模型应用—大模型赋能网络爬虫
大模型赋能网络爬虫 简单来说,网页抓取就是从网站抓取数据和内容,然后将这些数据保存为XML、Excel或SQL格式。除了用于生成潜在客户、监控竞争对手和市场研究外,网页抓取工具还可以用于自动化你的数据收集过程。 借助AI网页抓取工具,可以解决手动或纯基于代码的抓取工具的…...

在 Qt 中获取 MouseMove 事件
在编写 Qt 程序时,我希望在鼠标移动时(即使鼠标在另一个窗口上)能够调用 mouseMoveEvent(QMouseEvent* event) 方法。目前,在我的 mainwindow.cpp 文件中,我有如下代码: void MainWindow::mouseMoveEvent(…...

自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍
自动驾驶系列—智能巡航辅助功能中的车道中央保持功能介绍 自动驾驶系列—智能巡航辅助功能中的车道变换功能介绍 自动驾驶系列—智能巡航辅助功能中的横向避让功能介绍 自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍 文章目录 2. 功能定义3. 功能原理4. 传感器架构5. 实…...

如何为WordPress网站设置多语言站点
随着全球化的发展,拥有一个支持多语言的站点已成为提升用户体验、扩大受众范围的重要手段。本文将详细介绍如何为WordPress网站设置多语言站点,提供两种最佳方案详解,帮助您轻松实现多语言站点的搭建与管理。无论您是选择在同一站点内发布多语…...

【RHCE】综合真机实验(shell完成)
目录 题目: 需求描述 实操 一、服务端(servera) 1.ip配置 2.更改主机名 3.创建本地仓库 4.DNS服务 1.下载软件包和防火墙允许 2.配置主配置文件 3.配置区域文件 1.named.exam 2.named.fangxiang 4.重启服务 5.验证结果&#x…...

【Python】成功解决conda创建虚拟环境时出现的CondaHTTPError: HTTP 000 CONNECTION FAILED错误
【Python】成功解决conda创建虚拟环境时出现的CondaHTTPError: HTTP 000 CONNECTION FAILED错误 🌈 欢迎莅临我的个人主页👈这里是我深耕Python编程、机器学习和自然语言处理(NLP)领域,并乐于分享知识与经验的小天地&a…...

苹果笔记本电脑如何优化系统 苹果电脑系统优化软件哪个好 cleanmymac x怎么用
随着时间的推移,你可能会发现你的MacBook运行速度变慢,甚至在执行一些基本任务时也会感觉到卡顿。这不仅影响了工作效率,也大大降低了使用体验。但别担心,优化你的Mac系统比做早餐还简单。本文将用一种轻松的风格向你介绍7种简单易…...