springboot和redis处理页面缓存

页面缓存是应对高并发的一个比较常见的方案,当请求页面的时候,会先查询redis缓存中是否存在,若存在则直接从缓存中返回页面,否则会通过代码逻辑去渲染页面,并将渲染后的页面缓存到redis中,然后返回。下面通过简单的demo来描述这一过程:

 一、准备工作:

1、新建一个springboot工程,命名为novel,添加如下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dtouding</groupId>
    <artifactId>novel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>novel</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--mysql connector-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>

        <!--jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml

2、创建一个novel表,并插入几条数据,如下:

DROP TABLE IF EXISTS `t_novel`;
CREATE TABLE `t_novel` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘小说ID‘,
  `novel_name` varchar(16) DEFAULT NULL COMMENT ‘小说名称‘,
  `novel_category` varchar(64) DEFAULT NULL COMMENT ‘小说类别‘,
  `novel_img` varchar(64) DEFAULT NULL COMMENT ‘小说图片‘,
  `novel_summary` longtext COMMENT ‘小说简介‘,
  `novel_author` varchar(16) DEFAULT NULL COMMENT ‘小说作者‘,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
INSERT INTO `t_novel` VALUES (‘5‘, ‘诛仙‘, ‘仙侠‘, ‘/img/zhuxian.jpg‘, ‘该小说以“天地不仁,以万物为刍狗”为主题,讲述了青云山下的普通少年张小凡的成长经历以及与两位奇女子凄美的爱情故事,整部小说构思巧妙、气势恢宏,开启了一个独具魅力的东方仙侠传奇架空世界,情节跌宕起伏,人物性格鲜明,将爱情、亲情、友情与波澜壮阔的正邪搏斗、命运交战汇集在一起,文笔优美,故事生动。它与小说《飘邈之旅》、《小兵传奇》并称为“网络三大奇书”,又被称为“后金庸时代的武侠圣经”。‘, ‘萧鼎‘);
INSERT INTO `t_novel` VALUES (‘6‘, ‘英雄志‘, ‘武侠‘, ‘/img/yingxiongzhi.jpg‘, ‘《英雄志》为一虚构中国明朝历史的古典小说,借用明英宗土木堡之变为背景,以复辟为舞台,写尽了英雄们与时代间的相互激荡,造反与政变、背叛与殉道……书中无人不可以为英雄,贩夫走卒、市井小民、娼妇与公主、乞丐与皇帝,莫不可以为英雄。孙晓一次又一次建立英雄的面貌,又一次一次拆解英雄的形象。于穷途末路之时的回眸一笑,是孙晓笔下的安慰与沧桑。‘, ‘孙晓‘);

t_novel

3、在application.yml文件中配置数据库连接信息和redis连接信息:

spring:
  ##thymeleaf.#
  thymeleaf:
    ##默认前缀
    prefix: classpath:/templates/
    ##默认后缀
    suffix: .html
    cache: false
    servlet:
      content-type: text/html
    enabled: true
    encoding: UTF-8
    mode: HTML5

  ##datasource.#
  datasource:
    url: jdbc:mysql://localhost:3306/novel?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    tomcat:
      max-active: 2
      max-wait: 60000
      initial-size: 1
      min-idle: 1
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: select ‘dtouding‘
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false

