SpringBoot与Shiro的整合(单体式项目)

1.包结构

2.jar包,配置文件,类

2.1pom.xml文件配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zy</groupId>
    <artifactId>spring-boot01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>spring-boot01</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.14.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <shiro.version>1.2.3</shiro.version>
        <commons-logging.version>1.2</commons-logging.version>
        <mysql.version>5.1.45</mysql.version>
        <druid.version>1.0.21</druid.version>
        <mybatis-spring-boot.version>1.3.1</mybatis-spring-boot.version>
        <pageHelper.version>5.1.2</pageHelper.version>
        <mybatis-paginator.version>1.2.15</mybatis-paginator.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--会与本地tomcat冲突
                <scope>provided</scope>
            -->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--配置mysql,Mybatis,Druid-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring-boot.version}</version>
        </dependency>
        <!--配置分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>${pageHelper.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.miemiedev</groupId>
            <artifactId>mybatis-paginator</artifactId>
            <version>${mybatis-paginator.version}</version>
        </dependency>
        <!--用于解析Html,不能与jsp的支持包同时存在-->
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>-->
        <!--添加jsp相关-->
        <!--用于解析jsp,不能与HTML的支持包同时存在-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <!--配置shiro的依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>${commons-logging.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--<plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <path>/</path>
                    <port>8081</port>
                </configuration>
            </plugin>-->
        </plugins>
    </build>

</project>

2.2spring及springmvc配置(在application.yml中)

spring:
# 配置数据库连接
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shiro
    username: root
    password: 123456
# 配置jsp的解析
  mvc:
    view:
      prefix: /WEB-INF/
      suffix: .jsp
logging:
  pattern:
    level: debug
  level:
    com.zy.controller: error
    com.zy.service: info
    com.zy.mapper: debug
  file: D:/springboot.log
# mybatis中,静态资源不发布:此处指的是resources文件夹下的文件
mybatis:
  mapper-locations: classpath:com/zy/mapper/*.xml
  config-location: classpath:sqlMappingConfig.xml
# 使用pageHelper进行分页
pagehelper:
    helperDialect: mysql
    reasonable: true
    support-methods-arguments: true
    params: count=countSql
# Shiro
shiro:
    configLocation: classpath:/ehcache.xml

2.3配置mybatis

2.3.1配置sqlMappingConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--设置全局配置环境-->
    <settings>
        <!--开启全局缓存-->
        <setting name="cacheEnabled" value="true"/>
        <!--开启懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--关闭延迟加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!--配置分页插件pageHelper的拦截器:5.0版本之后的配置-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
</configuration>

2.3.2配置其他***Mappper.xml文件(以TbUserMapper.xml为例)

<?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.zy.mapper.TbUserMapper">

    <!--封装结果集-->
    <resultMap id="tbUserResultMap" type="com.zy.model.TbUser">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="username" property="username" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
        <result column="salt" property="salt" jdbcType="VARCHAR"/>
        <result column="status" property="status" jdbcType="VARCHAR"/>
    </resultMap>

    <!--
    根据用户名查询用户信息
    TbUser getTbUserByUserName(String username);
    -->
    <select id="getTbUserByUserName" resultMap="tbUserResultMap">
        select id,username,password,salt,status
        from tb_user
        where username = #{username}
    </select>

    <!--
     // 注册用户
    int addTbUser(TbUser tbUser);
    -->
    <insert id="addTbUser">
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select last_insert_id()
        </selectKey>
        insert into tb_user values(null,#{username},#{password},#{salt},#{status})
    </insert>

    <!--
    // 查询所有用户信息
    List<TbUser> getAllUser();
    -->
    <select id="getAllUser" resultMap="tbUserResultMap">
        select id,username,password,salt,status
        from tb_user
    </select>

    <!--
    // 删除用户信息及其关联角色信息,还需要去关联表中删除该信息
    void deleteUser(Integer id);
    -->
    <delete id="deleteUser">
        delete from tb_user where id = #{id}
    </delete>
    <delete id="deleteUserRole">
        delete from tb_user_role where user_id = #{id}
    </delete>

</mapper>

2.4配置ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />
</ehcache>

2.5配置config包下文件

2.5.1配置Shiro主配置类(类似于ssm中的applicationContext-shiro.xml)

package com.zy.config;

import com.zy.shiro.TbUserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/login/login");
        // 设置无权限时跳转的 url;
        shiroFilterFactoryBean.setUnauthorizedUrl("/login/login");

        // 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //游客,开发权限
        //filterChainDefinitionMap.put("/guest/**", "anon");
        //用户,需要角色权限 “user”
        //filterChainDefinitionMap.put("/user/**", "roles[user]");
        //管理员,需要角色权限 “admin”
        //filterChainDefinitionMap.put("/admin/**", "roles[admin]");
        //开放登陆接口
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/layui/**", "anon");
        filterChainDefinitionMap.put("/login/logout", "logout");
        filterChainDefinitionMap.put("/login/**", "anon");
        //其余接口一律拦截
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
        filterChainDefinitionMap.put("/**", "user");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * shiro缓存管理器;
     * 需要注入对应的其它的实体类中:
     * 1、安全管理器:securityManager
     * 可见securityManager是整个shiro的核心;
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager(){
        System.out.println("ShiroConfiguration.getEhCacheManager()");
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return cacheManager;
    }

    /**
     * 注入 securityManager
     */
    @Bean(name = "securityManager")
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(customRealm());
        //注入缓存管理器;
        securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;
        // 记住我管理器
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    /**
     * 自定义身份认证 realm;
     * <p>
     * 必须写这个类,并加上 @Bean 注解,目的是注入 CustomRealm,
     * 否则会影响 CustomRealm类 中其他类的依赖注入
     */
    // 配置自定义的权限登录器
    @Bean
    public TbUserRealm customRealm() {
        TbUserRealm tbUserRealm = new TbUserRealm();
        //告诉realm,使用credentialsMatcher加密算法类来验证密文
        tbUserRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        tbUserRealm.setCachingEnabled(true);
        return tbUserRealm;
    }
    /**
     * 凭证匹配器
     * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * )
     * 可以扩展凭证匹配器,实现 输入密码错误次数后锁定等功能,下一次
     * @return
     */
    @Bean(name="credentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1);//散列的次数,比如散列两次,相当于 md5(md5(""));
        //storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
        //hashedCredentialsMatcher.setStoredCredentialsHexEncoded(false);

        return hashedCredentialsMatcher;
    }

    /**
     * cookie对象;
     * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
        //System.out.println("ShiroConfiguration.rememberMeCookie()");
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间 ,单位秒;-->
        simpleCookie.setMaxAge(604800);
        return simpleCookie;
    }

    /**
     * cookie管理对象;
     * rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        //System.out.println("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        return cookieRememberMeManager;
    }

    /*开启切面支持,spring拦截支持
    * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类
    * */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

    //把shiro生命周期交给spring boot管理
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }

    /**
     *
     * 添加ShiroDialect 为了在thymeleaf里使用shiro的标签的bean
     * @return
     * 此处不用
        @Bean(name = "shiroDialect")
        public ShiroDialect shiroDialect(){
            return new ShiroDialect();
        }
     */
}

