springboot整合springcache(数据库redis)

系列文章目录


一、说明:

spring cache官方文档

spEl语法说明==>官方文档

  1. Spring Cache是一项缓存
  2. 可以注解就达到缓存效果
  3. 小编的案例是基于springboot,整合是redis

官网springcache介绍目录:
在这里插入图片描述

官网的注解一共有5个,如图:
在这里插入图片描述
小编给他翻译下

注解说明
@Cacheable触发将数据保存到缓存的操作(启动缓存)
@CacheEvict触发将数据从缓存删除的操纵(失效模式)
@CachePut不影响方法执行更新缓存(双写模式)
@Caching:组合以上多个操作(点击注解看源码就知道了,组合注解)
@CacheConfig在类级别共享缓存的相同配置

概念图:
在这里插入图片描述


二、原理梳理

2.1、 比较重要的源码类

  1. CacheAutoConfiguration 缓存的自动配置
  2. 小编用的类型是redis所以看 RedisCacheConfiguration
  3. CacheManager 缓存管理者
  4. 小编是类型是redis所以看 RedisCacheManager
  5. CacheProperties 缓存默认配置
  6. idea搜索的方法 双击shift 或者 ctrl n

2.2、 原理说明:

流程说明:

 CacheAutoConfiguration  =>  RedisCacheConfiguration =>
 自动配置了RedisCacheManager =>  初始化所有的缓存 => 
 每个缓存决定使用什么配置=>
 =>如果RredisCacheConfiguration有就用已有的,没有就用默认配置(CacheProperties=>想改缓存的配置,只要给容器中放一个RredisCacheConfiguration即可
 =>就会应用到当前RedisCacheManager管理的所有缓存分区中

三、默认缓存的数据类型

在默认配置下,springcache给我们缓存的试用jdk序列化过的数据

我们通常是缓存Json字符串,因为使用Json能跨语言,跨平台进行交互

所以我们要修改他的默认配置,包括ttl(过期时间)、存储格式、等…


四、整合

项目结构:

在这里插入图片描述

4.1、引入依赖

<!--spring-boot-starter-data-redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--spring cache-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

4.2、先看下配置源码是怎么样的

RedisCacheConfiguration
在这里插入图片描述

4.3、创建配置类(照猫画虎)

注意事项:要让原本配置文件的一些配置生效

开启属性绑定配置的功能
@EnableConfigurationProperties(CacheProperties.class)

MyCacheConfig

package sqy.config.cache;

import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/**
 * @author suqinyi
 * @Date 2022/1/13 -更新
 */
@EnableConfigurationProperties(CacheProperties.class)//开启属性绑定配置的功能
@Configuration //配置类
@EnableCaching //开启缓存功能
public class MyCacheConfig {

//    第一种、从容器里面拿
//    @Autowired
//    CacheProperties cacheProperties;

    /**
     * 配置文件中的很多东西没用上
     *      1、原来和配置文件绑定的配置类是这个样子的
     *          @ConfigurationProperties(
     *              prefix = "spring.cache"
     *          )
     *          public class CacheProperties
     *
     *      2、要让他生效
     *          @EnableConfigurationProperties(CacheProperties.class)//开启属性绑定配置的功能
     *
     */

    //第二种、因为注入了容器,参数属性spring会自己去容器里面找 (CacheProperties cacheProperties)
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//        config=config.entryTtl();
        config= config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        /**
         * GenericFastJsonRedisSerializer   fastjson家族的
         * GenericJackson2JsonRedisSerializer   spring自带的 package org.springframework.data.redis.serializer;
         */
        //指定序列化-Jackson
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        //指定序列化-fastjson
        //config= config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));


        //从所以配置中取出redis的配置
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        //将配置文件中所有的配置都生效(之间从源码里面拷 RedisCacheConfiguration)
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;

    }
}


4.4、配置文件(application.properties)

#类型指定redis
spring.cache.type=redis

#一个小时,以毫秒为单位
spring.cache.redis.time-to-live=3600000
#给缓存的建都起一个前缀。  如果指定了前缀就用我们指定的,如果没有就默认使用缓存的名字作为前缀,一般不指定
#spring.cache.redis.key-prefix=CACHE_
#指定是否使用前缀
spring.cache.redis.use-key-prefix=true
#是否缓存空值,防止缓存穿透
spring.cache.redis.cache-null-values=true

