zoukankan      html  css  js  c++  java
  • 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,'3658561548@qq.com','test001','test001');
    insert into `useraccount` values(2,'钱(dev)',27,136,'3658561548@126.com','test002','test002');
    insert into `useraccount` values(3,'孙(dev)',31,159,'3658561548@163.com','test003','test003');
    insert into `useraccount` values(4,'李(dev)',35,130,'3658561548@sina.com','test004','test004');
    select * from `useraccount`;

    1.3 mapper

    SpringBoot进阶教程(二十六)整合Redis之共享Session
    <?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>
    View Code
    SpringBoot进阶教程(二十六)整合Redis之共享Session
    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);
    }
    View Code

    1.4 实体类

    SpringBoot进阶教程(二十六)整合Redis之共享Session
    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();
        }
    }
    View Code

    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 "退出登录";
        }
    }

    v效果演示

    2.1 直接访问页面

    SpringBoot进阶教程(二十六)整合Redis之共享Session

    提示:请先登录

    2.2 调用登录接口

    SpringBoot进阶教程(二十六)整合Redis之共享Session

    SpringBoot进阶教程(二十六)整合Redis之共享Session

    登录以后再次访问页面,提示访问成功。

    SpringBoot进阶教程(二十六)整合Redis之共享Session

    SpringBoot进阶教程(二十六)整合Redis之共享Session

    2.3 退出登录

    SpringBoot进阶教程(二十六)整合Redis之共享Session

    v源码地址

    https://github.com/toutouge/javademosecond/tree/master/hellospringboot


    作  者:请叫我头头哥
    出  处:http://www.cnblogs.com/toutou/
    关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!
    版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

  • 相关阅读:
    19 C#循环语句的跳过和中断 continue和break
    18 C#中的循环执行 for循环
    一种绝对提高开发水平的方法(推荐英语)
    大数据知识普及
    全链路压测压测报告
    QuickSearch快排
    二分查找
    算法
    基于领域驱动设计的业务中台架构设计
    【科普】Scrum——从橄榄球争球到敏捷开发
  • 原文地址:https://www.cnblogs.com/toutou/p/redis_session.html
Copyright © 2011-2022 走看看