暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring Session with JDBC

Coding On Road 2019-07-13
1011

可以使用的Session存储机制为:

   Redis(建议)

   JDBC(传统数据库)

   MongoDB

       Hazelcast

 

在传统单机web应用中,一般使用tomcat/jettyweb容器时,用户的session都是由容器管理。浏览器使用cookie中记录sessionId,容器根据sessionId判断用户是否存在会话session。这里的限制是,session存储在web容器中,被单台服务器容器管理。

 

但是网站主键演变,分布式应用和集群是趋势(提高性能)。此时用户的请求可能被负载分发至不同的服务器,此时传统的web容器管理用户会话session的方式即行不通。除非集群或者分布式web应用能够共享session,尽管tomcat等支持这样做。但是这样存在以下两点问题:

 

Ø 需要侵入web容器,提高问题的复杂

Ø web容器之间共享session,集群机器之间势必要交互耦合


示例:

1:创建Spring boot项目添加以下依赖

注意: Spring Session JDBC依赖负责将Session信息持久化到数据库中。

 

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.1.6.RELEASE</version>

<relativePath /> <!-- lookup parent from repository -->

</parent>

<groupId>cn.isoft</groupId>

<artifactId>isoft-web</artifactId>

<version>1.0</version>

<name>isoft-web</name>

<description>Demo project for Spring Boot</description>

<properties>

<java.version>1.8</java.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.session</groupId>

<artifactId>spring-session-jdbc</artifactId>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

<executions>

<execution>

<configuration>

<mainClass>cn.isoft.IsoftWebApplication</mainClass>

</configuration>

<goals>

<goal>repackage</goal>

</goals>

</execution>

</executions>

</plugin>

</plugins>

</build>

</project>

 

2、创建数据表

默认情况下,在包:classpath:org/springframework/session/jdbc/ 里面包含了所有不同的数据库创建保存Sessionin信息的表结构。

 

CREATE TABLE SPRING_SESSION (

PRIMARY_ID CHAR(36) NOT NULL,

SESSION_ID CHAR(36) NOT NULL,

CREATION_TIME BIGINT NOT NULL,

LAST_ACCESS_TIME BIGINT NOT NULL,

MAX_INACTIVE_INTERVAL INT NOT NULL,

EXPIRY_TIME BIGINT NOT NULL,

PRINCIPAL_NAME VARCHAR(100),

CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)

) ENGINE=INNODB ROW_FORMAT=DYNAMIC;

 

CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);

CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);

CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);

 

CREATE TABLE SPRING_SESSION_ATTRIBUTES (

SESSION_PRIMARY_ID CHAR(36) NOT NULL,

ATTRIBUTE_NAME VARCHAR(200) NOT NULL,

ATTRIBUTE_BYTES BLOB NOT NULL,

CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),

CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE

) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

 

3、配置数据连接

application.properties文件中配置数据连接及JDBC Session信息如下:

server.port=9999

spring.profiles.active=dev

spring.datasource.url=jdbc:mysql://localhost:3306/study?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

spring.datasource.username=root

spring.datasource.password=123456

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.platform=mysql

 

spring.thymeleaf.cache=false

spring.thymeleaf.encoding=UTF-8

spring.thymeleaf.prefix=classpath:/templates/

spring.thymeleaf.suffix=.html

 

spring.http.encoding.charset=UTF-8

spring.messages.encoding=UTF-8

spring.mvc.date-format=yyyy-MM-dd HH:mm:ss

#会话存储类型

spring.session.store-type=JDBC

spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-mysql.sql

# Cron expression for expired session cleanup job.

spring.session.jdbc.cleanup-cron=0 * * * * *

# Name of the database table used to store sessions.

spring.session.jdbc.table-name=SPRING_SESSION

 

logging.level.root=info

logging.file=logs/web.log

 

4、开发启动类及Spring Boot MVC配置类

启动类:

package cn.isoft;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@SpringBootApplication

@EnableWebMvc

public class IsoftWebApplication {

public static void main(String[] args) {

SpringApplication.run(IsoftWebApplication.class, args);

}

}

 

WebMvc配置类:

package cn.isoft.config;

 

import org.springframework.context.annotation.Configuration;

import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration

@EnableWebMvc

@EnableJdbcHttpSession

public class WebConfig implements WebMvcConfigurer {

/**

 * 设置一些默认的请求的地址转发

 */

@Override

public void addViewControllers(ViewControllerRegistry registry) {

System.err.println("ViewControllers....");

registry.addViewController("/").setViewName("index");

registry.addViewController("").setViewName("index");

}

/**

 * 设置哪些可以跨域请求

 */

@Override

public void addCorsMappings(CorsRegistry registry) {

registry.addMapping("/**").allowedOrigins("http://localhost:8888").allowedHeaders("*").allowCredentials(true);

}

/**

 * 配置静态资源目录

 */

@Override

public void addResourceHandlers(ResourceHandlerRegistry registry) {

registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");

}

}

 

开发一个测试用的控制器:

package cn.isoft.config;

 

import org.springframework.context.annotation.Configuration;

import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration

@EnableWebMvc

@EnableJdbcHttpSession

public class WebConfig implements WebMvcConfigurer {

/**

 * 设置一些默认的请求的地址转发

 */

@Override

public void addViewControllers(ViewControllerRegistry registry) {

System.err.println("ViewControllers....");

registry.addViewController("/").setViewName("index");

registry.addViewController("").setViewName("index");

}

/**

 * 设置哪些可以跨域请求

 */

@Override

public void addCorsMappings(CorsRegistry registry) {

registry.addMapping("/**").allowedOrigins("http://localhost:8888").allowedHeaders("*").allowCredentials(true);

}

/**

 * 配置静态资源目录

 */

@Override

public void addResourceHandlers(ResourceHandlerRegistry registry) {

registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");

}

}

 

 

开发一个HTML页面,请求并获取SessionID

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

<script type="text/javascript" th:src="@{/static/jquery.min.js}"></script>

</head>

<body>

<p>主页</p>

<hr>

<button type="button" id="btn1">测试Ajax</button>

</body>

<script type="text/javascript">

$(function() {

$("#btn1").click(function() {

$.get("demo/one/hello", function(txt) {

$("#btn1").after(txt + "<br>");

}, "text");

});

});

</script>

</html>

 

5、打包spring boot

将项目打包成两个项目,一个使用端口号8888,另一个使得端口号9999。打完的jar包可以重命名如下:

isoft-web-1.0_8888.jar

isoft-web-1.0_9999.jar

现在使用java -jar 启动这两个项目:

Java -jar isoft-web-1.0_8888.jar

 


Java -jar isoft-web-1.0_9999.jar

 


 

6、配置nginx

http{  }节点下配置 upstream如下:

 

upstream nginxdemo{

server 127.0.0.1:8888;

server 127.0.0.1:9999;

}

server {

   listen 8080;

   

   location {

proxy_pass http://nginxdemo;

   }

}

 

7、启动nginx(测试成功)

现在就可以启动nginx并多次访问,可以看到是同一个Session ID

 


 

查看后台的输出以下信息:

   8888服务器输出的信息:

 


9999服务器输出的信息:

  


  由于没有配置比重,所以,分别调用了4次。

 

且共享了Session信息。

 

 


文章转载自Coding On Road,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论