4.5、使用

在方法上标注注解就可以

4.5.1、@Cacheable(开启缓存功能)

将查询到的结果存入缓存

注意事项

  1. 有对应的缓存就不进入方法 [需要返回值,没有返回值缓存空值]
  2. @Cacheable并没有单独的失效时间的方法。
  3. 但是可以在CacheManager配置,在+上自动刷新的功能,但是这样的的操作比较繁琐。如果不设置,只有统一的过期时间很容易导致缓存雪崩的问题

01、有返回缓存

	/**
     * TODO @Cacheable并没有单独的失效时间的方法。
     *      但是可以在CacheManager配置,在+上自动刷新的功能,但是这样的的操作比较繁琐。
     *      如果不设置,只有统一的过期时间很容易导致缓存雪崩的问题。
     *
     * @Cacheable开启缓存功能 有对应的缓存就不进入方法 [需要返回值,没有返回值缓存空值]
     * value = "student", 【key ="#root.methodName" 或 key = "'名称'" 或 key = "#传入的参数" 或  key = "#接收参数的实体.属性"
     * 更多方式看spEl语法 】
     * <p>
     * student是分区名字
     * #root.methodName是spEl语法 也就是方法名 testCache
     * <p>
     * 在redis里面 他的存储就是 student::testCache
     * 同一个业务类型是数据放在同一个分区,树形结构,
     * 类如:a包里面有b,c。  b和c就是具体缓存。a就是名称空间
     * @Cacheable(value = {"student"},key ="#root.method.name" ,sync = true)
     * sync = true	这个属性的意思是加锁,解决缓存击穿问题
     */
    //localhost:8080/testCache
    @Cacheable(value = "student", key = "#root.method.name")
    @GetMapping("/saveCache01")
    public HashMap<String, List<Student>> saveCache01() {
        System.out.println("方法saveCache01执行");
        HashMap<String, List<Student>> map = new HashMap<String, List<Student>>();
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("ssm", "888888"));
        studentList.add(new Student("boot", "123456"));
        studentList.add(new Student("cloud", "741147"));
        map.put("studentList", studentList);
        System.out.println("缓存成功");
        return map;
    }

02、无返回值,或者返回空,缓存空值

/**
     * 1、返回值为void 缓存空值
     * 2、返回null 缓存空值
     * TODO 【NullValue】
     *  sr+org.springframework.cache . support.NullValue xp
     */
    @Cacheable(value = "student", key = "#root.method.name")
    @GetMapping("/saveCache02")
    public void saveCache02() {
        System.out.println("方法saveCache02执行");
        HashMap<String, List<Student>> map = new HashMap<String, List<Student>>();
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("ssm", "888888"));
        studentList.add(new Student("boot", "123456"));
        studentList.add(new Student("cloud", "741147"));
        map.put("studentList", studentList);
        System.out.println("缓存成功");
    }

4.5.2、@CacheEvict(失效模式)

简单的说:就是你执行了修改/删除的操作,他会将缓存里面数据给清除

第一种、删除单个

	 /**
     * 失效模式(可以叫删除模式)
     * value = "student",key = "'saveCache01'" 注意单引号
     * student是分区名字
     * saveCache01是缓存的key值。使用@Cacheable缓存的时候spEl我们指定的方法名
     * todo @CacheEvict(value = "student",allEntries = true)  allEntries = true表示删除student分区下所有数据
     */
    @CacheEvict(value = "student", key = "'saveCache01'")//缓存 失效模式
    @GetMapping("/updateData")
    public void updateData() {
        System.out.println("执行失效模式,删除缓存");
    }

第二种、删除多个,将整个分区的缓存都清除

好比说 a下面有b和c 。将b和c一起删除

所以:同一业务\同一类型缓存的数据要放在同一的分区下面

	//1、失效模式 
	//2、allEntries = true 删除分区所有的数据
 	@CacheEvict(value = "category",allEntries = true)
    @Transactional
    @Override
    public void updateCascade(CategoryEntity category) {
		//service的业务代码
		
	}

4.5.3、@Caching(组合使用)

