SpringBoot(二十六)整合Redis之共享Session

集群现在越来越常见,当我们项目搭建了集群,就会产生session共享问题。因为session是保存在服务器上面的。那么解决这一问题,大致有三个方案,1.通过nginx的负载均衡其中一种ip绑定来实现(通过ip绑定服务器其中一台,就没有集群概念了);2.通过cookie备份session实现(因为cookie数据保存在客户端,不推荐;3.通过redis备份session实现(推荐);

学习本章节之前,建议依次阅读以下文章,更好的串联全文内容,如已掌握以下列出知识点,请跳过:

vSpring Session概念

Spring Session 提供了一套创建和管理 Servlet HttpSession 的方案。Spring Session 提供了集群 Session(Clustered Sessions)功能,默认采用外置的 Redis 来存储 Session 数据(不用手动存储到redis中),以此来解决 Session 共享的问题。

Spring Session 为企业级 Java 应用的 session 管理带来了革新,使得以下的功能更加容易实现:

API 和用于管理用户会话的实现。

支持每个浏览器上使用多个 session,从而能够很容易地构建更加丰富的终端用户体验。

当用户使用 WebSocket 发送请求的时候,能够保持 HttpSession 处于活跃状态。

控制 session id 如何在客户端和服务器之间进行交换,这样的话就能很容易地编写 Restful API,因为它可以从 HTTP头信息中获取 session id,而不必再依赖于 cookie。

将 session 所保存的状态卸载到特定的外部 session 存储中,如 Redis 或 Apache Geode 中,它们能够以独立于应用服务器的方式提供高质量的集群。

HttpSession - 允许以应用程序容器(即 Tomcat)中性的方式替换 HttpSession。

关于更多Spring Session概念的介绍,可以看看官网Spring Session

vSpring Session整合

1.1 引入pmo.xml

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

1.2 创建useraccount表

CREATE TABLE `useraccount` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `username` varchar(255) NOT NULL,
    `age` int(10) NOT NULL,
    `phone` bigint NOT NULL,
    `email` varchar(255) NOT NULL,
    `account` varchar(100) NOT NULL UNIQUE,
    `pwd` varchar(255) NOT NULL,
    PRIMARY KEY (`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
insert into `useraccount` values(1,‘赵(dev)‘,23,158,‘[email protected]‘,‘test001‘,‘test001‘);
insert into `useraccount` values(2,‘钱(dev)‘,27,136,‘[email protected]‘,‘test002‘,‘test002‘);
insert into `useraccount` values(3,‘孙(dev)‘,31,159,‘[email protected]‘,‘test003‘,‘test003‘);
insert into `useraccount` values(4,‘李(dev)‘,35,130,‘[email protected]‘,‘test004‘,‘test004‘);
select * from `useraccount`;

1.3 mapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.dao.UserAccountMapper">
  <resultMap id="BaseResultMap" type="com.demo.pojo.UserAccount">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="age" jdbcType="INTEGER" property="age" />
    <result column="phone" jdbcType="BIGINT" property="phone" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="account" jdbcType="VARCHAR" property="account" />
    <result column="pwd" jdbcType="VARCHAR" property="pwd" />
  </resultMap>
  <sql id="Base_Column_List">
    id, username, age, phone, email, account, pwd
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from useraccount
    where id = #{id,jdbcType=INTEGER}
  </select>
  <select id="getUserByAccount" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from useraccount
    where account = #{account}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from useraccount
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.demo.pojo.UserAccount">
    insert into useraccount (id, username, age,
      phone, email, account,
      pwd)
    values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER},
      #{phone,jdbcType=BIGINT}, #{email,jdbcType=VARCHAR}, #{account,jdbcType=VARCHAR},
      #{pwd,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.demo.pojo.UserAccount">
    insert into useraccount
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="username != null">
        username,
      </if>
      <if test="age != null">
        age,
      </if>
      <if test="phone != null">
        phone,
      </if>
      <if test="email != null">
        email,
      </if>
      <if test="account != null">
        account,
      </if>
      <if test="pwd != null">
        pwd,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="username != null">
        #{username,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        #{age,jdbcType=INTEGER},
      </if>
      <if test="phone != null">
        #{phone,jdbcType=BIGINT},
      </if>
      <if test="email != null">
        #{email,jdbcType=VARCHAR},
      </if>
      <if test="account != null">
        #{account,jdbcType=VARCHAR},
      </if>
      <if test="pwd != null">
        #{pwd,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.demo.pojo.UserAccount">
    update useraccount
    <set>
      <if test="username != null">
        username = #{username,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="phone != null">
        phone = #{phone,jdbcType=BIGINT},
      </if>
      <if test="email != null">
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="account != null">
        account = #{account,jdbcType=VARCHAR},
      </if>
      <if test="pwd != null">
        pwd = #{pwd,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.demo.pojo.UserAccount">
    update useraccount
    set username = #{username,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      phone = #{phone,jdbcType=BIGINT},
      email = #{email,jdbcType=VARCHAR},
      account = #{account,jdbcType=VARCHAR},
      pwd = #{pwd,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

package com.demo.dao;

import com.demo.pojo.UserAccount;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface UserAccountMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(UserAccount record);

    int insertSelective(UserAccount record);

    UserAccount selectByPrimaryKey(Integer id);

    UserAccount getUserByAccount(@Param("account") String account);

    int updateByPrimaryKeySelective(UserAccount record);

    int updateByPrimaryKey(UserAccount record);
}

1.4 实体类

package com.demo.pojo;

import java.io.Serializable;

public class UserAccount  implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer id;

    private String username;

    private Integer age;

    private Long phone;

    private String email;

    private String account;

    private String pwd;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username == null ? null : username.trim();
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Long getPhone() {
        return phone;
    }

    public void setPhone(Long phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email == null ? null : email.trim();
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account == null ? null : account.trim();
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd == null ? null : pwd.trim();
    }
}

1.5 service层

Service

UserAccount getUserByAccount(String account);

ServiceImpl

    @Override
    public UserAccount getUserByAccount(String account){
        return userAccountMapper.getUserByAccount(account);
    }

1.6 添加session配置类

package com.demo.common;

import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

/**
 * Created by toutou on 2019/1/22.
 */
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
/**
 * maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Redis Session 之后,原 Boot 的 server.session.timeout 属性不再生效。
 */
public class SessionRedisConfig {
}

1.7 设置拦截器

关于拦截器不懂的话,可以看我之前的一篇文章《SpringBoot(十一)过滤器和拦截器》

    /*
     * 进入controller层之前拦截请求
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
        System.out.println("MyTestInterceptor  1111111111");
        Object user= request.getSession().getAttribute("useraccount");
        if (user==null){
            // response.sendRedirect(request.getContextPath()+"/error");
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write("请先登录");
            return false;
        }

        return true;
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 自定义拦截器,添加拦截路径和排除拦截路径
        registry.addInterceptor(myTestInterceptor).addPathPatterns("/**").excludePathPatterns("/userlogin");
    }

设置全局拦截

1.8 登录/注销

package com.demo.controller;

import com.demo.pojo.UserAccount;
import com.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * Created by toutou on 2019/1/22.
 */
@RestController
public class LoginController {
    @Autowired
    UserService userService;

    @RequestMapping(value = "/userlogin")
    public String Login(HttpServletRequest request, String account, String pwd)
    {
        UserAccount user= userService.getUserByAccount(account);
        if (user!=null && user.getPwd().equals(pwd)){
            request.getSession().setAttribute("useraccount",user);
            return "登录成功";
        }

        return "登录失败";
    }

    @RequestMapping(value = "/userlogout")
    public String logout (HttpServletRequest request){
        HttpSession session=request.getSession();
        session.removeAttribute("useraccount");
        return "退出登录";
    }
}

原文地址:https://www.cnblogs.com/toutou/p/redis_session.html

时间: 2024-11-05 14:41:00

SpringBoot(二十六)整合Redis之共享Session的相关文章

SpringBoot(二十四)整合Redis

缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力.Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多. 之前有两篇博文(centos安装Redis 和 Redis五大数据类型的常用操作),分别介绍了Redis的安装和Redis的常用操作.今天主要介绍介绍springboot整合Redis. v应用场景 现在公司做的项目都偏重论坛/社区/社交类产品,所以对Redis的实用场景主要集中在排行榜,最

二十六:Struts2 和 spring整合

二十六:Struts2 和 spring整合 将项目名称为day29_02_struts2Spring下的scr目录下的Struts.xml文件拷贝到新项目的scr目录下 在新项目的WebRoot---->WEB-INF目录下新建一个目录lib,用于存放jar包(Struts2和spring整合所需jar包) 将项目名称为day29_02_struts2Spring,WebRoot---->WEB-INF下的lib目录下的所有jar包拷贝到新项目对应的位置,同时将spring的配置文件appl

Powershell管理系列(二十六)PowerShell操作之批量导出&导入邮箱

-----提供AD\Exchange\Lync\Sharepoint\CRM\SC\O365等微软产品实施及外包,QQ:185426445.电话18666943750 项目中有时候做跨林邮箱迁移的时候,条件不成熟,比如安全考虑或者其他考虑,不能做双林信任,这样就提出了一个问题,历史邮件需要使用的话怎么办,一个简单高效的解决办法就是从源森林批量导出邮件为.pst文件,在批量导入到目的域森林,具体操作如下: 1.赋予管理账号邮件导入导出权限,命令如下: cls whoami New-Manageme

攻城狮在路上(叁)Linux(二十六)--- linux文件系统的特殊查看与操作

一.boot sector 与 super block的关系: 1.boot sector用于存放引导装载程序,占用1024个字节. 2.super block的大小也为1024字节. 3.若block大小为1k,则boot sector和super block各占一个block. 4.若block大于1K(2K/4K)时,则两者都位于第一个block中. 二.磁盘空间的浪费问题:暂不考虑. 三.利用GUN的parted命令进行分区行为: 因为fdisk不支持高于2TB的分区. 命令格式: pa

第一百二十六节,JavaScript,XPath操作xml节点

第一百二十六节,JavaScript,XPath操作xml节点 学习要点: 1.IE中的XPath 2.W3C中的XPath 3.XPath跨浏览器兼容 XPath是一种节点查找手段,对比之前使用标准DOM去查找XML中的节点方式,大大降低了查找难度,方便开发者使用.但是,DOM3级以前的标准并没有就XPath做出规范:直到DOM3在首次推荐到标准规范行列.大部分浏览器实现了这个标准,IE则以自己的方式实现了XPath. 一.IE中的XPath 在IE8及之前的浏览器,XPath是采用内置基于A

企业搜索引擎开发之连接器connector(二十六)

连接器通过监视器对象DocumentSnapshotRepositoryMonitor从上文提到的仓库对象SnapshotRepository(数据库仓库为DBSnapshotRepository)中迭代获取数据 监视器类DocumentSnapshotRepositoryMonitor在其构造方法初始化相关成员变量,这些成员属性都是与数据获取及数据处理逻辑相关的对象 /** This connector instance's current traversal schedule. */ pri

【Unity 3D】学习笔记二十六:unity游戏脚本(六)

在3D游戏世界中,任何一个游戏对象在创建的时候都会附带Transform(变换)组件,并且该组件是无法删除的,也不应该删除.在unity中,Transform面板一共有3个属性: Position  (位置) Rotation(旋转) Scale(缩放) 这三个值都是用来调整游戏对象在游戏界面中的位置,状态等相关参数. Position  (位置) 任何一个游戏对象的三维坐标都保存在Vector3容器中,该容器记录对象在X轴,Y轴,Z轴的坐标.一旦Vector33容器中的坐标发生变化,那么Sce

每日算法之二十六:Substring with Concatenation of All Words

变相的字符串匹配 给定一个字符串,然后再给定一组相同长度的单词列表,要求在字符串中查找满足以下条件的起始位置: 1)从这个位置开始包含单词列表中所有的单词,且每个单词仅且必须出现一次. 2)在出现的过程中不能出现其他的干扰单词. 3)出现的位置可能有多个. 4)单词的出现顺序不做要求. 下面是一个例子: S:"barfoothefoobarman" L:"foo","bar" 位置0是出现位置,:两个单词均出现仅出现一次,且没有干扰.同样位置9也

【管理心得之二十六】职场中的“武功”

场景再现==================={放学路上}同学A:最近<天龙八部>看没?我喜欢那里的虚竹,因为他武功最高.同学B:什么呀?才不是虚竹呢,是段誉武功最高.他不仅会"六脉神剑",还会"一阳指"和"北冥神功".同学A:虚竹厉害,他有天山童姥等三人最强内力,后期又习得"降龙十八掌".同学B:这些都没有"六脉神剑"厉害.同学A:..................同学B:...... ==