實現流程 1. 實現緩存文章 1.1 實體類 package com.intehel.demo.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import ...
實現流程
1. 實現緩存文章
1.1 實體類
package com.intehel.demo.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Article implements Serializable {
private Integer id;
private Integer num;
}
1.2 資料庫持久層
package com.intehel.demo.mapper;
import com.intehel.demo.domain.Article;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface ArticleMapper {
Article findArticleById(Long id);
Long updateArticle(@Param("lviews") Long lviews, @Param("lid") Long lid);
}
1.3 mybatis映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.intehel.demo.mapper.ArticleMapper" >
<resultMap id="BaseResultMap" type="com.intehel.demo.domain.Article" >
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="num" property="num" jdbcType="BIGINT"/>
</resultMap>
<!--根據參數名稱查詢參數配置表-->
<select id="findArticleById" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select * from article where id = #{id}
</select>
<!--根據主鍵,不存在就新增,已存在就修改-->
<update id="updateArticle" parameterType="java.lang.Long">
update article set num = #{lviews} where id = #{lid}
</update>
</mapper>
1.4 實現服務層的緩存設置
package com.intehel.demo.service;
import com.intehel.demo.domain.Article;
import com.intehel.demo.mapper.ArticleMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
@CacheConfig(cacheNames = "articleService")
public class ArticleService {
@Autowired
private ArticleMapper articleMapper;
@Cacheable(key = "#id")
public Article findArticleById(Long id) {
return articleMapper.findArticleById(id);
}
@CachePut(key = "#lid")
public Article updateArticle(@Param("lviews") Long lviews, @Param("lid") Long lid) {
articleMapper.updateArticle(lviews,lid);
return articleMapper.findArticleById(lid);
}
}
1.5 配置redis
package com.intehel.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.*;
import java.lang.reflect.Method;
import java.time.Duration;
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
//在緩存對象集合中,緩存是以key-value形式保存的
//如果沒有指定緩存的key,則Spring Boot 會使用SimpleKeyGenerator生成key
@Override
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
//定義緩存key的生成策略
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();
}
};
}
@SuppressWarnings("rawtypes")
@Bean
//緩存管理器 2.X版本
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisSerializer<String> strSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jacksonSeial =
new Jackson2JsonRedisSerializer(Object.class);
// 解決查詢緩存轉換異常的問題
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 定製緩存數據序列化方式及時效
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(strSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(jacksonSeial))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager
.builder(connectionFactory).cacheDefaults(config).build();
return cacheManager;
}
//緩存管理器 1.X版本
/* public CacheManager cacheManager(@SuppressWarnings("rawtypes")RedisTemplate redisTemplate){
return new RedisCacheManager(redisTemplate);
}*/
@Bean
//註冊成Bean被Spring管理,如果沒有這個Bean,則Redis可視化工具中的中文內容都會以二進位存儲,不易檢查
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 創建JSON格式序列化對象,對緩存數據的key和value進行轉換
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// 解決查詢緩存轉換異常的問題
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//設置redisTemplate模板API的序列化方式為json
template.setDefaultSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory){
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
private RedisSerializer<?> keySerializer() {
return new StringRedisSerializer();
}
// 值使用jackson進行序列化
private RedisSerializer<?> valueSerializer() {
return new GenericJackson2JsonRedisSerializer();
// return new JdkSerializationRedisSerializer();
}
}
2. 實現統計點擊量
package com.intehel.demo.controller;
import com.intehel.demo.domain.Article;
import com.intehel.demo.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@RequestMapping("/{id}")
public Article testPathVariable(@PathVariable("id") Integer id){
Article article = articleService.findArticleById(Long.valueOf(id));
System.out.println(article);
if (article.getNum()>0){
if (redisTemplate.opsForValue().get("num::"+id)!=null){
redisTemplate.opsForValue().increment("num::"+id, 1);
}else {
redisTemplate.boundValueOps("num::"+id).increment(article.getNum()+1);
}
}else {
redisTemplate.boundValueOps("num::"+id).increment(1);
}
return article;
}
}
3.實現定時同步
package com.intehel.demo.config;
import com.intehel.demo.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Component
public class CountScheduledTasks {
@Autowired
private ArticleService articleService;
@Resource
private RedisTemplate<String,Object> redisTemplate;
@Scheduled(cron = "0/10 * * * * ?" )
public void syncPostViews(){
Long StartTime = System.nanoTime();
List dtolist = new ArrayList();
Set<String> keySet = redisTemplate.keys("num::*");
System.out.println(keySet);
for (String key : keySet) {
String view = redisTemplate.opsForValue().get(key).toString();
String sid = key.replaceAll("num::", "");
Long lid = Long.valueOf(sid);
Long lviews = Long.valueOf(view);
articleService.updateArticle(lviews,lid);
redisTemplate.delete(key);
}
}
}
同時要在啟動類中添加註解,開啟redis緩存和定時任務:
@SpringBootApplication
@EnableCaching
@EnableScheduling
@MapperScan("com.intehel.demo")