##mybatis.#
mybatis:
  type-aliases-package: com.dtouding.novel.domain
  configuration:
    map-underscore-to-camel-case: true
    default-fetch-size: 100
    default-statement-timeout: 30
  mapper-locations: classpath:com/dtouding/novel/dao/*.xml

redis:
  host: 127.0.0.1
  port: 6379
  timeout: 3
  password: 123456
  poolMaxTotal: 10
  poolMaxIdle: 10
  poolMaxWait: 3

application.yml

4、做一个简单的查询小说列表的功能,编写dao、service、controller、html:

public class Novel {

    private Long id;

    private String novelName;

    private String novelCategory;

    private String novelImg;

    private String novelSummary;

    private String novelAuthor;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNovelName() {
        return novelName;
    }

    public void setNovelName(String novelName) {
        this.novelName = novelName;
    }

    public String getNovelCategory() {
        return novelCategory;
    }

    public void setNovelCategory(String novelCategory) {
        this.novelCategory = novelCategory;
    }

    public String getNovelImg() {
        return novelImg;
    }

    public void setNovelImg(String novelImg) {
        this.novelImg = novelImg;
    }

    public String getNovelSummary() {
        return novelSummary;
    }

    public void setNovelSummary(String novelSummary) {
        this.novelSummary = novelSummary;
    }

    public String getNovelAuthor() {
        return novelAuthor;
    }

    public void setNovelAuthor(String novelAuthor) {
        this.novelAuthor = novelAuthor;
    }
}

Novel

@Mapper
public interface NovelDao {

    @Select("select * from t_novel")
    List<Novel> list();

}

NovelDao

@Service
public class NovelService {

    @Resource
    private NovelDao novelDao;

    public List<Novel> list() {
        return novelDao.list();
    }
}

NovelService

@Controller
@RequestMapping(value = "/novel")
public class NovelController {

    @Autowired
    private NovelService novelService;

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public String list(Model model) {
        List<Novel> list = novelService.list();
        model.addAttribute("novelList", list);
        return "novel_list";
    }
}

NovelController

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>小说列表</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" />
    <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
</head>
<body>

<div class="panel panel-default">
    <div class="panel-heading">小说列表</div>
    <table class="table" id="goodslist">
        <tr><td>小说名称</td><td>小说图片</td><td>小说类别</td><td>小说作者</td><td>小说简介</td>
        <tr  th:each="novel : ${novelList}">
            <td th:text="${novel.novelName}"></td>
            <td ><img th:src="@{${novel.novelImg}}" width="100" height="100" /></td>
            <td th:text="${novel.novelCategory}"></td>
            <td th:text="${novel.novelAuthor}"></td>
            <td th:text="${novel.novelSummary}"></td>
        </tr>
    </table>
</div>
</body>
</html>

novel_list

5、通过http://localhost:8080/novel/list,可访问。

二、缓存novel_list页面

1、引入redis依赖:

<dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
</dependency>

2、编写redis配置类和通用的redis工具类:

@Component
@ConfigurationProperties(prefix = "redis")
public class RedisConfig {

    private String host;
    private int port;
    private int timeout;//秒
    private String password;
    private int poolMaxTotal;
    private int poolMaxIdle;
    private int poolMaxWait;//秒

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getPoolMaxTotal() {
        return poolMaxTotal;
    }

    public void setPoolMaxTotal(int poolMaxTotal) {
        this.poolMaxTotal = poolMaxTotal;
    }

    public int getPoolMaxIdle() {
        return poolMaxIdle;
    }

    public void setPoolMaxIdle(int poolMaxIdle) {
        this.poolMaxIdle = poolMaxIdle;
    }

    public int getPoolMaxWait() {
        return poolMaxWait;
    }

    public void setPoolMaxWait(int poolMaxWait) {
        this.poolMaxWait = poolMaxWait;
    }

    @Bean
    public JedisPool jedisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(poolMaxIdle);
        jedisPoolConfig.setMaxTotal(poolMaxTotal);
        jedisPoolConfig.setMaxWaitMillis(poolMaxWait * 1000);
        JedisPool jedisPool = new JedisPool(jedisPoolConfig,
                host,
                port,
                timeout * 1000,
                password);
        return jedisPool;
    }
}

RedisConfig

@Service
public class RedisService {

    @Autowired
    private JedisPool jedisPool;

    /**
     * 获取存储对象
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T get(String key, Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = jedis.get(key);
            T t = stringToBean(str, clazz);
            return t;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 设置对象
     * @param key
     * @param expireSeconds
     * @param value
     * @param <T>
     * @return
     */
    public <T> boolean set(String key, int expireSeconds, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = beanToString(value);
            if (null == str) {
                return false;
            }
            if (expireSeconds <= 0) {
                jedis.set(key, str);
            } else {
                jedis.setex(key, expireSeconds, str);
            }
            return true;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 判断key是否存在
     * */
    public <T> boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            return  jedis.exists(key);
        }finally {
            returnToPool(jedis);
        }
    }

    /**
     * 增加值
     * */
    public <T> Long incr(String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            return  jedis.incr(key);
        }finally {
            returnToPool(jedis);
        }
    }

    /**
     * 减少值
     * */
    public <T> Long decr(String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            return  jedis.decr(key);
        }finally {
            returnToPool(jedis);
        }
    }

    private <T> String beanToString(T value) {
        if (null == value) {
            return null;
        }
        if (value instanceof Integer || value instanceof Long) {
            return "" + value;
        } else if (value instanceof String) {
            return (String) value;
        } else {
            return JSON.toJSONString(value);
        }
    }

    private <T> T stringToBean(String str, Class<T> clazz) {
        if (StringUtils.isEmpty(str) || clazz==null) {
            return null;
        }
        if (clazz==int.class || clazz==Integer.class) {
            return (T) Integer.valueOf(str);
        } else if (clazz == String.class) {
            return (T) str;
        } else if (clazz==long.class || clazz==Long.class) {
            return (T)Long.valueOf(str);
        } else {
            return JSON.toJavaObject(JSON.parseObject(str), clazz);
        }
    }

    private void returnToPool(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }
}

