文章目录
1. Cookie
主要分析服务端 Spring 工程是如何使用 Cookie 的,有读、写两种操作
1.1 读Cookie
为 Control
类的方法增加一个HttpServletRequest
参数,通过request.getCookies()
取得cookie
数组,然后再循环遍历数组即可
系统会自动传入方法参数所需要的的HttpServletRequest
对象
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
@RestController
public class SongListControl {
//从配置文件中读取自定义的配置项
@Value("${song.author}")
private String songAuthor;
@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;
}
}
1.2 使用注解读取 Cookie
必须要知道 cookie 的名字,才可以使用。
为control
类的方法增加一个@CookieValue("xxxx") String xxxx
参数即可,系统会自动解析并传入同名的 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("JSESSIONID", jSessionId);
return returnData;
}
如果系统解析不到指定名字的 Cookie,使用此注解就会报错
1.3 写 Cookie
为control
类的方法增加一个HttpServletResponse
参数,调用response.addCookie()
方法添加Cookie
实例对象。
系统会自动传入方法参数所需要的HttpServletResponse
对象
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
@RequestMapping("/songlist")
public Map index(HttpServletResponse response) {
Cookie cookie = new Cookie("sessionId", "CookieTestInfo");
//设置的是 cookie 的域名,就是会在哪个域名下生成 cookie 值
cookie.setDomain("*****");
//设置的是 cookie 的路径,一般就是写到 / ,不会写其他路径的
cookie.setPath("/");
//设置 cookie 的最大存活时间,-1代表随浏览器的有效期
cookie.setMaxAge(-1);
//设置是否只能服务器修改,浏览器端不能修改
cookie.setHttpOnly(false);
response.addCookie(cookie);
return new HashMap();
}
2. Spring Session API
采用 Session 会话机制将用户ID、登录状态等重要信息放在服务端,避免安全隐患
使用会话机制时,Cookie 作为 session id 的载体与客户端通信。上面文章中的代码中,Cookie 中的 JSESSIONID就是这个作用。
名字为 JSESSIONID 的cookie,是专门用来记录用户 session 的。JSESSIONID 是标准的、通用的名字
2.1 读操作
从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;
//get、set方法省略
}
操作代码
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();
//取得 HTTPSession 对象
HttpSession session = request.getSession();
//读取登录信息(取出来的为Object类型,要进行强制转换)
UserLoginInfo userLoginInfo = (UserLoginInfo) session.getAttribute("userLoginInfo");
if (userLoginInfo == null) {
//未登录
} else {
//已登录
}
return new HashMap();
}
2.2 写操作
假设登录成功,如何记录登录信息到 Session 呢?
写入信息用setAttribute()
方法
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@RequestMapping("/loginmock")
public Map loginMock(HttpServletRequest request, HttpServletResponse response) {
UserLoginInfo userLoginInfo = new UserLoginInfo();
userLoginInfo.setUserId("12345");
userLoginInfo.setUserName("hahah");
//取得 HttpSession 对象
HttpSession session = request.getSession();
//写入登录信息
session.setAttribute("userLoginInfo", userLoginInfo);
return new HashMap();
}
3. Spring Session 配置
上面代码中,没有涉及 cookie,系统会自动把默认的JSESSIONID
放在默认的cookie
中。但 Cookie 作为 session id 的载体,也可以修改属性
配置
application.properties
是SpringBoot
的标准配置文件,配置一些简单的属性,同时,Spring Boot
也提供了编程式的配置方式,主要用于配置Bean
。
基本格式:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringHttpSessionConfig {
@Bean
public TestBean testBean() {
return new TestBean();
}
}
在类上添加@Configuration
注解,就表示这是一个配置类,系统会自动扫描并处理,在方法上添加@Bean
注解,表示把此方法返回的对象实例注册成Bean
3.1 Session 配置
3.1.1 依赖库
<!-- spring session 支持 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
3.1.2 配置类
在类上额外加一个注解:@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 {
@Bean
public 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;
}
@Bean
public MapSessionRepository sessionRepository() {
return new MapSessionRepository(new ConcurrentHashMap<>());
}
}
4. Spring Request 拦截器
大量的页面功能是需要判断用户是否登录了
4.1 创建拦截器
拦截器必须实现HandlerInterceptor
接口
三个拦截点:
Controller
方法执行之前。例如是否登录的验证就是在preHandler()
方法中处理Controller
方法执行之后。例如记录日志、统计方法、执行时间等,就要在postHandler
方法中处理- 整个请求完成后。例如统计整个请求的执行时间在
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 UserInterceptor implements HandlerInterceptor {
//Controller方法执行之前
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//只有返回 true 才会继续向下执行,返回 false 取消当前请求
return true;
}
//Controller方法执行之后
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
//整个请求完成后(包括 Thymeleaf 渲染完毕)
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
4.2 实现 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 {
@Override
public void addInterceptors(InterceptoryRegistry registry) {
//多个拦截器组成一个拦截器链
registry.addInterceptor(new UserInterceptor()).addPathPatterns("/**");
}
}