Spring Boot Sample 032之spring-boot-session
一、环境
Idea 2020.1
JDK 1.8
maven
二、目的
spring boot 通过整合session的多种方式
gitHub地址: https://github.com/ouyushan/ouyushan-spring-boot-samples
三、步骤
3.1、点击File -> New Project -> Spring Initializer,点击next
3.2、在对应地方修改自己的项目信息
3.3、选择Web依赖,选中Spring Web、Spring Session、Spring Data JDBC、H2 DataBase、Spring Data Redis、Spring Data MongoDB、Spring Boot DevTools。可以选择Spring Boot版本,本次默认为2.3.0,点击Next
3.4、项目结构
四、添加文件
pom.xml文件
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Compile -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>redis</id>
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>jdbc</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>hazelcast</id>
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-hazelcast</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>mongodb</id>
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
application.properties文件
spring.security.user.name=user
spring.security.user.password=password
management.endpoints.web.exposure.include=*
######## REDIS ########
Redis数据库索引(默认为0)
spring.redis.database=0
Redis服务器地址
spring.redis.host=127.0.0.1
Redis服务器连接端口
spring.redis.port=6379
Redis服务器连接密码(默认为空)
spring.redis.password=
连接超时时间(毫秒)
spring.redis.timeout=3000
连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=8
连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=-1
连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
hazelcast.xml
<map name="spring:session:sessions">
<attributes>
<attribute extractor="org.springframework.session.hazelcast.PrincipalNameExtractor">principalName</attribute>
</attributes>
<indexes>
<index>principalName</index>
</indexes>
</map>
<network>
<join>
<multicast enabled="false"/>
</join>
</network>
LettuceRedisConfig.java
package org.ouyushan.springboot.session.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.annotation.Resource;
/**
- @Description:
- @Author: ouyushan
- @Email: ouyushan@hotmail.com
- @Date: 2020/5/11 9:55
*/
@Configuration
@EnableCaching
public class LettuceRedisConfig {
@Resource
private LettuceConnectionFactory lettuceConnectionFactory;
// 缓存管理器
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory lettuceConnectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.builder(lettuceConnectionFactory).build();
return redisCacheManager;
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
// key序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 使用Jackson ,将对象序列化为JSON
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//json 转对象类,不设置默认的会将json转成hashmap 报错:java.util.LinkedHashMap cannot be cast to XX
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
五、测试
SpringBootSessionApplicationTests.java
package org.ouyushan.springboot.session;
import org.junit.jupiter.api.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class SpringBootSessionApplicationTests {
@Test
public void sessionExpiry() throws Exception {
ConfigurableApplicationContext context = createContext();
String port = context.getEnvironment().getProperty("local.server.port");
URI uri = URI.create("http://localhost:" + port + "/");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> firstResponse = firstRequest(restTemplate, uri);
String sessionId1 = firstResponse.getBody();
String cookie = firstResponse.getHeaders().getFirst("Set-Cookie");
String sessionId2 = nextRequest(restTemplate, uri, cookie).getBody();
assertThat(sessionId1).isEqualTo(sessionId2);
Thread.sleep(1000);
String loginPage = nextRequest(restTemplate, uri, cookie).getBody();
assertThat(loginPage).containsIgnoringCase("login");
}
private ConfigurableApplicationContext createContext() {
ConfigurableApplicationContext context = new SpringApplicationBuilder().sources(SpringBootSessionApplication.class)
.properties("server.port:0", "server.servlet.session.timeout:1")
.initializers(new ServerPortInfoApplicationContextInitializer()).run();
return context;
}
private ResponseEntity<String> firstRequest(RestTemplate restTemplate, URI uri) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes()));
RequestEntity<Object> request = new RequestEntity<>(headers, HttpMethod.GET, uri);
return restTemplate.exchange(request, String.class);
}
private ResponseEntity<String> nextRequest(RestTemplate restTemplate, URI uri, String cookie) {
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie", cookie);
RequestEntity<Object> request = new RequestEntity<>(headers, HttpMethod.GET, uri);
return restTemplate.exchange(request, String.class);
}
}