猴子也能懂的springboot教程(三) - springboot整合Redis

20190514180005.jpg

摘要

本文介绍
springboot整合redis
采用RedisCacheManager作为缓存管理器
并使用fastjson序列化

承接上篇
猴子也能懂的springboot教程(二) - springboot整合Mybatis
本次我们在原先代码基础上整合Redis
直接上代码。。。

添加依赖

在pom.xml中添加依赖文件

    <!--redis 依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.31</version>
    </dependency>

新增配置文件

在spring下级添加redis配置文件

spring:
  #mysql 配置略(参见上文)
  #redis
  redis:
    database: 0
    host: 192.168.162.134
    port: 6379
    password: redis
    pool:
      jedis:
        max-active: 200
        max-wait: -1
        max-idle: 10
        min-idle: 1
    timeout: 1000

自定义Redis序列化工具

创建com.gao.utils.FastJsonRedisSerializer类实现RedisSerializer接口

package com.gao.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;

public class FastJsonRedisSerializer<T> implements RedisSerializer<T>{

    private final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Class<T> clazz;

    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if(null == t) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (null == bytes || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes,DEFAULT_CHARSET);
        return (T)JSON.parseObject(str,clazz);
    }
}

配置Redis

创建com.gao.config.RedisConfig类,

package com.gao.config;

import com.alibaba.fastjson.parser.ParserConfig;
import com.gao.utils.FastJsonRedisSerializer;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
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.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;
import java.time.Duration;

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {

        //初始化一个RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
        //序列化方式
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);//JSONObject
        RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer);

        RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig();
        //设置缓存过期时间
        defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofMinutes(10));
        defaultCacheConfig = defaultCacheConfig.serializeValuesWith(pair);

        RedisCacheManager rcm = RedisCacheManager.builder(redisCacheWriter).cacheDefaults(defaultCacheConfig).transactionAware().build();
        ParserConfig.getGlobalInstance().addAccept("com.gao");
        return rcm;
    }

    /**
     * @Description: 防止redis入库序列化乱码的问题
     * @return     返回类型
     * @date 2018/4/12 10:54
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        StringRedisTemplate redisTemplate = new StringRedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //使用fastjson序列化
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        //key序列化使用StringRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //value序列化使用fastJsonRedisSerializer
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);  //value序列化
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}

封装redisTemplate

其实上一步已经可以直接调用redisTemplate操作Redis了,不过这里对其做了简单的封装。
缓存接口ICache
创建com.gao.cache.ICache接口类

package com.gao.cache;

public interface ICache<V> {
    /**
     * 60秒
     */
    public static final long ONE_MIN_SECONDS = 60;
    /**
     * 半小时
     */
    public static final long HALF_HOUR_SECONDS = 30 * ONE_MIN_SECONDS;

    /**
     * 保存自定义时长
     */
    void set(final String key, V value, Long expireTime);

    /**
     * 保存半小时
     */
    void setHalfHour(String key, V value);

    /**
     * 查询
     */
    V get(final String key);

    /**
     * 删除
     */
    public void remove(final String key);
}

实现ICache接口
创建com.gao.cache.impl.RedisCache实现ICache接口

package com.gao.cache.impl;
import ...;
import java.util.concurrent.TimeUnit;

@Component
public class RedisCache<V> implements ICache<V>{

    // 在构造器中获取redisTemplate实例, key(not hashKey) 默认使用String类型
    private RedisTemplate<String, V> redisTemplate;
    private ValueOperations<String, V> valueOperations;

    // 实例化操作对象后就可以直接调用方法操作Redis数据库
    @Autowired
    public RedisCache(RedisTemplate<String, V> redisTemplate) {
        this.redisTemplate = redisTemplate;
        this.valueOperations = redisTemplate.opsForValue();
    }

    @Override
    public void set(String key, V value, Long expireTime) {
        valueOperations.set(key, value ,expireTime, TimeUnit.SECONDS);
    }

    @Override
    public void setHalfHour(String key, V value) {
        set(key,value,HALF_HOUR_SECONDS);
    }

    @Override
    public V get(String key) {
        return valueOperations.get(key);
    }

    @Override
    public void remove(String key) {
        redisTemplate.delete(key);
    }
}

完成,开始测试

修改mapper

mapper接口中添加方法

@Mapper
public interface UserMapper {

    User getUserByName(String username);

    User getUserById(String Id);
}

mapper.xml中添加

<mapper namespace="com.gao.dao.UserMapper">
    <select id="getUserByName" parameterType="String" resultType="User">
        SELECT id, username, password FROM user WHERE username = #{username}
    </select>

    <select id="getUserById" parameterType="String" resultType="User">
        SELECT id, username, password FROM user WHERE id = #{id}
    </select>
</mapper>

修改service

service接口

public interface IUserService {
    User getUserByUsername(String username);

    User getUserById(String id);
}

service实现类

@EnableCaching
@Service
public class UserServiceIml implements IUserService{

    private Logger logger = LogManager.getLogger(this.getClass());

    @Autowired
    private ICache cache;

    @Autowired
    private UserMapper userMapper;

    @Value("${spring.redis.cache.user.key}")
    private String CACHE_USER_KEY;

    //显示调用缓存
    @Override
    public User getUserByUsername(String username) {
        User user = userMapper.getUserByName(username);
        cache.setHalfHour(CACHE_USER_KEY + user.getId(),user);
        return user;
    }
    //使用注解测试cacheManager
    @Cacheable(value = "user_id", key="#id")
    @Override
    public User getUserById(String id) {
        User user = userMapper.getUserById(id);
        logger.info("查询数据库");
        return user;
    }
}

修改controller

@RestController
@RequestMapping("test")
public class TestController {

    @Autowired
    private IUserService userService;

    @GetMapping("name/{name}")
    public String index(@PathVariable String name){
        User user = userService.getUserByUsername(name);
        return "hi " + user.getUsername() + " your id is "+ user.getId();
    }

    @GetMapping("id/{id}")
    public String getUserById(@PathVariable String id){
        User user = userService.getUserById(id);
        return "hi " + user.getId() + " your name is "+ user.getUsername();
    }
}

启动测试

先访问 http://localhost:8890/test/name/stephen 获得id

20190514100001.png

再访问 http://localhost:8890/test/id/8f5689836eef11e9869d000d29242eff 获得name
多次刷新页面,控制台只有一条日志,其余查询走了缓存

20190514100002.png

去Redis查询 keys *


20190514100003.png

至此springboot整合Redis完成

系列文章

猴子也能懂的springboot教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354