2.5.2配置静态资源类

package com.zy.config;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class StaticResourceConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /*配置js,css等*/
        registry.addResourceHandler("/js/**").addResourceLocations("WEB-INF/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("WEB-INF/css/");
        registry.addResourceHandler("/fonts/**").addResourceLocations("WEB-INF/fonts/");
        registry.addResourceHandler("/images/**").addResourceLocations("WEB-INF/images/");
        registry.addResourceHandler("/layui/**").addResourceLocations("WEB-INF/layui/");
        //registry.addResourceHandler("/error/**").addResourceLocations("WEB-INF/error/");
        super.addResourceHandlers(registry);
    }

    //统一页码处理配置
    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                //ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html");
                ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/WEB-INF/error/404.jsp");
                ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/WEB-INF/error/500.jsp");

                container.addErrorPages( error404Page, error500Page);
            }
        };
    }

}

2.6配置springboot的启动类

package com.zy;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
/*配置事务的注解,同时也需要在service层方法上添加注解*/
@EnableTransactionManagement
/*整合mybatis*/
@MapperScan("com.zy.mapper")
public class SpringBoot01Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot01Application.class, args);
    }
}

2.8其他mapper层,service层,controller层配置详见https://www.cnblogs.com/psy-code/p/9457947.html

原文地址:https://www.cnblogs.com/psy-code/p/9458014.html

