1 需求

最近博客的音乐播放器出现了问题,无法获取到音乐的数据了,我才发现原来我以前用的不是网易官方的API(o(╥﹏╥)o),真是打了我一个措手不及啊。因为音乐播放器不是我自己写的(但还好为了适配我的网站我还是看了看它的代码,改了一部分接口),不知道数据格式是什么样的,只能自己看代码探索(也是绝了),所以难度系数增加了不少。

2 寻找API

首先面临的问题就是找到相关的API,我的需求是能返回我歌单里面的所有歌曲的详细信息(包括歌曲名,歌手,封面图片,歌曲链接等信息)。经过一番寻找,先是找到了别人提供的第三方的接口,可以获取到我所需要的信息,试了一下,音乐播放器又复活了。但是一方面因为再也不信任第三方的缘故,和速度问题,我还是决定使用官方的接口。又经过了一番寻找,摸索,终于找到了我需要的接口。因为没有接口能一次性满足我的要求,所以找到了两个替代接口。

2.1 获取歌单详细信息
http://music.163.com/api/playlist/detail?id=xxx

id为你歌单的id,如何找出你歌单的id,这个具体操作方法,你可以在网上找找,因为不是写这个,就不写这个方法了。接口返回结果如下:

2.2 获取歌曲链接
http://music.163.com/api/song/enhance/player/url?ids=["+id+"]&br=320000

id为歌曲的id,可以一次获取多个id之间使用逗号(,)分隔。br为歌曲的品质,320000代表320K(这里需要注意的是,如果没有相应的品质或者需要VIP才能享受的,会默认返回180K)。结果如下:

3 速度太慢

首先因为歌单中歌曲的数量很多,并且会一直增加,如果每次都向网易的接口那边请求数据,连接,读取,处理,传递,一连串的操作,我觉得速度非常的慢,完全不能忍受。还有就是返回的数据不是我所需求的格式,我还需要处理一下才返回给前端,这无疑不是又增加了开销吗!当然还有最重要的一个原因,请求太频繁,网易改接口了怎么办(我太难了o(╥﹏╥)o)。获取的数据不是立即需要更新的,需要重复使用,但是每次使用都要做一系列操作,导致速度慢。套上这个场景,我第一时刻就想到了缓存

4 SpringBoot及Spring默认缓存(ConcurrentMapCache)

首先使用的是默认的缓存,因为什么都不需要配置。了解一下注解使用缓存

4.1 使用注解开启缓存

4.2 使用@Cacheable注解
	@Cacheable(value = "playList",key = "#id")
    @RequestMapping("/music/getPlayList")
    public Object getLikePlayList(String id){
        
    }

SpEL表达式

其中value相当于文件夹(缓存的名称cacheName),key相当于文件夹下的文件名(这样在不同的value下存放key相同的值了)

4.3 新的问题

使用默认的存储虽说简单,不需要什么配置,但是所有的东西都交给了spring管理,我后台想看看缓存的数据都不方便,缓存又存储在服务器的内存中,这样以后缓存的数据越来越多,服务器还不炸了,还是让他们分开比较好。所以又想到了缓存的一把好手Redis

5 整合Redis使用缓存

5.1 配置文件
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=xxx
# Redis服务器连接端口
spring.redis.port=xxx
# Redis服务器连接密码(默认为空)
spring.redis.password=xxx
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000
5.2 Java类配置Redis对应配置
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {


    @Bean
    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
        //设置默认的过期时间(以秒为单位)
        redisCacheManager.setDefaultExpiration(600);
        
        //开启使用前缀,将会用冒号连接value和key,如果设置为false
        //不同value,同key将会覆盖,不会出现上面的情况(注意)
        redisCacheManager.setUsePrefix(true);
        //设置缓存名称(按value)的过期时间(以秒为单位)
        //redisCacheManager.setExpires();
        //例子:
        //Map<String, Long> timeToLiveMap = new HashMap<>(2);
        //timeToLiveMap.put("playList",200L);
        //timeToLiveMap.put("musicUrl",250L);
        return redisCacheManager;
    }

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        serializer.setObjectMapper(mapper);

        template.setValueSerializer(serializer);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }

}
5.3 Jackson2JsonRedisSerializer反序列化问题

按照下面这样写的话

	@Cacheable(value = "playList",key = "#id")
    @RequestMapping("/music/getPlayList")
    public JsonArray getLikePlayList(String id){
       	....
        return returnJsonArray;
    }

会报转换异常

java.lang.ClassCastException: java.util.ArrayList cannot be cast to net.sf.json.JSONArray

因为从Redis中取出的数据是一个List数组,无法转换为我外部引入的JSONArray,那怎么解决了?

5.4 第一个方法

将JsonArray转换为String存储,就不存在转换问题

	@Cacheable(value = "playList",key = "#id")
    @RequestMapping("/music/getPlayList")
    public String getLikePlayList(String id){
       	....
        return returnJsonArray.toString();
    }
5.5第二个方法
	@Cacheable(value = "playList",key = "#id")
    @RequestMapping("/music/getPlayList")
    public Object getLikePlayList(String id){
       	....
        return returnJsonArray;
    }

存储在Redis中的是Json数组,从缓冲中拿出的时候转换为Object,直接返回

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