1.安装redis,并配置密码
这里就不针对于redis的安装约配置进行说明了,直接在项目中使用。
redis在windows环境下安装:window下redis的安装和部署详细图文教程_redis_代码网 (jb51.net)
2.pom.xml文件中引入需要的maven
<dependency> <groupid>redis.clients</groupid> <artifactid>jedis</artifactid> <version>2.9.0</version> </dependency>
3.在项目的配置文件中加入redis的配置
redis:
database: 0
host: localhost
password: 123456
pool:
max-active: 8
max-idle: 8
max-wait: -1
min-idle: 0
port: 6379
timeout: 30004.添加redis的配置文件放在项目的config文件夹下
import org.springframework.beans.factory.annotation.value;
import org.springframework.cache.annotation.cachingconfigurersupport;
import org.springframework.cache.annotation.enablecaching;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.data.redis.connection.redisconnectionfactory;
import org.springframework.data.redis.connection.jedis.jedisconnectionfactory;
import redis.clients.jedis.jedispool;
import redis.clients.jedis.jedispoolconfig;
/**
* @author kjz
*/
@configuration
@enablecaching
public class redisconfig extends cachingconfigurersupport {
@value("${redis.host}")
private string host;
@value("${redis.port}")
private int port;
@value("${redis.timeout}")
private int timeout;
@value("${redis.pool.max-idle}")
private int maxidle;
@value("${redis.pool.max-wait}")
private long maxwaitmillis;
@value("${redis.password}")
private string password;
@bean
public jedispool redispoolfactory() {
jedispoolconfig jedispoolconfig = new jedispoolconfig();
jedispoolconfig.setmaxidle(maxidle);
jedispoolconfig.setmaxwaitmillis(maxwaitmillis);
jedispool jedispool = new jedispool(jedispoolconfig, host, port, timeout);
return jedispool;
}
@bean
public redisconnectionfactory redisconnectionfactory() {
jedispoolconfig jedispoolconfig = new jedispoolconfig();
jedispoolconfig.setmaxidle(maxidle);
jedispoolconfig.setmaxwaitmillis(maxwaitmillis);
jedisconnectionfactory jedisconnectionfactory = new jedisconnectionfactory(jedispoolconfig);
jedisconnectionfactory.sethostname(host);
jedisconnectionfactory.setport(port);
jedisconnectionfactory.settimeout(timeout);
jedisconnectionfactory.setpassword(password);
return jedisconnectionfactory;
}
}5.具体实现思路(手动实现)
实现思路
创建一个过滤器,拦截除了登录之外的所有请求,判断请求中是否存在cookie,如果存在cookie则判断redis中是否存在以cookie为key的键值对数据,如果有则取出对应的value同时对这个key的过期时间进行续期,如果没有则返回一个响应,说明登录已经过期了,将value就是session进行jason反序列化得到session对象,然后把session绑定到当前的请求中,如果不存在cookie,则直接返回一个响应,说明还未登录。如果是登录请求的话,直接到controller中进行登录校验,让深沉的session通过json序列化放到redis中,并且以uuid为key,同时,返回给前端一个cookie字段,cookie字段的值就是uuid,请求完成之后,在过滤器中将会话数据session更新到redis中。
下面是思路流程图

