目录
spring与redis配置:
Jar包
spring-redis.Xml中配置
Spring-dao.xml
序列化ClassCastException问题
maxActive和maxWait没有找到
最近做公司项目,项目结构大体完成,自己在这里做个记录,怕自己忘记!
项目想做前后端分离,多个项目组合成一个项目,但是用户感觉是一个项目,用户登录之后不需要在其他项目重复登录,根据权限用各个项目的功能。根据客户需求可以多个项目任意组合卖,这就需要项目可以部署在一个或多个tomcat并且该项目需要部署在一台电脑或者多台电脑上。
先说下大体用到的技术,前端angularjs,服务端ssm+redis+mysql+nginx,大体这些。
客户端与服务端通讯方式是http,传输数据是json格式。项目遇到主要问题是会话的共享和跨域。
http协议是无状态的,为了浏览器和服务器保持联系两边建立了cookie和session机制,浏览器第一次请求到tomcat,tomcat进行响应并设置cookie(tomcat设置的是jsessionid)保持在浏览器,自己保持session,这样两边建立联系。
现在问题来了,用户使用项目,但这个项目由两个Tomcat发布,用户访问a项目,Atomcat建立一套会话,当用户访问b项目Btomcat又建立一套会话,这样系统分不清是否是一个用户登录,用户可能频繁登录体验很差,为了解决这个问题我在项目中加入redis进行解决。
加入redis想要解决的是session共享问题,想了两个实现方式:我采用第二个(有点懒)
1. 用户第一次登陆成功时自己做一个token相当于sessionid,user是用户信息,将token作为key,user作为value存到redis数据库并设置存入时间,response时将token放入cookie中;客户端再次请求时检查请求的cookie中token和本次请求的时间,请求时间和存入时间对比不符合告诉用户超时并重新登陆,符合便根据token获取redis中的value,value存在返回信息重置存入时间,不存在则从新登陆。
2. 有一种spring封装好的代替原始session的方式,用这种方式直接设置session的同时自动往redis中存储信息。
spring与redis配置:
首先安装redis,之后spring与redis进行配置。
Jar包
jedis-2.9.0.jar :redis关于java客户端的jar包;
spring-data-redis-1.7.1.RELEASE.jar :spring自己封装的redis的jar;
commons-pool2-2.5.0.jar :与redis相配合的连接池;
spring-session-1.2.0.RELEASE.jar :spring配合redis实现的session封装(突然发现spring已经有一个session封装,所以直接拿来用自己就不写cookie、session这种机制了)
spring-redis.Xml中配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd
">
<bean id="poolConfig"class="redis.clients.jedis.JedisPoolConfig">
<!--最大空闲数 -->
<property name="maxIdle"value="${redis.maxIdle}" />
<!--连接池的最大数据库连接数 -->
<property name="maxTotal"value="${redis.maxTotal}" />
<!--最大建立连接等待时间 -->
<property name="maxWaitMillis"value="${redis.maxWaitMillis}" />
</bean>
<!-- redis链接工厂,并配置ip、端口、密码等 -->
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"
p:pool-config-ref="poolConfig" />
<!--redis操作模版,使用该对象可以操作redis -->
<bean id="redisTemplate"class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory"ref="connectionFactory" />
<!-- RedisTemplate中注入序列化等属性 -->
<property name="keySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<!-- 值json序列化-->
<property name="valueSerializer">
<bean
class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
</bean>
<!-- 设置spring-session相关 -->
<bean id="defaultCookieSerializer"
class="org.springframework.session.web.http.DefaultCookieSerializer">
<!-- 设置请求时获取的项目路径 -->
<property name="cookiePath"value="/"></property>
<!-- 设置存入浏览器的sessionid名称 -->
<property name="cookieName"value="NVWEBSESSIONID" />
</bean>
<!-- 将session放入redis -->
<bean id="redisHttpSessionConfiguration"
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<!-- 设置超时时间 -->
<property name="maxInactiveIntervalInSeconds"value="1800" />
</bean>
</beans>
Spring-dao.xml
<!-- 引入外部属性文件,加密 -->
<bean class="com.nv.common.util.EncryptPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders"value="true" />
<property name="locations">
<list>
<value>classpath:dbconfig.properties</value>
<value>classpath:redis.properties</value>
</list>
</property>
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这插件利用的是filter,所以需要在web.xml中进行配置,
配置完成后,测试时遇到一点问题,问题和解决问题方法如下(提出问题并解决才不是耍流氓!):
序列化ClassCastException问题
maxActive和maxWait没有找到
jedis的版本问题,有的属性不对应
spring-session封装后在使用request.getSession().setAttribute()类似方法的时候其实已经存进 redis了。
经过以上配置就可以解决在一个域下(一个ip,主意127.0.0.1和localhost不是一个域)多个tomcat集成的session共享问题,也就是在一个电脑上配置多个tomcat,这几个tomcat发布的项目就可以获取共同的session信息了!
但是并不能解决在不同ip下的跨域问题,为什么呢?因为我们这种方式其实还是cookie和session这种方式,而浏览器存储cookie时是和一个域绑定的,什么意思?也就是百度存储的cookie不会到淘宝服务器上,所以当tomcat部署在不同电脑上发布项目,用户第一次访问127.0.0.1:8080建立联系,第二次再访问localhost:8081时不会向localhost发送127.0.0.1存储的cookie信息,这个时候就是之前所说的跨域问题。
提出问题,就要解决。
下面我们用Nginx的反向代理进行解决:
思路就是,浏览器存储的域是Nginx的,而Nginx集成tomcat,这样多个tomcat就可以分享一个域下的cookie信息了,
1.安装Nginx
2配置如下
完成以上配置,就可以完成在多个主机下多个web服务器发布多个项目合并成一个项目的简单思路。
问题:
1. 如果是ajax跨域,请自行搜索一下,ajax和spring跨域设置。
2. spring-session的问题,这个问题导致不能实现跨域共享,具体描述与解决如下:
我按照这个博主进行修改并没有成功,或者说有点复杂,spring出的插件是不是应该有spring的感觉呢?我又查了很多资料最后找到如下配置:
这样解决了获取路径不统一问题,以上是java web 项目多服务器部署的简单思路,深入的后续会写。