RedisService

3、改写NovelController中的list方法,添加页面缓存逻辑,具体包括:

1)、在list方法上添加@ResponseBody注解,并修改返回类型为text/html,可以避免返回的html再次被渲染,因为缓存在redis中的页面是通过代码手工渲染的。

2)、判断redis中是否有novel_list的页面缓存,若有,则直接返回该缓存页面:

String html = redisService.get(NovelRedisKeys.NOVEL_LIST_PAGE, String.class);if (!StringUtils.isEmpty(html)) {    return html;}

3、若缓存中没有,则借助ThymeleafViewResolver去渲染html页面:

html = thymeleafViewResolver.getTemplateEngine().process("novel_list", webContext);

4、将渲染后的页面缓存到redis中:

if (!StringUtils.isEmpty(html)) {
            //将渲染后的页面缓存到redis中
            redisService.set(NovelRedisKeys.NOVEL_LIST_PAGE, 60, html);
      }

4、修改后的完整代码如下:

@Controller@RequestMapping(value = "/novel")public class NovelController {

@Autowired    private NovelService novelService;

@Autowired    private RedisService redisService;

@Autowired    private ThymeleafViewResolver thymeleafViewResolver;

@RequestMapping(value = "/list", method = RequestMethod.GET)    @ResponseBody    public String list(HttpServletRequest request, HttpServletResponse response, Model model) {        //判断redis是否有缓存        String html = redisService.get(NovelRedisKeys.NOVEL_LIST_PAGE, String.class);        if (!StringUtils.isEmpty(html)) {            return html;        }        List<Novel> list = novelService.list();        model.addAttribute("novelList", list);        WebContext webContext = new WebContext(request,                response,                request.getServletContext(),                request.getLocale(),                model.asMap());        //渲染页面        html = thymeleafViewResolver.getTemplateEngine().process("novel_list", webContext);        if (!StringUtils.isEmpty(html)) {            //将渲染后的页面缓存到redis中            redisService.set(NovelRedisKeys.NOVEL_LIST_PAGE, 60, html);        }        return html;    }}

原文地址:https://www.cnblogs.com/gujianzhe/p/10229210.html

时间: 2024-11-05 21:50:29

springboot和redis处理页面缓存的相关文章

Magento2使用Redis进行页面缓存或会话存储。

1.Redis是一个可选的后端缓存解决方案,不过magento2默认使用的是Zend_Cache_Backend_File 2.Zend_Cache_Backend_File的问题 core_cache_tag表不断增长. 如果Magento实例具有多个网站和具有大型目录的网络商店,则该表可在不到一天内增长到1500万条记录. 插入到core_cache_tag会导致MySQL服务器的问题,包括性能降低. 3.为什么使用Redis Redis也可以用于PHP会话存储,使得可以使用Redis完全替

SpringBoot集成Redis来实现缓存技术方案

概述 在我们的日常项目开发过程中缓存是无处不在的,因为它可以极大的提高系统的访问速度,关于缓存的框架也种类繁多,今天主要介绍的是使用现在非常流行的NoSQL数据库(Redis)来实现我们的缓存需求. Redis简介 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件,Redis 的优势包括它的速度.支持丰富的数据类型.操作原子性,以及它的通用性. 案例整合 本案例是在之前一篇SpringBoot + Mybatis + RESTful的基础上来集

springboot+mybatis+redis实现分布式缓存

大家都知道springboot项目都是微服务部署,A服务和B服务分开部署,那么它们如何更新或者获取共有模块的缓存数据,或者给A服务做分布式集群负载,如何确保A服务的所有集群都能同步公共模块的缓存数据,这些都涉及到分布式系统缓存的实现. 前面其实我已经介绍了springboot+mybatis+ehcache实现缓存数据,但是ehcache的设计并不适合做分布式缓存,所以今天用redis来实现分布式缓存. 原理什么的,我就不多说了,直接上代码. pom依赖 <dependency> <gr

SpringBoot+Mybatis+redis实现二级缓存

对于查询比较多的项目可以考虑配置二级缓存,mybatis本身的二级缓存是缓存到本地,但是对于多个节点的项目来说,可能会出现数据不一致的问题,所以采用redis缓存,这样二级缓存的数据就可以缓存到内存,可实现多个节点项目的数据同步. 1.配置redis的连接 #redis gmall.redis.host=172.16.1.250 gmall.redis.port=6379 gmall.redis.pass=Gworld2017 gmall.redis.photo.database=6 #最大分配

spring-boot 整合redis作为数据缓存

添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> Redis配置 package com.wisely.ij.config; import com.fasterxml.jackson.annotation.JsonAutoDetect

SpringBoot集成Redis分布式锁以及Redis缓存

https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 <!-- 引入redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifa

SpringBoot 整合 Redis缓存

在我们的日常项目开发过程中缓存是无处不在的,因为它可以极大的提高系统的访问速度,关于缓存的框架也种类繁多,今天主要介绍的是使用现在非常流行的NoSQL数据库(Redis)来实现我们的缓存需求. SpringBoot整合Redis是非常方便快捷的,我用的是Mybatis,这里就不说Springboot整合Mybatis了网上有很多,同样非常简单. 下面进入正题: 原文地址:https://www.cnblogs.com/yueguanguanyun/p/9756058.html

springboot整合redis缓存一些知识点

前言 最近在做智能家居平台,考虑到家居的控制需要快速的响应于是打算使用redis缓存.一方面减少数据库压力另一方面又能提高响应速度.项目中使用的技术栈基本上都是大家熟悉的springboot全家桶,在springboot2.x以后操作redis的客户端推荐使用lettuce(生菜)取代jedis. jedis的劣势主要在于直连redis,又无法做到弹性收缩. 一.配置文件 application.yml文件中的内容 spring: application: name: simple-lettuc

Spring Boot使用redis实现数据缓存

基于Spring Boot 1.5.2.RELEASE版本,一方面验证与Redis的集成方法,另外了解使用方法. 集成方法 配置依赖 修改pom.xml,增加如下内容. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 配置Redis