源码:
在这里插入图片描述
比如说要让哪个分区下面的哪个缓存失效(删除)

	/**
     * TODO @Caching 组合注解 允许在同一方法上使用多个嵌套的 @Cacheable、@CachePut和@CacheEvict
     * value ==> student分区
     * key   ==> saveCache01 缓存的key名称
     * 个人感觉还是使用@CacheEvict的删除分区里面全部的缓存方便点
     */
    @Caching(evict = {
            @CacheEvict(value = "student", key = "'saveCache01'"),
            @CacheEvict(value = "student", key = "'saveCache02'")
    })
    @GetMapping("/selectEvict")
    public void selectEvict() {
        System.out.println("组合注解=>指定分区下失效的key");
    }

4.5.4、@CachePut(双写模式)

/**
     *  @CachePut
     * 根据返回值更新缓存,【双写模式】,用得比较少,这边就不搞了
     */
    @CachePut
    @GetMapping("/testPut")
    public void testPut() {
        System.out.println("双写模式");
    }

4.5.5、redisTemplate获取数据方法

  1. 这边使用的是StringRedisTemplate
  2. 没使用RedisTemplate因为没去重构序列化器

	@Autowired
    StringRedisTemplate redisTemplate;//采用string的序列化构造器

	
	 @GetMapping("/getCache")
    public void getCache() {
        HashMap<String, List<Student>> map = new HashMap<String, List<Student>>();
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("ssm", "888888"));
        studentList.add(new Student("boot", "123456"));
        studentList.add(new Student("cloud", "741147"));
        map.put("studentList", studentList);
        redisTemplate.opsForValue().set("student::saveCache03", String.valueOf(map));
        System.out.println("获取缓存");
        String s = redisTemplate.opsForValue().get("student::saveCache03");
        System.out.println(s);
    }

4.5.6、测试效果

01、
在这里插入图片描述
02、
在这里插入图片描述
03、
在这里插入图片描述
04、
在这里插入图片描述

五、简单实战案例

实体类:

package sqy.pojo;

import org.springframework.stereotype.Component;

/**
 * @author suqinyi
 * @Date 2022/1/21
 * user表
 */
//@Component
public class User {

    private String id;//主键
    private String userName;//用户名
    private String password;//密码

	//get /set /构造、tostring...省略
}


实战测试:

package sqy.controller;

import org.springframework.cache.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import sqy.pojo.User;

import java.io.IOException;

/**
 * @author suqinyi
 * @Date 2022/1/21
 * springCache的实战使用【sqy测】--- TODO 缓存数据不要去数据库直接改数据!!!
 */
@RestController
@CacheConfig(cacheNames = "user")//指定缓存空间的名称
//@Lazy//懒加载--这个有毒测试着玩,用于注入的service
public class UserCacheController {

    
    /**
     * todo 说明
     *
     * @Cacheable 必须要有返回【实体、list、map】-- 用于 查询
     * @CachePut 必须要有返回【实体、list、map】-- 用于 新增、修改
     * @CacheEvict 返回值为void--用于 删除
     * @CacheConfig 配置      --通常用于指定缓存空间名称较多
     * @Cacheable 组合注解  [ cacheable() 、put()、evict() ] 存、加、删
     */
//    private static List<User> list = new ArrayList<>();


    //模拟从数据库获取到数据
    private User getUserData01() {
        User user = new User("001", "userOO1", "123456");
        return user;
    }
    //模拟从数据库获取到数据
    private User getUserData02() {
        User user = new User("002", "userOO2", "789456");
        return user;
    }




    /**
     * 主键查询--这个缓存是在service做,测试案例我就之间在controller写了
     * 名称空间value 在controller统一指定了
     * 缓存key为 名称空间::id
     *
     * @Cacheable(key = "#qvo.id",unless = "#result!=null" )
     * unless = "#result!=null" 返回的结果不为空才缓存
     * 这个方法不缓存空值
     * localhost:8080/findById
     * post  json  {"id":"1"}
     */
    @PostMapping("/findById")
    @Cacheable(key = "#qvo.id")
    public User findById(@RequestBody User qvo) {
        System.out.println("执行方法-findById");
        //查到数据
        if ("001".equals(qvo.getId())) {
            User user = getUserData01();
            return user;
        } else {
            return null;
        }
    }


