用redis和jpa實現緩存文章和點擊量-SpringBoot(23)

来源:https://www.cnblogs.com/liwenruo/archive/2022/08/13/16581811.html
-Advertisement-
Play Games

實現流程 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")

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • @(文章目錄) 提示:本文僅供學習交流,請勿用於非法活動! 前言 本文內容: 日誌搭建 一、依賴 <!-- Spring集成日誌包 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</arti ...
  • 一、基本 1.hashmap: 1.1 轉紅黑樹條件: a.數組長度大於等於64(預設16,要經過2次擴容--當達到16*預設擴容因數0.75=12就擴容) b.鏈表長度大於8 1.2 hashmap先計算hash值,再用hash值計算下標。 2.sleep與await: 1.1 sleep是線程方 ...
  • @(文章目錄) 前言 一、建項目 1. 在父項目ams-cloud下建立maven子項目ams-websocket 2.pom文件添加常用依賴,另外添加redis依賴等,我這裡直接引用common模塊 <dependencies> <dependency> <groupId>com.alibaba. ...
  • 準備工作 概述:微信掃碼支付是商戶系統按微信支付協議生成支付二維碼,用戶再用微信掃一掃完成支付的模式。該模式適用於PC網站支付、實體店單品或訂單支付、媒體廣告支付等場景。 第一步:註冊公眾號(類型須為:服務號):請根據營業執照類型選擇以下主體註冊:個體工商戶| 企業/公司| 政府| 媒體| 其他類型 ...
  • python的面向對象 面向對象與面向過程 面向過程 面向過程思想:需要實現一個功能的時候,看重的是開發的步驟和過程,每一個步驟都需要自己親力親為,需要自己編寫代碼(自己來做) 面向對象 面向對象的三大特征:封裝性、繼承性、多態性 面向對象思想:需要實現一個功能的時候,看重的並不是過程和步驟,而是關 ...
  • “Java有幾種文件拷貝方式,哪一種效率最高?” 這個問題是京東一面的時候,針對4年經驗的同學的一個面試題。 大家好,我是Mic,一個工作了14年的Java程式員。 關於這個問題的回答,我把文字版本整理到了15W字的面試文檔裡面。 大家可以在我的主頁加V領取。 下麵看看高手的回答。 高手: 第一種, ...
  • 首先確保全裝好WSL2和DockerDesktop,本文章不討論這個。 在DockerDesktop的Setting->Resources->Proxy 設置好代理,這樣能夠加快鏡像的拉取速度。 http://127.0.0.1:xxxx https://127.0.0.1:xxxx 使用如下命令安 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...