时间: 2024-10-06 08:13:48

SpringBoot与Shiro的整合(单体式项目)的相关文章

SSM项目与Shiro项目的整合(单体式项目)

1.项目的包结构: 2.jar包,配置文件及工具类 2.1pom.xml的配置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=&qu

springboot+springcache+shiro+Redis整合时@Cacheable、@Transactional等注解失效的问题

问题描述: 1.springboot整合shiro之前@Cacheable.@Transactional等注解都可以正常使用: 2.整合了shiro之后,自定义MyShiroRealm中注入RoleUserService时 RolerUservice中的@Cacheable.@Transaction都失效了. MyShiroRealm代码: RoleUserService代码: 原因:shiro和cache在引用service实例顺序问题,shiro引入应在cache后, shiro配置文件中引

SpringBoot与Shiro整合

修改pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <

项目一:第十三天 1、菜单数据管理 2、权限数据管理 3、角色数据管理 4、用户数据管理 5、在realm中动态查询用户权限,角色 6、Shiro中整合ehcache缓存权限数据

1 课程计划 菜单数据管理 权限数据管理 角色数据管理 用户数据管理 在realm中动态查询用户权限,角色 Shiro中整合ehcache缓存权限数据         2 菜单数据添加 2.1 使用combotree父菜单项数据     1. 页面:menu_add.jsp 2. 修改组件样式:easyui-combotree,修改url  树型表格treeGrid跟下来数combotree要求数据格式基本一致. Combotree通过text属性展示文本.   3. 使用treegrid组件的

Springboot集成Shiro和Cas实现单点登录(服务端篇CAS5)

什么是单点登录? 先说一个需求场景,比如:一个企业的内部有N多个子系统,每个子系统都有一套自己的用户名和密码,那么企业的员工要登录N个子系统,这样一个员工 就要记住N个用户名和密码,就算各个子系统的用户名和密码都是统一的,登录每个子系统都要输入用户名和密码进行登录也是一个繁琐的操作过程,那么单点登录功能由此便应运而生了.单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应

cas4.2.7与shiro进行整合

准备工作 cas单点登录开始前准备,请参考cas4.2.7实现单点登录. 与shiro进行整合 注:准备工作的基础上,对cas客户端进行如下改进. 引入相关jar包 shiro-cas-1.2.6.jar shiro-core-1.2.6.jar shiro-spring-1.2.6.jar shiro-web-1.2.6.jar web.xml引入shiro过滤器 <?xml version="1.0" encoding="UTF-8"?> <w

Springboot 2.0.4 整合Mybatis出现异常Property &#39;sqlSessionFactory&#39; or &#39;sqlSessionTemplate&#39; are required

在使用Springboot 2.0.4 整合Mybatis的时候出现异常Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required,然后各种找日志百度,网上给了一种解决方法: 版本太高,使用手动注入sqlSessionFactory,然后用dao的实习类继承,因为我的项目没有dao 的实现类,直接是interface+mapper文件,所以直接忽略了,没有试过,想试一下可以试一下 阅读博客点这里(随手百度的):这里是传送门

SpringBoot和Mybatis的整合

这里介绍两种整合SpringBoot和Mybatis的模式,分别是"全注解版" 和 "注解xml合并版". 前期准备开发环境 开发工具:IDEAJDK:1.8技术:SpringBoot.Maven.Mybatis创建项目 项目结构 Maven依赖 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org

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

集群现在越来越常见,当我们项目搭建了集群,就会产生session共享问题.因为session是保存在服务器上面的.那么解决这一问题,大致有三个方案,1.通过nginx的负载均衡其中一种ip绑定来实现(通过ip绑定服务器其中一台,就没有集群概念了):2.通过cookie备份session实现(因为cookie数据保存在客户端,不推荐;3.通过redis备份session实现(推荐); 学习本章节之前,建议依次阅读以下文章,更好的串联全文内容,如已掌握以下列出知识点,请跳过: SpringBoot(