    /**
     * 用户名查询
     * 名称空间value 在controller统一指定了
     * 缓存key为 名称空间::id
     * 这个查询缓存空值  sr+org.springframework.cache . support.NullValue xp
     * localhost:8080/findByName
     * post json {"userName":"userOO1"}
     */
    @PostMapping("/findByName")
    @Cacheable(key = "#qvo.userName")
    public User findByName(@RequestBody User qvo) {
        System.out.println("执行方法-findByName");
        //查到数据
        if ("userOO1".equals(qvo.getUserName())) {
            User user = getUserData01();
            return user;
        } else {
            return null;
        }
    }


    /**
     * 新增数据-测试 @Caching组合注解
     * 缓存新增的id和用户名
     * condition = "#result != null" 当结果不为空时缓存
     * localhost:8080/userSave
     * post json  {"id":"002","userName":"user002"}
     */
    @PostMapping("/userSave")
    @Caching(put = {
            @CachePut(key = "#result.id", condition = "#result != null"),
            @CachePut(key = "#result.userName", condition = "#result != null")
    })
    public User userSave(@RequestBody User vo) throws IOException {
        if ("002".equals(vo.getId()) && "user002".equals(vo.getUserName())) {
            //1、存入数据库 2、查询数据返回
            System.out.println(vo);
            return vo;
        } else {
            return null;
        }
    }

    /**
     * 修改数据-测试 @Caching组合注解---
     * 【有双写模式@CachePut 和 失效模式@CacheEvict 】
     * 缓存新增的id和用户名
     * condition = "#result != null" 当结果不为空时缓存
     *
     *  localhost:8080/userUpdate
     *  post json  {"id":"002","userName":"user003"}
     */
    @PostMapping("/userUpdate")
    @Caching(put = {
            @CachePut(key = "#result.id", condition = "#result != null"),
            @CachePut(key = "#result.userName", condition = "#result != null")
    })
    public User userUpdate(@RequestBody User vo) {
        //将原本2号数据user002改成user003
        if ("002".equals(vo.getId()) && "user003".equals(vo.getUserName())) {
            //查数据
            User user = getUserData02();
            //更新
            user.setUserName(vo.getUserName());
            user.setPassword(vo.getPassword());
            return user;
        } else {
            return null;
        }
    }


    /**
     * 删除数据
     * 缓存新增的id和用户名
     * condition = "#result != null" 当结果不为空时缓存
     * localhost:8080/userDel
     * post json {"id":"001","userName":"user001"}
     *
     */
    @PostMapping("/userDel")
    @Caching(evict = {
            @CacheEvict(key = "#vo.id"),
            @CacheEvict(key = "#vo.userName")
    })
    public void userDel(@RequestBody User vo) throws Exception {
        //删除1号数据
        if ("001".equals(vo.getId()) && "user001".equals(vo.getUserName())) {
            //1、查数据
            User user = getUserData01();
            System.out.println(user);
            //2、删除  ...
        } else {
            throw new Exception("id不是1,不能删");
        }
    }

    /**
     * 查询-有缓存就查缓存,不走方法
     * localhost:8080/findUser
     * post josn {"id":"001","userName":"user001"}
     */
    @PostMapping("/findUser")
    public void findUser(@RequestBody User vo) throws Exception {
        if ("001".equals(vo.getId())) {
            User user = this.findById(vo);
            System.out.println("findById==>" + user);
        }
        if ("user001".equals(vo.getUserName())) {
            User user = this.findByName(vo);
            System.out.println("findByName==>" + user);
        }
    }

}

效果:

在这里插入图片描述

六、小归纳

@Cacheable
     代表当前方法的结果需要缓存
      如果缓存种有,方法不用调用
      如果缓存中没有,就会调用方法,将方法的结果放入缓存
    
      @Cacheable(value = {"category"})
      		每一个需要缓存的数据都来指定要放到那个名字缓存。[缓存的分区(推荐按照业务类型划分)]
    
      默认行为
          1、缓存中有,方法不用调用
          2、key默认生成,缓存的名字::SimpleKey [](自主生成的key值)
          3、缓存value的值,默认采用jdk序列化机制,将序列化后的数据存到redis
          4、默认的ttl时间是 -1 代表永不过期
    
      自定义操作:
          1)、指定生成的缓存使用的key:      使用key属性指定,接收一个spEl表达式
                    spEl语法说明==>官方表达式地址说明:https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-spel-context
    
          2)、指定缓存的数据的存活时间:      在配置文件中修改ttl
          3)、将数据保存为json (因为json跨平台跨语言能交互)
          	  源码类
             	 CacheAutoConfiguration
              	 RedisCacheConfiguration

