spring boot 缓存应用实例讲解

最近在做springboot的一个项目,用到缓存做登录验证(这块也可用Redis),学到了一些新知识,想和大家分享一下。

一、创建springboot项目

个人认为创建spring boot项目最快的地方就是访问spring.io官网,从官网创建,里面的一些基础配置都给我们配置好了,直接添加即可。

  1. 首先我们通过QUICKSTART进入
    在这里插入图片描述
  2. 点击start.spring.io,进入springboot的搭建界面,进行配置在这里插入图片描述
    在这里插入图片描述
  3. 选择成功以后直接下载,下载直接解压,导入maven项目(在这里我用的IDEA工具)在这里插入图片描述
  4. pom.xml中导入依赖内容如下:
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</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-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mybatis-plus完成项目构建所需模板,真实项目不需要使用-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
        <!--commons -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.70</version>
        </dependency>

      
        <!-- activeMq end -->
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
        </dependency>

        <!--js客户端的静态资源-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.7</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>

    </dependencies>

二、创建数据库表,导入数据库配置,反向生成代码

  1. 我设计了一个t_user表,包括id(主键自增) , use_name(登录名) , password(密码)在这里插入图片描述
  2. 将数据库连接信息以及基础配置加进项目的配置文件中
    在这里插入图片描述
spring.datasource.druid.url=jdbc:mysql://localhost:3306/byte_easy?useUnicode=true&characterEncoding=utf-8&serverTimezone=CTT
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
# \u521D\u59CB\u5316\u65F6\u5EFA\u7ACB\u7269\u7406\u8FDE\u63A5\u7684\u4E2A\u6570
spring.datasource.druid.initial-size=5
# \u6700\u5927\u8FDE\u63A5\u6C60\u6570\u91CF
spring.datasource.druid.max-active=30 
# \u6700\u5C0F\u8FDE\u63A5\u6C60\u6570\u91CF
spring.datasource.druid.min-idle=5
# \u83B7\u53D6\u8FDE\u63A5\u65F6\u6700\u5927\u7B49\u5F85\u65F6\u95F4\uFF0C\u5355\u4F4D\u6BEB\u79D2
spring.datasource.druid.max-wait=60000
# \u914D\u7F6E\u95F4\u9694\u591A\u4E45\u624D\u8FDB\u884C\u4E00\u6B21\u68C0\u6D4B\uFF0C\u68C0\u6D4B\u9700\u8981\u5173\u95ED\u7684\u7A7A\u95F2\u8FDE\u63A5\uFF0C\u5355\u4F4D\u662F\u6BEB\u79D2
spring.datasource.druid.time-between-eviction-runs-millis=60000
# \u8FDE\u63A5\u4FDD\u6301\u7A7A\u95F2\u800C\u4E0D\u88AB\u9A71\u9010\u7684\u6700\u5C0F\u65F6\u95F4
spring.datasource.druid.min-evictable-idle-time-millis=300000
# \u7528\u6765\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\u7684sql\uFF0C\u8981\u6C42\u662F\u4E00\u4E2A\u67E5\u8BE2\u8BED\u53E5
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
# \u5EFA\u8BAE\u914D\u7F6E\u4E3Atrue\uFF0C\u4E0D\u5F71\u54CD\u6027\u80FD\uFF0C\u5E76\u4E14\u4FDD\u8BC1\u5B89\u5168\u6027\u3002\u7533\u8BF7\u8FDE\u63A5\u7684\u65F6\u5019\u68C0\u6D4B\uFF0C\u5982\u679C\u7A7A\u95F2\u65F6\u95F4\u5927\u4E8EtimeBetweenEvictionRunsMillis\uFF0C\u6267\u884CvalidationQuery\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\u3002
spring.datasource.druid.test-while-idle=true
# \u7533\u8BF7\u8FDE\u63A5\u65F6\u6267\u884CvalidationQuery\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\uFF0C\u505A\u4E86\u8FD9\u4E2A\u914D\u7F6E\u4F1A\u964D\u4F4E\u6027\u80FD\u3002
spring.datasource.druid.test-on-borrow=false
# \u5F52\u8FD8\u8FDE\u63A5\u65F6\u6267\u884CvalidationQuery\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6709\u6548\uFF0C\u505A\u4E86\u8FD9\u4E2A\u914D\u7F6E\u4F1A\u964D\u4F4E\u6027\u80FD\u3002
spring.datasource.druid.test-on-return=false
# \u662F\u5426\u7F13\u5B58preparedStatement\uFF0C\u4E5F\u5C31\u662FPSCache\u3002PSCache\u5BF9\u652F\u6301\u6E38\u6807\u7684\u6570\u636E\u5E93\u6027\u80FD\u63D0\u5347\u5DE8\u5927\uFF0C\u6BD4\u5982\u8BF4oracle\u3002\u5728mysql\u4E0B\u5EFA\u8BAE\u5173\u95ED\u3002
spring.datasource.druid.pool-prepared-statements=true
# \u8981\u542F\u7528PSCache\uFF0C\u5FC5\u987B\u914D\u7F6E\u5927\u4E8E0\uFF0C\u5F53\u5927\u4E8E0\u65F6\uFF0CpoolPreparedStatements\u81EA\u52A8\u89E6\u53D1\u4FEE\u6539\u4E3Atrue\u3002
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=50
# \u914D\u7F6E\u76D1\u63A7\u7EDF\u8BA1\u62E6\u622A\u7684filters\uFF0C\u53BB\u6389\u540E\u76D1\u63A7\u754C\u9762sql\u65E0\u6CD5\u7EDF\u8BA1
spring.datasource.druid.filters=stat,wall
# \u901A\u8FC7connectProperties\u5C5E\u6027\u6765\u6253\u5F00mergeSql\u529F\u80FD\uFF1B\u6162SQL\u8BB0\u5F55
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# \u5408\u5E76\u591A\u4E2ADruidDataSource\u7684\u76D1\u63A7\u6570\u636E
spring.datasource.druid.use-global-data-source-stat=true
# druid\u8FDE\u63A5\u6C60\u76D1\u63A7
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=123456
# \u6392\u9664\u4E00\u4E9B\u9759\u6001\u8D44\u6E90\uFF0C\u4EE5\u63D0\u9AD8\u6548\u7387
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
  1. 我在项目继承了mybatis-plus,利用mybatis plus 的代码生成器来生成代码 。Mybatis-Plus官网地址.
    在这里插入图片描述(直接运行main方法)