代码实现
创建过滤器 sessionfilter
import com.fasterxml.jackson.databind.objectmapper;
import redis.clients.jedis.jedis;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.ioexception;
import java.util.hashmap;
import java.util.map;
import java.util.uuid;
public class sessionfilter implements filter {
private jedispool jedispool;
private objectmapper objectmapper;
private static final string login_path = "/login";
private static final int session_expiration_time = 30 * 60; // 30 minutes in seconds
public sessionfilter(jedispool jedispool) {
this.jedispool = jedispool;
this.objectmapper = new objectmapper();
}
@override
public void dofilter(servletrequest request, servletresponse response, filterchain chain)
throws ioexception, servletexception {
httpservletrequest httprequest = (httpservletrequest) request;
httpservletresponse httpresponse = (httpservletresponse) response;
string requesturi = httprequest.getrequesturi();
if (requesturi.equals(login_path)) {
// 直接转发到登录控制器
chain.dofilter(request, response);
} else {
// 检查 cookie
cookie[] cookies = httprequest.getcookies();
string sessionid = null;
if (cookies != null) {
for (cookie cookie : cookies) {
if ("sessionid".equals(cookie.getname())) {
sessionid = cookie.getvalue();
break;
}
}
}
if (sessionid != null) {
try (jedis jedis = jedispool.getresource()) {
string sessiondatajson = jedis.get(sessionid);
if (sessiondatajson != null) {
// 续期
jedis.expire(sessionid, session_expiration_time);
// 反序列化 session
map<string, object> sessionattributes = objectmapper.readvalue(sessiondatajson, map.class);
httpsessionwrapper wrappedsession = new httpsessionwrapper(sessionattributes);
request.setattribute("httpsession", wrappedsession);
// 继续执行过滤器链
chain.dofilter(request, response);
// 更新 session 到 redis
if (wrappedsession.isdirty()) {
jedis.set(sessionid, objectmapper.writevalueasstring(wrappedsession.getsessiondata()));
}
} else {
// 登录过期
httpresponse.setcontenttype("application/json");
httpresponse.getwriter().write("{\"error\": \"session expired\"}");
}
} catch (exception e) {
// 处理异常
e.printstacktrace();
httpresponse.senderror(httpservletresponse.sc_internal_server_error);
}
} else {
// 未登录
httpresponse.setcontenttype("application/json");
httpresponse.getwriter().write("{\"error\": \"not logged in\"}");
}
}
}
// ... 其他 filter 方法 ...
}注册过滤器
在 spring 配置中注册过滤器:
@bean
public filterregistrationbean<sessionfilter> sessionfilterregistration(sessionfilter sessionfilter) {
filterregistrationbean<sessionfilter> registrationbean = new filterregistrationbean<>();
registrationbean.setfilter(sessionfilter);
registrationbean.addurlpatterns("/*");
return registrationbean;
}创建 httpsessionwrapper 类
将session和sessionid封装到这个类里面
import javax.servlet.http.httpsession;
import java.util.enumeration;
import java.util.hashmap;
import java.util.map;
public class httpsessionwrapper implements httpsession {
private final map<string, object> attributes;
private boolean dirty;
public httpsessionwrapper(map<string, object> attributes) {
this.attributes = attributes;
this.dirty = false;
}
// ... 实现 httpsession 接口的方法 ...
public void setattribute(string name, object value) {
attributes.put(name, value);
dirty = true;
}
public map<string, object> getsessiondata() {
return attributes;
}
public boolean isdirty() {
return dirty;
}
// ... 其他方法 ...
}登录控制器
@restcontroller
public class logincontroller {
@postmapping("/login")
public httpservletresponse login(httpservletrequest request, httpservletresponse response) {
// ... 登录逻辑 ...
// 创建新的会话
string sessionid = uuid.randomuuid().tostring();
map<string, object> sessionattributes = new hashmap<>();
// 填充会话属性
sessionattributes.put("user", user);
// 使用 jsonutil 序列化会话并存储到 redis
string sessiondatajson = jsonutil.obj2string(sessionattributes);
try (jedis jedis = jedispool.getresource()) {
jedis.setex(sessionid, session_expiration_time, sessiondatajson);
} catch (exception e) {
// 处理异常
e.printstacktrace();
return "error";
}
// 创建 cookie 并设置给客户端
cookie sessioncookie = new cookie("sessionid", sessionid);
sessioncookie.setpath("/");
sessioncookie.sethttponly(true); // 确保 cookie 不会被 javascript 访问
sessioncookie.setsecure(true); // 确保 cookie 在 https 连接中传输
response.addcookie(sessioncookie);
return httpservletresponse ;
}
}下面是序列化工具类
import com.fasterxml.jackson.annotation.jsoninclude;
import com.fasterxml.jackson.core.type.typereference;
import com.fasterxml.jackson.databind.javatype;
import com.fasterxml.jackson.databind.objectmapper;
import lombok.extern.slf4j.slf4j;
import org.apache.commons.lang.stringutils;
/**
*@author kjz
*/
@slf4j
public class jsonutil {
private static objectmapper objectmapper = new objectmapper();
static{
//对象的所有字段全部列入
objectmapper.setserializationinclusion(jsoninclude.include.always);
}
public static <t> string obj2string(t obj){
if(obj == null){
return null;
}
try {
return obj instanceof string ? (string)obj : objectmapper.writevalueasstring(obj);
} catch (exception e) {
log.warn("parse object to string error",e);
return null;
}
}
/**
* 格式化json串,看起来比较好看,但是有换行符等符号,会比没有格式化的大
* @param obj
* @param <t>
* @return
*/
public static <t> string obj2stringpretty(t obj){
if(obj == null){
return null;
}
try {
return obj instanceof string ? (string)obj : objectmapper.writerwithdefaultprettyprinter().writevalueasstring(obj);
} catch (exception e) {
log.warn("parse object to string error",e);
return null;
}
}
public static <t> t string2obj(string str,class<t> clazz){
if(stringutils.isempty(str) || clazz == null){
return null;
}
try {
return clazz.equals(string.class)? (t)str : objectmapper.readvalue(str,clazz);
} catch (exception e) {
log.warn("parse string to object error",e);
return null;
}
}
public static <t> t string2obj(string str, typereference<t> typereference){
if(stringutils.isempty(str) || typereference == null){
return null;
}
try {
return (t)(typereference.gettype().equals(string.class)? str : objectmapper.readvalue(str,typereference));
} catch (exception e) {
log.warn("parse string to object error",e);
return null;
}
}
/**
* 转换集合
* list<user></>
* @param str
* @param collectionclass
* @param elementclasses
* @param <t>
* @return
*/
public static <t> t string2obj(string str,class<?> collectionclass,class<?>... elementclasses){
javatype javatype = objectmapper.gettypefactory().constructparametrictype(collectionclass,elementclasses);
try {
return objectmapper.readvalue(str,javatype);
} catch (exception e) {
log.warn("parse string to object error",e);
return null;
}
}
}6.利用spring session data redis框架实现
引入spring session data redis 的依赖
<dependency>
<groupid>org.springframework.session</groupid>
<artifactid>spring-session-data-redis</artifactid>
<version>2.7.0</version>
</dependency>创建spring session的配置类
创建一个配置类 sessionconfig,使用 @enableredishttpsession 注解来启用 spring session 的 redis 支持:
import org.springframework.session.data.redis.config.configureredisaction;
import org.springframework.session.data.redis.config.annotation.web.http.redishttpsessionconfiguration;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
@configuration
@enableredishttpsession
public class sessionconfig {
// 配置会话过期时间(例如,设置为 1800 秒,即 30 分钟)
@bean
public redishttpsessionconfiguration redishttpsessionconfiguration() {
redishttpsessionconfiguration configuration = new redishttpsessionconfiguration();
configuration.setmaxinactiveintervalinseconds(1800);
return configuration;
}
// 如果你使用的是 spring boot 2.3 或更高版本,你可能需要定义这个 bean 来避免警告
@bean
public static configureredisaction configureredisaction() {
return configureredisaction.no_op;
}
}@enableredishttpsession 是一个方便的注解,它做了以下几件事情:
- 启用 spring session 的支持,使得 httpsession 能够被 spring session 管理。
- 配置 redis 作为会话数据的存储后端。
- 注册一个
sessionrepositoryfilter的 bean,这个 filter 负责拦截请求,并将标准的 httpsession 替换为 spring session 的实现。
session的创建存储和获取
做完上面的配置之后,你可以像使用常规 httpsession 一样使用 spring session。每次修改会话时,spring session 都会自动将这些更改同步到 redis。
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;
import javax.servlet.http.httpsession;
@restcontroller
public class sessioncontroller {
@getmapping("/setsession")
public string setsession(httpsession session) {
session.setattribute("message", "hello, redis session!");
return "session set in redis";
}
@getmapping("/getsession")
public string getsession(httpsession session) {
return "session message: " + session.getattribute("message");
}
}以上就是springboot使用redis实现session共享的详细内容,更多关于springboot redis session共享的资料请关注代码网其它相关文章!
发表评论