七 、Spring-Cache的不足:

SpringCache对读模式都进行处理,解决了缓存击穿,缓存穿透,缓存雪崩的问题
但是对写模式并没有去处理

读模式(SpringCache都处理了)

  1. 缓存穿透:查询一个null数据。 解决方法:缓存空数据。 spring.cache.redis.use-key-prefix=true
  2. 缓存击穿:大量并发进来,查询一个正好过期的数据。 解决方法:加锁 :默认是无加锁的; sync = true(加锁,解决缓存击穿)
  3. 缓存雪崩:大量的key同时过期 解决方法:加随机时间 (很容易弄巧成拙,要注意) spring.cache.redis.time-to-live=3600000

写模式(SpringCache没有管)

我们该如何解决(3种方式)

  1. 读写加锁
  2. 引入中间件Canal,感知到mysql的更新去更新
  3. 读多写多的,直接去数据库查询

八、个人推荐:

  1. 如果集成最后要配置缓存管理。要加锁、加自动过期等配置
  2. 当然还有其他选择如:
    redis、
    redisson 分布式、
    caffeine 这个会增大服务器压力、
    Guava 是Google Fuava中的一个内存缓存模块、
    Ehcache 是一个Java实现的开源分布式缓存框、
    JBoss Cache 分布式

九、小结:

常规数据:(读多写少,即使性、一致性要求不高的的数据)
完成可以使用spring-cache,写模式(是要缓存的数据有过期时间就足够了)