三、配置缓存

  1. 在resourses目录下创建一个cache的文件夹,导入配置文件在这里插入图片描述

cache.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation = "http://ehcache.org/ehcache.xsd"
         updateCheck = "false">
    <!-- 指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
    <diskStore path = "java.io.tmpdir"/>
    <!-- 默认的管理策略 -->
    <defaultCache
            name = "serviceCacheToken"
            eternal = "false"
            maxElementsInMemory = "10000"
            overflowToDisk = "true"
            diskPersistent = "false"
            timeToIdleSeconds = "7200"
            timeToLiveSeconds = "7200"
            diskExpiryThreadIntervalSeconds = "120"
            memoryStoreEvictionPolicy = "LRU"/>
</ehcache>
  1. 在config包下导入CacheConfig.java(key生成策略),内容如下
package com.mbyte.easy.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName: CacheConfig
 * @Description: 缓存配置
 * @Author: zte
 * @Date: 2019-02-14 18:12
 * @Version 1.0
 **/
@Configuration
public class CacheConfig {
    
    
    private final static Logger logger = LoggerFactory.getLogger(CacheConfig.class);
    /**
     * @Title: classKey
     * @Description: 以【类名】为缓存的key值 一般用于【selectALL】查询
     * @Author: zte
     * @Date: 2019-03-01 15:42
     * @return: org.springframework.cache.interceptor.KeyGenerator
     * @throws:
     */
    @Bean
    public KeyGenerator classKey() {
    
    
        return (target, method, params) -> {
    
    
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            logger.info("缓存classKey-key:"+sb.toString());
            return sb.toString();
        };

    }
    /**
     * @Title: classMethodParamsKey
     * @Description: 以【类名+方法名+参数】为缓存的key值
     * @Author: zte
     * @Date: 2019-03-01 15:43
     * @return: org.springframework.cache.interceptor.KeyGenerator
     * @throws:
     */
    @Bean
    public KeyGenerator classMethodParamsKey() {
    
    
        return (target, method, params) -> {
    
    
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
    
    
                sb.append(obj == null ? "" : obj.toString());
            }
            logger.info("缓存classMethodParamsKey-key:"+sb.toString());
            return sb.toString();
        };

    }
}

  1. 主方法添加 开启缓存注解(必须在这里插入图片描述

四、实现登录接口

代码如下

package com.mbyte.easy.rest.login;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mbyte.easy.common.controller.BaseController;
import com.mbyte.easy.user.entity.User;
import com.mbyte.easy.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author zte
 * @title: LoginController
 * @projectName easy
 * @description: 用户登录接口
 * @date 2020/7/27 10:22 下午
 */

@RestController
@RequestMapping("/rest/login")
public class LoginController extends BaseController {
    
    
    @Autowired
    private IUserService userService;

    @Resource
    private CacheManager cacheManager;

    /**
     * 登录验证
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @GetMapping
    public Map<String, Object> index(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password){
    
    
        Map<String , Object> map = new HashMap<>();
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserName , username));
        if(user != null && user.getPassword().equals(password)){
    
    
            Cache cache = cacheManager.getCache("serviceCacheToken");//serviceCacheToken,需要与配置文件xml里面的name保持一致
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //放入缓存
            cache.put(uuid, user);

            map.put("uuid",uuid);
            map.put("msg","success");
            return map;
        }
        map.put("msg","用户名或密码不正确");
        return map;
    }

    /**
     * 根据token加载用户信息
     * @param token 令牌
     * @return
     */
    @GetMapping("/loadUser")
    public Map<String, Object> loadUser(@RequestParam(value = "token") String token){
    
    
        Cache cache = cacheManager.getCache("serviceCacheToken");
        Map<String , Object> map = new HashMap<>();
        User user = cache.get(token, User.class);
        if(user != null){
    
    
            map.put("user",user);
            map.put("msg","success");
            return map;
        }
        map.put("msg","令牌已失效!");
        return map;
    }
}

  1. 登录接口(index),传入两个参数(用户名和密码),然后根据用户名到数据库去匹配,如果不存在,直接返回错误信息,如果存在继续匹配密码,如果密码也正确,创建一个缓存:
Cache cache = cacheManager.getCache("serviceCacheToken");
//serviceCacheToken,需要与配置文件xml里面的name保持一致

生成一个UUID,作为key值,user对象作为value,存入缓存(类似于Map):

String uuid = UUID.randomUUID().toString().replaceAll("-", "");
//放入缓存
 cache.put(uuid, user);

然后将这个uuid返回回去,作为用户的身份标识,就是我们说的令牌。

  1. 根据身份标识加载用户信息接口:传入用户身份标识,然后我们根据身份标识去匹配,匹配成功,将缓存的value,也就是我们存的user对象返回回去,如果匹配失败,则返回错误信息。
 User user = cache.get(token, User.class);

五、postman测试接口

  1. 首先我们现在数据库加载一条数据
    在这里插入图片描述

  2. 验证失败,提示信息
    在这里插入图片描述

  3. 验证成功,返回用户身份标识,登录接口测试完毕。
    在这里插入图片描述

  4. 然后我们根据返回的uuid测试加载信息接口在这里插入图片描述
    我们可以看到,根据身份标识返回我们的用户信息

  5. 到这里,缓存应用就讲解完毕了。有问题欢迎评论区留言。

    扫描二维码关注公众号,回复: 12721976 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_44922113/article/details/107656195