Spring-session+mongodb实现session共享
pom.xml配置
首先需要引入依赖包,直接在pom.xml中添加以下代码即可。
<!-- spring-session整合mongodb -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongo</artifactId>
<version>1.3.3.RELEASE</version>
</dependency>
这里使用spring 4.x进行了项目的构建,这里说明一下,本项目使用spring 4.x进行构建,5.x的配置方式改变,请绕行。根据mavean的官方描述,该引用包含spring-session以及spring-data-mongo,一次性引入
web.xml配置
第一步使用spring-session拦截session,再web.xml中配置拦截器,特别注意,这个拦截器一般来说应该是优先级最高的,一定放到开头,拦截配置如下
<!-- spring-session 注意我的位置,一定要非常靠前-->
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring-session 结束-->
- 还是特别注意 ,一定要配置的很靠前,尤其系统内有用户登录session校验的,一定要在其后;
applicationContext.xml 核心配置文件
首先在文件头我们增加mongodb的引用 头部增加
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation中增加
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
完整代码–我这里引用了其他的,无视就好
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
增加mongodb的配置 注意一下这里Host port等各种参数应该在外部配置文件中,直接介绍图方便直接写在了配置文件中
<!-- mongodb数据源 -->
<mongo:mongo id="mongo" host="你的mongo的ip地址" port="你的mongo的端口">
<mongo:options connections-per-host="8" threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="1000" max-wait-time="1500" auto-connect-retry="true" socket-keep-alive="true" socket-timeout="1500"
slave-ok="true" write-number="1" write-timeout="0" write-fsync="true" />
</mongo:mongo>
<!-- mongo的工厂,通过它来取得mongo实例,testmongo为mongodb的数据库名,没有的话会自动创建 -->
<mongo:db-factory id="mongoDbFactory" dbname="testmongo" mongo-ref="mongo" />
<!-- mongodb的主要操作对象,所有对mongodb的增删改查的操作都是通过它完成 -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
增加mongodb对session的托管
<!-- 将session放入mongo -->
<bean id="mongoHttpSessionConfiguration"
class="org.springframework.session.data.mongo.config.annotation.web.http.MongoHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="1800" />
</bean>
在系统中使用session
以上已经配置完毕,我们启动项目以后登录,会在刚才配置的mongo中自动创建一个名为sesssions的表,使用该语法查看
db.sessions.find();
session正常已经正常存入了mongo,存入后,接下来涉及系统使用。我们都知道,再获取session内对象的时候,我们使用session.getAttribute("")方法,如果此时session中仅是存的简单的key-value格式,那么到此为止,全部工作已经完成,但是如果session中存放了比较复杂的对象,存了key-object这种,在我们直接通过session.get获取到内容以后,你会发现他是一个dbobject类型,结构为{aaa=123,bbb=456,ccc=789},这个内容无法直接强制转换为我们想要的java对象。接下来就要借助gson先将dbobject转为jsonstr,再将jsonstr转为obj
为了方便以后我们对session存储复杂对象的时候进行操作,我们封装一个工具类,用于获取session对象
package com.easternie.newframe.util;
import java.text.DateFormat;
import java.util.Date;
import javax.servlet.http.HttpSession;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* SessionUtil 用于处理是否使用mongodb作为session的缓存
* @author ZhangQiang
* 注意=如果使用mongo进行seesion共享需要进行以下操作。
* 1、再pom.xml引入spring-session-data-mongo
* 2、applicationcontext中引入mongo的jdbc 并将mongo注入session
* 3、web.xml中增加spring-session的拦截-注意往前放,作为第一道拦截
*/
public class SessionUtils {
//设置是否开启Mongo存储session 如果为true 从mongo中处理,false直接返回session的内容本身
static Boolean DOMONGOTRACE = true;
public static <T> T getMongoSession(HttpSession session,Class<?> t) {
return getMongoSession(session,t,null);
}
/**
*
* @param session - httpsession
* @param t - xxx.class
* @param className - 注意全字母大写,session的key理论上装载以后就要全部大写
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getMongoSession(HttpSession session,Class<?> t,String className) {
className = className == null? t.getSimpleName().toUpperCase() : className;
if(DOMONGOTRACE) {
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer()).setDateFormat(DateFormat.LONG).create();
return (T) gson.fromJson(gson.toJson(session.getAttribute(className)), t);
}else {
return (T) session.getAttribute(className);
}
}
}
在需要获取session中的对象的时候我们使用
User user = SessionUtils.getMongoSession(session, User.class);
这样就可以轻易获取到我们存入到session中的对象,注意一下封装了两个方法,无className的会自动根据t找名字,另外养成习惯我们插入session中的数据,全部大写。这样方便使用t直接找到。如果t的类名和存入session的key值不一致的时候,使用第二个方法。
细心的可能发现,在使用gson处理数据的时候,因为mongodb本身日期类型是和javascript的日期类型保持一致的,所以当我们直接存入java的date类型的时候,数据库中对直接转换为long类型的时间戳。那么在gson进行转换的时候,发现Longl类型的时间戳转换为date的时候,就会报错。
再gson转换之前,我们先解决一下Long转date的问题
新建DateDeserializer重写deserialize方法,代码如下
package com.easternie.newframe.util;
import java.lang.reflect.Type;
import java.util.Date;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
/** gson转换的时候对于Long时间戳类型进行特殊处理
* @author ZhangQiang
* @date 2018年10月30日15:02:46
*/
public class DateDeserializer implements JsonDeserializer<Date> {
@Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new java.util.Date(json.getAsJsonPrimitive().getAsLong());
}
}
这样在sessionutils中进行转换的时候使用该方法进行处理,就不会异常了
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer()).setDateFormat(DateFormat.LONG).create();
该方法同样适用于对于前台js传过来的某些个别的时间戳类型的日期数据。
通过以上设置,我们程序就是支持分布式部署的了,对于分布式部署的方式,可以参考我的其他文章,Nginx+tomcat实现分布式架构及,或者随便搜一下随手一大堆。 在程序通过以上改造后,我们配置分布式系统,无需配置iphash,直接进行轮训访问即可,能够更合理的利用负载,均衡访问资源。