題目:
模擬一個微博的熱搜
表: 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 層和之前同樣 寫