二级缓存
java@CacheNamespace(implementation = MybatisEhcacheCache.class)### 一、导入依赖xml<!-- 缓存开始 --><!-- 开启二级缓存 --><dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId></dependency><!-- 缓存结束 -->完整的 pomxml<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.xxtsoft</groupId> <artifactId>call-center</artifactId> <version>0.0.1-SNAPSHOT</version> <name>call-center</name> <description>信讯通呼叫中心标准版</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- thymeleaf 模版引擎 begin --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency> <!-- thymeleaf 模版引擎 end --> <!-- spring-boot-starter begin --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- spring-boot-starter end --> <!-- web begin --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- end begin --> <!-- devtools begin --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <!-- devtools end --> <!-- 数据库驱动 begin --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- 数据库驱动 end --> <!-- 用传统的 xml 或 properties 配置,就需要使用 spring-boot-configuration-processor begin --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- end --> <!-- lombok begin --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- lombok end --> <!-- 测试 starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <!-- 测试 starter 结束 --> <!-- 安全 开始--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- 安全 结束--> <!--数据校验 begin--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!--数据校验 end--> <!-- mybatis 开始 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <!-- 代码生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> </dependency> <!-- 引入 freemarker包 作为代码生成器引擎 --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> <!-- mybatis 结束 --> <!-- hutool 工具包 begin --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.4.4</version> </dependency> <!-- hutool 工具包 end --> <!-- json 依赖 开始 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency> <!-- json 依赖 结束 --> <!-- swagger 开始 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <!-- swagger 结束 --> <!-- apache 开始 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.1</version> <exclusions> <exclusion> <artifactId>poi-ooxml-schemas</artifactId> <groupId>org.apache.poi</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>3.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.11</version> </dependency> <!-- apache 结束 --> <!-- junit 测试开始 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!-- junit 测试 结束 --> <!-- web jar 开始 --> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <version>0.34</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.3.6</version> <exclusions> <exclusion> <artifactId>jquery</artifactId> <groupId>org.webjars</groupId> </exclusion> </exclusions> </dependency> <!-- <dependency>--> <!-- <groupId>org.webjars.bowergithub.dreamerlxb</groupId>--> <!-- <artifactId>jquery-easyui</artifactId>--> <!-- <version>1.9.0</version>--> <!-- </dependency>--> <dependency> <groupId>org.webjars</groupId> <artifactId>font-awesome</artifactId> <version>4.4.0</version> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>animate.css</artifactId> <version>4.1.1</version> </dependency> <dependency> <groupId>org.webjars.bower</groupId> <artifactId>bootstrap-table</artifactId> <version>1.14.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>zTree</artifactId> <version>3.5.18</version> <exclusions> <exclusion> <artifactId>jquery</artifactId> <groupId>org.webjars</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>bootstrap-select</artifactId> <version>1.13.14</version> </dependency> <dependency> <groupId>org.webjars.bower</groupId> <artifactId>metisMenu</artifactId> <version>1.1.3</version> <exclusions> <exclusion> <groupId>org.webjars.bower</groupId> <artifactId>bootstrap</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jQuery-slimScroll</artifactId> <version>1.3.1</version> <exclusions> <exclusion> <artifactId>jquery</artifactId> <groupId>org.webjars</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>pace</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery-cookie</artifactId> <version>1.4.1</version> <exclusions> <exclusion> <artifactId>jquery</artifactId> <groupId>org.webjars</groupId> </exclusion> </exclusions> </dependency> <!-- 缓存开始 --> <!-- 开启二级缓存 --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!-- 缓存结束 --> <dependency> <groupId>org.webjars.bower</groupId> <artifactId>jquery.serializeJSON</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>echarts</artifactId> <version>2.1.10</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>layui</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.webjars.bowergithub.sentsin</groupId> <artifactId>layer</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>vue</artifactId> <version>2.6.11</version> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>axios</artifactId> <version>0.20.0</version> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>element-ui</artifactId> <version>2.14.0</version> </dependency> <!-- web jar 结束 --> </dependencies> <build> <plugins> <plugin> <!--热部署配置--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.4</version> <configuration> <argLine>-Xmx1024m</argLine> </configuration> </plugin> </plugins> </build></project>### 二、设置配置文件application.yml````yml# 连接数据库spring: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.6.250:3306/call_center?sserverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8 # url: jdbc:mysql://10.8.0.142:3306/call_center?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 username: root password: XXT123456. devtools: restart: # spring boot devtools 热部署后访问报 404 问题 # https://www.jianshu.com/p/9337fd517291 poll-interval: 3000ms quiet-period: 2999ms # 配置 redis 缓存 redis: # host: 10.8.0.142 host: 192.168.6.250 port: 6379 password: XXT123456. database: 1 timeout: 2000ms # 连接超时时间(毫秒)默认是2000ms lettuce: pool: max-active: 200 # 连接池最大连接数(使用负值表示没有限制) max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) max-idle: 100 # 连接池中的最大空闲连接 min-idle: 50 # 连接池中的最小空闲连接 shutdown-timeout: 100ms# MyBatis plus 显示 SQL 语句mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 使用缓存 cache-enabled: true# ===================================================================# 日志配置 从低到高# log.trace("trace");# log.debug("debug");# log.info("info");# log.warn("warn");# log.error("error");# ===================================================================logging: # 对 com.xxtsoft 下的文件开启 trace 级别的日志 level: com: xxtsoft: traceserver: port: 8081 servlet: context-path: /call```### 三、创建RedisUtil封装RedisTemplateRedisTemplatejavapackage com.xxtsoft.util.redis;import cn.hutool.core.collection.ListUtil;import cn.hutool.core.lang.Validator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.TimeUnit;/** * redis 工具类 * * @author yang */@Componentpublic class RedisUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private StringRedisTemplate stringRedisTemplate; /** * 指定缓存失效时间 * * @param key 键 * @param time 时间(秒) * @return boolean */ public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据key 获取过期时间 * * @param key 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ public Long getExpire(String key) { final Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS); assert expire != null; return expire; } /** * 判断key是否存在 * * @param key 键 * @return true 存在 false不存在 */ public Boolean hasKey(String key) { try { final Boolean aBoolean = redisTemplate.hasKey(key); assert aBoolean != null; return aBoolean; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除缓存 * * @param key 可以传一个值 或多个 */ public void del(String... key) { if (Validator.isNotNull(key) && Validator.isTrue(key.length > 0)) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete(ListUtil.toList(key)); } } } // ============================String============================= /** * 普通缓存获取 * * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入 * * @param key 键 * @param value 值 * @return true成功 false失败 */ public Boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通缓存放入并设置时间 * * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 递增 * * @param key 键 * @param delta 要增加几(大于0) * @return long */ public Long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * * @param key 键 * @param delta 要减少几(大于0) * @return long */ public Long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * * @param key 键 不能为null * @param item 项 不能为null * @return 值 */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * * @param key 键 * @return 对应的多个键值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * * @param key 键 * @param map 对应多个键值 * @return true 成功 false 失败 */ public boolean hmset(String key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * HashSet 并设置时间 * * @param key 键 * @param map 对应多个键值 * @param time 时间(秒) * @return true成功 false失败 */ public boolean hmset(String key, Map<String, Object> map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * * @param key 键 * @param item 项 * @param value 值 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * * @param key 键 * @param item 项 * @param value 值 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除hash表中的值 * * @param key 键 不能为null * @param item 项 可以使多个 不能为null */ public Object hdel(String key, Object... item) { return redisTemplate.opsForHash().delete(key, item); } /** * 判断hash表中是否有该项的值 * * @param key 键 不能为null * @param item 项 不能为null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * * @param key 键 * @param item 项 * @param by 要增加几(大于0) * @return 新增后的值 */ public Double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash递减 * * @param key 键 * @param item 项 * @param by 要减少记(小于0) * @return 新减后的值 */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } /** * hash 键数量 * * @param key key * @return int */ public int hsize(String key) { return redisTemplate.opsForHash().size(key).intValue(); } // ============================set============================= /** * 根据 key 获取 Set 中的所有值 * * @param key 键 * @return 所有值 */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根据value从一个set中查询,是否存在 * * @param key 键 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { try { final Boolean member = redisTemplate.opsForSet().isMember(key, value); assert member != null; return member; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将数据放入set缓存 * * @param key 键 * @param values 值 可以是多个 * @return 成功个数 */ public long sSet(String key, Object... values) { try { final Long add = redisTemplate.opsForSet().add(key, values); assert add != null; return add; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 将 set 数据放入缓存 * * @param key 键 * @param time 时间(秒) * @param values 值 可以是多个 * @return 成功个数 */ public Long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) { expire(key, time); } return count; } catch (Exception e) { e.printStackTrace(); return 0L; } } /** * 获取 set 缓存的长度 * * @param key 键 * @return set 缓存的长度 */ public long sGetSetSize(String key) { try { final Long size = redisTemplate.opsForSet().size(key); assert size != null; return size; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 移除值为value的 * * @param key 键 * @param values 值 可以是多个 * @return 移除的个数 */ public long setRemove(String key, Object... values) { try { Long count = redisTemplate.opsForSet().remove(key, values); assert count != null; return count; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================list================================= /** * 获取 list 缓存的内容 * * @param key 键 * @param start 开始 * @param end 结束 0 到 -1代表所有值 * @return 缓存的内容 */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取 list 缓存的长度 * * @param key 键 * @return 缓存的长度 */ public long lGetListSize(String key) { try { final Long size = redisTemplate.opsForList().size(key); assert size != null; return size; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 通过索引 获取 list 中的值 * * @param key 键 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return list 中的值 */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 将 list 放入缓存 * * @param key 键 * @param value 值 * @return 是否成功 */ public boolean lSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将 list 放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return boolean */ public boolean lSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将 list 放入缓存 * * @param key 键 * @param value 值 * @return boolean */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return boolean */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据索引修改 list 中的某条数据 * * @param key 键 * @param index 索引 * @param value 值 * @return boolean */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 移除N个值为value * * @param key 键 * @param count 移除多少个 * @param value 值 * @return 移除的个数 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); assert remove != null; return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================sorted set 有序集合================================= /** * 添加一个元素 * * @param key 键 * @param value 值 * @param score 分值 */ public void zAdd(String key, Object value, double score) { redisTemplate.opsForZSet().add(key, value, score); } /** * 返回有序集中,成员的分数值 * * @param key 键 * @param value 值 * @return 成员的分数值 */ public double zScore(String key, Object value) { Double d = redisTemplate.opsForZSet().score(key, value); d = d == null ? 0L : d; return d; } /** * 判断 value 在 zset 中的排名 * * @param key 键 * @param value 值 * @return 排名 */ public Long zRank(String key, Object value) { Long index = redisTemplate.opsForZSet().rank(key, value); index = index == null ? 0L : index; return index; } /** * 查询 集合中 指定顺序 的 值 和 score * <p> * (start=0 & end = -1)表示获取全部的集合内容 * * @param key 键 * @param start 开始 * @param end 结束 * @return 全部的集合内容 */ public Set<Object> zRangeWithScore(String key, long start, long end) { return redisTemplate.opsForZSet().rangeByScore(key, start, end); }}```### 四、`SpringContextUtils` :维护 Spring 中的实例> [可以使用 hutool 的 Spring 工具 - SpringUtil 来替换](https://hutool.cn/docs/#/extra/Spring/Spring%E5%B7%A5%E5%85%B7-SpringUtil)```javapackage com.xxtsoft.util.spring;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.util.Objects;/** * Spring 工具类 * * @author yang */@Componentpublic class SpringContextUtils implements ApplicationContextAware { /** * 上下文对象实例 */ private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtils.applicationContext = applicationContext; } /** * 获取applicationContext * * @return 获取applicationContext */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 获取HttpServletRequest */ public static HttpServletRequest getHttpServletRequest() { return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); } public static String getDomain() { HttpServletRequest request = getHttpServletRequest(); StringBuffer url = request.getRequestURL(); return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString(); } public static String getOrigin() { HttpServletRequest request = getHttpServletRequest(); return request.getHeader("Origin"); } /** * 通过name获取 Bean. * * @param name name * @return Bean */ public static Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通过class获取Bean. * * @param clazz 类 * @param <T> 类型 * @return bean */ public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通过name,以及Clazz返回指定的Bean * * @param name 名字 * @param clazz 类 * @param <T> 类型 * @return bean */ public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); }}```### 五、`RedisConfig` :配置`Redis` 的 `RedisTemplate` 和 `CacheManager` 并载入 `Spring IOC` 容器```javapackage com.xxtsoft.config;import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;import com.fasterxml.jackson.databind.SerializationFeature;import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.CachingConfigurerSupport;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.cache.RedisCacheManager;import org.springframework.data.redis.cache.RedisCacheWriter;import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.*;import javax.annotation.Resource;import java.time.Duration;import static java.util.Collections.singletonMap;/** * redis 配置类 * * @author yang */@Configuration@EnableCachingpublic class RedisConfig extends CachingConfigurerSupport { @Resource private LettuceConnectionFactory lettuceConnectionFactory; /** * RedisTemplate 配置 * * @param lettuceConnectionFactory lettuceConnectionFactory * @return RedisTemplate */ @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { // 设置序列化 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, Visibility.ANY); om.enableDefaultTyping(DefaultTyping.NON_FINAL); // 解决jackson2无法反序列化LocalDateTime的问题 om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); om.registerModule(new JavaTimeModule()); jackson2JsonRedisSerializer.setObjectMapper(om); // 配置redisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); RedisSerializer<?> stringSerializer = new StringRedisSerializer(); // key序列化 redisTemplate.setKeySerializer(stringSerializer); // value序列化 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // Hash key序列化 redisTemplate.setHashKeySerializer(stringSerializer); // Hash value序列化 redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } /** * 缓存配置管理器 * * @param factory factory * @return CacheManager */ @Bean public CacheManager cacheManager(LettuceConnectionFactory factory) { // 配置序列化(缓存默认有效期 6小时) RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(6)); RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); /* 自定义配置test:demo 的超时时间为 5分钟*/ return RedisCacheManager .builder(RedisCacheWriter.lockingRedisCacheWriter(factory)) .cacheDefaults(redisCacheConfiguration) .withInitialCacheConfigurations(singletonMap("test:demo", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).disableCachingNullValues())) .transactionAware() .build(); }}```### 六、创建 `MybatisRedisCache` 实现 `org.apache.ibatis.cache.Cachejavapackage com.xxtsoft.config;import cn.hutool.extra.spring.SpringUtil;import com.xxtsoft.util.redis.RedisUtil;import lombok.Setter;import org.apache.ibatis.cache.Cache;import org.springframework.stereotype.Component;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/** * 缓存实现类 * * @author 杨磊 /@Componentpublic class MybatisRedisCache implements Cache { private RedisUtil redisUtil; private RedisUtil getRedis() { return SpringUtil.getBean(RedisUtil.class); } private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); /* * 缓存刷新时间(秒) */ @Setter private long flushInterval = 0L; private String id; public MybatisRedisCache() { } public MybatisRedisCache(final String id) { if (id == null) { throw new IllegalArgumentException(“Cache instances require an ID”); } this.id = id; } @Override public String getId() { return this.id; } @Override public void putObject(Object o, Object o1) { getRedis().hset(getId(), o.toString(), o1); if (flushInterval > 0L) { getRedis().expire(getId(), flushInterval); } } @Override public Object getObject(Object o) { return getRedis().hget(getId(), o.toString()); } @Override public Object removeObject(Object o) { return getRedis().hdel(getId(), o); } @Override public void clear() { getRedis().del(getId()); } @Override public int getSize() { return getRedis().hsize(getId()); } @Override public ReadWriteLock getReadWriteLock() { return readWriteLock; }}### 七、添加 缓存注解Mybatis 支持两种方式添加缓存注解,以下方案**二选一**即可:- 添加缓存注解 `@CacheNamespace`在代码中为每个 mapper 添加缓存注解,声明 implementation **或** eviction 的值为 `MybatisRedisCache````java@CacheNamespace(implementation = MybatisRedisCache.class,eviction=MybatisRedisCache.class)public interface UserMapper extends BaseMapper<User> {}- 在对应的 mapper.xml 中将原有注释修改为链接式声明,以保证 xml 文件里的缓存能够正常xml<cache-ref namespace="com.w.mapper.UserMapper"></cache-ref>
Mybatis-Plus 二级缓存
最新推荐文章于 2025-08-26 15:11:42 发布
本文介绍了如何在 Mybatis-Plus 中利用 Redis 实现二级缓存,包括导入相关依赖、配置文件设置以及在 mapper.xml 中的配置调整,确保缓存功能的正常工作。
4万+





