题目:
模拟一个微博的热搜
表: tb_news id title
Redis: zsetcss
例:
1.建立一个实体类 NewsEntityhtml
package com.lanou3g.redisdemo.entity; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; import java.io.Serializable; /** * 建立人: 武奇 * 建立事件: 2019/6/26 */ @Data @NoArgsConstructor @AllArgsConstructor @Builder @Entity @Table(name = "tb_news") public class NewsEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; @Transient private Double score; }
2 建立. NewsRepository 接口继承JpaRepository 接口(继承后可根据方法名自动生成sql语句)前端
package com.lanou3g.redisdemo.repository; import com.lanou3g.redisdemo.entity.NewsEntity; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; /** * 建立人: 武奇 * 建立事件: 2019/6/26 */ public interface NewsRepository extends JpaRepository<NewsEntity, Long> { List<NewsEntity> findByIdIn(List<Long> idList); }
3.编写前端导入JQ 向后台发送请求java
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> <title>新闻列表</title> </head> <body> <div id="news-list"></div> <script> $.get("/news/list", function (items) { const newsList = $("#news-list"); for (const item of items) { //列出从数据库中查出的数据 const a = $("<a></a>").text(item.title); //点击查出的数据获取id 去redis中查出谁的点击量最高 a.click(function () { const data = {id: item.id}; $.post("/news/like", data, function (resp) { console.log("点同意功") }) }); //把每条数据放入div中 在放入br标签使每条数据都换行 newsList.append(a); newsList.append($("<br>")) } }) </script> </body> </html>
4.建立controller 层接收前端发送过来的请求jquery
@RestController @RequestMapping("/news") public class NewsController { // 引入NewsService 接口 @Resource private NewsService newsService; // 查询全部 @RequestMapping("/list") public List<NewsEntity> list() { return this.newsService.findAll(); } // 增长点击数量 (Id 的添加) @RequestMapping("/like") public Map<String, Object> like(Long id) { this.newsService.likeId(id); return Collections.singletonMap("message", "OK"); } // 向前端返回集合(id 的返回) @RequestMapping("/sort") public Collection<?> sort() { return this.newsService.getWithScoresId(); }
建立 newservice 接口 (接口中写了两种添加 到 redis方式)redis
public interface NewsService { // 查新全部新闻 List<NewsEntity> findAll(); // 添加点击数量(对象作法) void like(Long id); // 返回点击数量(对象作法) Set<?> getWithScores(); // 添加点击数量(id 作法) void likeId(Long id); // 返回点击数量(id 作法) Collection<?> getWithScoresId();
建立 NewsService 接口的实现类spring
@Service("newsService") public class NewsServiceImpl implements NewsService { // 引入NewsRepository接口 @Resource private NewsRepository newsRepository; // 引入springframework.data.redis.core 包下的 实体类 RedisTemplate @Resource private RedisTemplate<String, Object> redisTemplate; // 查出全部 @Override public List<NewsEntity> findAll() { return this.newsRepository.findAll(); } // 在redis中存入对象 @Override public void like(Long id) { ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet(); // 使用id查询全部 Optional<NewsEntity> optional = this.newsRepository.findById(id); // 若是optional有值存在 if (optional.isPresent()) { // 取出查出NewsEntity 点击增长多少 NewsEntity news = optional.get(); // 添加到redis 中 1,名字 2,对象 3每次 opsZ.incrementScore("news:like", news, 1); } } // 返回 按照scores排序好的数据 @Override public Set<?> getWithScores() { ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet(); // 取出redis 中的按照scores排序好的数据 1,取出数据的名字 2,从0 开始 3,到第10 个结束 Set<ZSetOperations.TypedTuple<Object>> set = opsZ.reverseRangeWithScores("news:like", 0, 10); return set; } // 在redis中存入id @Override public void likeId(Long id) { ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet(); opsZ.incrementScore("news:like:id", id, 1); } // 从redis中取出 存入的id 与Scores @Override public Collection<?> getWithScoresId() { ZSetOperations<String, Object> opsZ = this.redisTemplate.opsForZSet(); // 取出存入id的集合 Set<ZSetOperations.TypedTuple<Object>> tuple = opsZ.reverseRangeWithScores("news:like:id", 0, 10); // 这个tuple里保存的关键信息是每一个新闻的分数和新闻的id的顺序. List<NewsEntity> items = new ArrayList<>(); for (ZSetOperations.TypedTuple<Object> item : tuple) { Long id = Long.parseLong(String.valueOf(item.getValue())); // 使用id查询 查询这条新闻的全部信息 Optional<NewsEntity> optional = this.newsRepository.findById(id); // 若是返回的对象不为空 if (optional.isPresent()) { NewsEntity news = optional.get(); // 把分数加入对象 news.setScore(item.getScore()); // 添加进list items.add(news); } } return items; }
建立 RedisConfig 配置 存储 redis 时 存入对象的配置sql
package com.lanou3g.redisdemo.config; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.core.ValueOperations; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import javax.annotation.PostConstruct; import javax.annotation.Resource; /** * 建立人: 武奇 * 建立事件: 2019/6/25 */ @Configuration public class RedisConfig { // 配置key的序列化 @Bean public RedisSerializer keySerializer() { return new StringRedisSerializer(); } // 配置value的序列化 @Bean public RedisSerializer valueSerializer() { // 当向Redis中存储一个对象时候, // 会把对象转换为json数据存储到Redis中 return new GenericJackson2JsonRedisSerializer(); } // @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(keySerializer()); redisTemplate.setHashKeySerializer(keySerializer()); // 若是不配置JSON的序列化, 还想保存对象, // 那么前提是这个对象是能够被序列化的, 也就是说 // 对应的类必须是实现Serializable接口的 // 若是须要使用JSON的序列化, 被保存的对象, // 必须得有默认的构造方法, 不然对象能被存上, 可是读不出来 redisTemplate.setValueSerializer(valueSerializer()); redisTemplate.setHashValueSerializer(valueSerializer()); return redisTemplate; } /* <bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/> <bean id="redisTemplate" class="com.xxx.RedisTemplate"> <property key="connectionFactory" ref="redisConnectionFactory"/> <property key="keySerializer" ref="keySerializer" /> <property key="hashKeySerializer" ref="keySerializer" /> </bean> */ }
这样 模拟的微博热搜 就写完了数据库
Redis缓存json
须要在 application.yml 里配置(其实能够不配置,只要导包时 有导入redis 包 那么他会自动匹配能够不写)
#如果已经导入redis框架 能够不写 (下面一段)它默认就是redis redis: host: localhost port: 6379 #选择缓存器是 谁的缓存(可不写 加入redis框架后默认是redis #如不加redis框架也能够用缓存,会默认用simple cache: type: redis
在SpringBoot 项目开始建立时,自动建立的实体类中写 开始缓存的注解
package com.lanou3g.redisdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication //启用缓存 @EnableCaching public class RedisDemoApplication { public static void main(String[] args) { SpringApplication.run(RedisDemoApplication.class, args); } }
在cotroller 层 中 作缓存
// @Cacheable 该方法支持缓存 cacheNames缓存的名字 @Cacheable(cacheNames = "cache:news") // 在建立工程最初的被建立的实体类中开启缓存加上 @EnableCaching 注解 @RequestMapping("/{id}") public NewsEntity getOne(@PathVariable Long id) { return this.newsService.findById(id); } // 再缓存中真正的key 是由两部分组成的: // 第一部分是缓存的名字,也cacheNames就是相应的值 // 第二部分是缓存的key, 也就是key的属性 //在作数据更新的时候须要缓存进行同步 // @CacheEvict删掉某个缓存 @CacheEvict(cacheNames = "cache:news",key = "#news.id") @RequestMapping("/update") public NewsEntity update(NewsEntity news) { return this.newsService.update(news); } // 添加数据 // @CachePut 直接更新缓存 // key的参数是 返回值的id @CachePut(cacheNames = "cache:news",key = "#result.id") @RequestMapping("/save") public NewsEntity save(NewsEntity news){ return NewsEntity.builder() .id(10001L) .build(); }
只要加上注解 redis 就会开始缓存
@Cacheable 该方法支持缓存
@CachePut 直接更新缓存
@CacheEvict删掉某个缓存
缓存相关的注解,不必定非写在controller层
写在service或Dao层均可以
根据实际需求灵活使用
service 层和之前同样 写