特殊数据: 特殊设计

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
SpringBoot非官方教程》 入门篇 SpringBoot非官方教程 | 第一篇:构建第一个SpringBoot工程 配置篇 SpringBoot非官方教程 | 第二篇:Spring Boot配置文件详解 数据库SpringBoot非官方教程 | 第三篇:SpringBoot用JdbcTemplates访问Mysql SpringBoot非官方教程 | 第四篇:SpringBoot 整合JPA SpringBoot非官方教程 | 第五篇:springboot整合 beatlsql SpringBoot非官方教程 | 第六篇:springboot整合mybatis SpringBoot非官方教程 | 第七篇:springboot开启声明式事务 SpringBoot非官方教程 | 第八篇:springboot整合mongodb SpringBoot非官方教程 | 第九篇: springboot整合Redis 构架文档篇 SpringBoot非官方教程 | 第十篇: 用spring Restdocs创建API文档 SpringBoot非官方教程 | 第十一篇:springboot集成swagger2,构建优雅的Restful API SpringBoot非官方教程 | 第十二篇:springboot集成apidoc 缓存SpringBoot非官方教程 | 第十三篇:springboot集成spring cache 消息队列 SpringBoot非官方教程 | 第十四篇:在springboot中用redis实现消息队列 SpringBoot非官方教程 | 第十五篇:Springboot整合RabbitMQ 网络相关 SpringBoot非官方教程 | 第十六篇:用restTemplate消费服务 SpringBoot非官方教程 | 第十七篇:上传文件 任务调度 SpringBoot非官方教程 | 第十八篇: 定时任务(Scheduling Tasks) 表单相关 SpringBoot非官方教程 | 第十九篇: 验证表单信息 SpringBoot非官方教程 | 第二十篇: 处理表单提交 其他 SpringBoot非官方教程 | 第二十一篇: springboot集成JMS SpringBoot非官方教程 | 第二十二篇: 创建含有多module的springboot工程 SpringBoot非官方教程 | 第二十三篇: 异步方法 SpringBoot非官方教程 | 第二十四篇: springboot整合docker 案例 SpringBoot非官方教程 | 第二十五篇: 2小时学会springboot
# 该项目骨架集成了以下技术: - SpringBoot多环境配置 - SpringMVC - Spring - MyBaits - MyBatis Generator - MyBatis PageHelper - Druid - Lombok - JWT - Spring Security - JavaMail - Thymeleaf - HttpClient - FileUpload - Spring Scheduler - Hibernate Validator - Redis Cluster - MySQL主从复制,读写分离 - Spring Async - Spring Cache - Swagger - Spring Test - MockMvc - HTTPS - Spring DevTools - Spring Actuator - Logback+Slf4j多环境日志 - i18n - Maven Multi-Module - WebSocket - ElasticSearch # 功能们: ## 用户模块 - 获取图片验证码 - 登录:解决重复登录问题 - 注册 - 分页查询用户信息 - 修改用户信息 ## 站内信模块 - 一对一发送站内信 - 管理员广播 - 读取站内信(未读和已读) - 一对多发送站内信 ## 文件模块 - 文件上传 - 文件下载 ## 邮件模块 - 单独发送邮件 - 群发邮件 - Thymeleaf邮件模板 ## 安全模块 - 注解形式的权限校验 - 拦截器 ## 文章管理模块 - 增改删查 # 整合注意点 1. 每个Mapper上都要加@Mapper 2. yaml文件 @Value获取xx.xx.xx不可行,必须使用@ConfigurationProperties,指定prefix,属性设置setter和getter 3. logback日志重复打印:自定义logger上加上 ` additivity="false" ` 4. SpringBoot 项目没有项目名 5. 登录 Spring Security +JWT - 已登录用户验证token - 主要是在Filter中操作。 从requestHeader中取得token,检查token的合法性,检查这一步可以解析出username去查数据库; 也可以查询缓存,如果缓存中有该token,那么就没有问题,可以放行。 - 未登录用户进行登录 - 登录时要构造UsernamePasswordAuthenticationToken,用户名和密码来自于参数,然后调用AuthenticationManager的authenticate方法, 它会去调用UserDetailsService的loadFromUsername,参数是token的username,然后比对password,检查userDetails的一些状态。 如果一切正常,那么会返回Authentication。返回的Authentication的用户名和密码是正确的用户名和密码,并且还放入了之前查询出的Roles。 调用getAuthentication然后调用getPrinciple可以得到之前听过UserDetailsService查询出的UserDetails - 在Controller中使用@PreAuthorize等注解需要在spring-web配置文件中扫描security包下的类 6. 引用application.properties中的属性的方式:@ConfigurationProperties(prefix = "spring.mail") + @Component + setter + getter 7. 引用其他自定义配置文件中的属性的方式: - @Component - ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
spring boot 实践学习案例,与其它组件结合如 mybatis、jpa、dubbo、redis、mongodb、memcached、kafka、rabbitmq、activemq、elasticsearch、security、shiro等 #### Spring Boot 版本 - 2.0.3.RELEASE #### 模块说明 - springboot-basic - Spring Boot 基础知识,包括SpringBoot起步、配置详解、aop、filter、拦截器、监听、启动器、全局异常处理、外部Tomcat启动、HTTPS、监控 等。 - springboot-data - Spring Boot 数据库操作,包括SpringJDBC、JPA、Mybatis注解版 & XML版、MongoDB。其中,每个版本都有其对应的多数据源解决方案。 - springboot-caches - Spring Boot 缓存,包括redis、ehcachespring-cache、memcached、使用redis实现session共享 等。 - springboot-templates - Spring Boot 模板,包括thymeleaf、freemarker、jsp、表单校验 等。 - springboot-docs - Spring Boot 文档生成工具,包括 Swagger、Spring RestDocs - springboot-bussiness - Spring Boot 业务应用,包括 定时任务、上传文件、发送邮件、Doc文档操作 等。 - springboot-ajax - Spring Boot AJAX 跨域,包括 JSONP、Node.js与SpringBoot集成使用反向代理 等。 - springboot-websockets - Spring Boot 使用 Websocket - springboot-webflux - Spring Boot 集成 WebFlux 开发反应式 Web 应用 - springboot-dubbo - Spring Boot 集成 Dubbo 的三种方式 - springboot-search - Spring Boot 集成 搜索引擎,包括 elasticsearch、solr - springboot-mq - Spring Boot 集成 消息队列,包括 kafka、rabbitmq、activemq、rocketmq、redismq - springboot-auth - Spring Boot 权限认证,包括 Apache Shiro、Spring Security - springboot-cloud - Spring Cloud 入门,包括 Eureka(服务注册与发现)、Config(配置中心)、Hystrix(断路器)、Bus(消息总线) 等

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suqinyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值