day14_用户前台项目环境搭建(首页接口开发,分类接口开发,网关服务搭建,Redis缓存,Spring Cache)

文章目录

  • 1 尚品甄选H5介绍
    • 1.1 业务功能介绍
    • 1.2 系统架构
    • 1.3 前端H5开发说明
  • 2 搭建项目环境
    • 2.1 项目结构说明
    • 2.2 模块依赖说明
    • 2.3 环境说明
    • 2.4 项目模块创建
      • 2.4.1 spzx-parent
      • 2.4.2 spzx-service
      • 2.4.43 service-product
    • 2.5 导入接口文档
  • 3 首页接口开发
    • 3.1 需求分析
    • 3.3 接口开发
      • 3.3.1 IndexVo
      • 3.3.2 IndexController
      • 3.3.3 商品一级分类接口
        • CategoryService
        • CategoryMapper
        • CategoryMapper.xml
      • 3.3.4 畅销商品列表接口
        • ProductService
        • ProductSkuMapper
        • ProductSkuMapper.xml
      • 3.3.5 Knife4j调试接口
        • 配置前端H5接口
        • Knife4j调试首页接口
        • H5对接本地接口
      • 3.3.6 接口测试
  • 4 分类接口开发
    • 4.1 需求分析
    • 4.2 接口开发
      • 4.2.1 CategoryController
      • 4.2.2 CategoryService
      • 4.2.3 CategoryMapper
      • 4.2.4 CategoryMapper.xml
      • 4.2.5 接口测试
  • 5 网关服务搭建
    • 5.1 网关服务说明
    • 5.2 服务网关搭建
    • 5.3 服务网关测试
  • 6 Redis缓存
    • 6.1 使用缓存
    • 6.2 Spring Cache
      • 6.2.1 介绍
      • 6.2.2 注解
      • 6.2.3 入门程序
      • 6.2.4 其他注解
        • @CachePut
        • @CacheEvict
    • 6.3 缓存所有分类数据

1 尚品甄选H5介绍

本章讲解尚品甄选H5端介绍。

1.1 业务功能介绍

首页、商品分类查询、关键字查询、商品详情、注册、登录、购物车模块、用户收货地址管理、订单模块、支付…

项目演示地址:http://spzx.atguigu.cn/

1.2 系统架构

服务器端架构:SpringBoot3 + Spring Cloud + Spring Cloud Alibaba(Nacos/Sentinel) + MyBatis + Redis + Mysql

前端架构:Uni-App

1.3 前端H5开发说明

前端H5部分我们不需要开发,我们只需要根据接口文档开发微服务接口,然后对接到写好的前端H5即可

导入课程资料:spzx-h5

部署spzx-h5:

1、docker部署nignx

#拉取镜像
docker pull nginx:latest#运行nginx镜像
docker run -d -p 80:80 \
--name nginx-spzx \
-v nginx_html:/usr/share/nginx/html \
-v nginx_conf:/etc/nginx/ \
-v nginx_logs:/var/log/nginx  nginx# nginx-spzx容器的管理命令
docker start nginx-spzx			# 启动容器
docker stop nginx-spzx			# 关闭容器
docker rm nginx-spzx			# 删除容器#使用浏览器访问测试:http://ip

2、部署spzx-h5

删除/var/lib/docker/volumes/nginx_html/_data目录下的文件,将spzx-h5目录下的文件上传到该目录下。

view /var/lib/docker/volumes/nginx-conf/_data/nginx.conf
[root@localhost ~]# view /var/lib/docker/volumes/nginx-conf/_data/nginx.confevents {worker_connections  1024;
}http {include       /etc/nginx/mime.types;default_type  application/octet-stream;log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  /var/log/nginx/access.log  main;sendfile        on;#tcp_nopush     on;keepalive_timeout  65;#gzip  on;include /etc/nginx/conf.d/*.conf;server{listen 80;server_name www.spzx.com;location / {root /usr/share/nginx/html;index index.html index.html;}}}

在这里插入图片描述

C:\Windows\System32\drivers\etc

浏览器访问:http://ip,打开手机模式

在这里插入图片描述

3、H5调用本地接口设置

我的 => 设置 =》 接口base路径,改为本地网关地址:http://IP:端口

注意:http://139.198.163.91:8400为云服务接口地址

在这里插入图片描述

2 搭建项目环境

本章讲解在spzx-parent基础上搭建尚品甄选H5端微服务开发环境。

2.1 项目结构说明

尚品甄选H5端微服务项目结构如下所示:

在这里插入图片描述

模块说明:

spzx-parent: 尚品甄选项目的父工程,进行项目依赖的统一管理,打包方式为pom

​ spzx-common: 尚品甄选项目公共模块的管理模块

​ common-util: 工具类模块

​ common-service:公共服务模块

​ spzx-model: 尚品甄选项目实体类模块

​ spzx-manager: 尚品甄选项目后台管理系统的后端服务(忽略、前面已讲)

​ spzx-server-gateway: 尚品甄选项目的网关

​ spzx-service: 尚品甄选微服务模块的父工程

​ service-product:商品微服务模块

​ service-user:用户微服务模块

​ service-order:订单微服务模块

​ spzx-service-client: 尚品甄选微服务模块远程调用接口的父工程

​ service-product-client:商品微服务远程调用接口模块

​ service-user-client:用户微服务远程调用接口模块

2.2 模块依赖说明

模块之间的依赖关系如下图所示:

在这里插入图片描述

对应说明:

1、common-service依赖common-util、spzx-mode

2、spzx-service依赖common-service、service-product-client、service-user-client

3、spzx-server-gateway依赖common-util、spzx-mode

2.3 环境说明

本次项目开发的时候所使用的软件环境版本如下所示:

软件名称版本说明
jdkjdk17
spring boot3.0.5
spring cloud2022.0.2
spring cloud alibaba2022.0.0.0-RC2
redis7.0.10
mybaits-spring-boot-starter3.0.1
mysql8.0.29
idea2022.2.2
nacos server2.2.1
sentinel dashboard2.0.0-alpha-preview

2.4 项目模块创建

2.4.1 spzx-parent

添加微服务依赖:

<properties>...<cloud.version>2022.0.2</cloud.version><alibaba.version>2022.0.0.0-RC2</alibaba.version><alipay.version>4.8.73.ALL</alipay.version>
</properties><!-- 管理依赖,版本锁定 -->
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!--导入支付宝支付sdk--><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>${alipay.version}</version></dependency>...</dependencies>
</dependencyManagement>

2.4.2 spzx-service

在spzx-parent下面创建该子模块,并导入如下依赖:

<dependencies><dependency><groupId>com.atguigu.spzx</groupId><artifactId>common-service</artifactId><version>1.0-SNAPSHOT</version></dependency><!-- mybatis的起步依赖 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!-- mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.3.0</version></dependency><!-- 服务注册 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 流量控制 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency></dependencies>

注意:删除src目录、修改项目packaging类型为pom

2.4.43 service-product

在spzx-service下面创建子模块service-product.在service-product服务的src/resources目录下创建application.yml、application-dev.yml文件,文件的内容如下所示:

application.yml

spring:profiles:active: dev

application-dev.yml

server:port: 8511spring:application:name: service-productcloud:nacos:discovery:server-addr: 192.168.136.142:8848sentinel:transport:dashboard: localhost:8080datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.136.142:3306/db_spzx?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=trueusername: rootpassword: 1234mybatis:config-location: classpath:mybatis-config.xmlmapper-locations: classpath:mapper/*/*.xml

导入课程资料中提供的:logback-spring.xml配置文件,修改输出路径:

<property name="log.path" value="F://logs//service-product//logs" />

启动类创建

package com.atguigu.spzx.product;@SpringBootApplication
public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class, args);}}

2.5 导入接口文档

将课程资料中所提供的接口文档(OpenAPI文件夹下的json文件)导入到Apifox中,具体步骤如下所示:

1、在Apifox中创建项目

2、进入项目 ----> 项目设置 ----> 导入数据 -----> 点击或者拖拽文件到本区域导入

在这里插入图片描述

3、导出完毕以后可以在接口中管理中看到对应的接口信息

在这里插入图片描述

3 首页接口开发

3.1 需求分析

需求说明:在前台系统首页展示商品一级分类数据以及畅销商品列表数据,如下所示:

在这里插入图片描述

需求分析:

商品一级分类:查询category表,获取parent_id="0"的数据列表

畅销商品列表:查询product_sku表,根据sale_num字段排序,取前20条数据列表

整体的访问流程如下所示:

在这里插入图片描述

3.3 接口开发

对比着接口文档进行相关接口的开发。

查看接口文档:

首页接口地址及示例数据

get  /api/product/index
返回结果:
{"code": 200,"message": "成功","data": {"productSkuList": [{"id": 1,"createTime": "2023-05-25 22:21:07","skuCode": "1_0","skuName": "小米 红米Note10 5G手机 颜色:白色 内存:8G","productId": 1,"thumbImg": "http://139.198.127.41:9000/spzx/20230525/665832167-5_u_1 (1).jpg","salePrice": 1999.00,"marketPrice": 2019.00,"costPrice": 1599.00,"stockNum": 99,"saleNum": 1,"skuSpec": "颜色:白色,内存:8G","weight": "1.00","volume": "1.00","status": null,"skuSpecList": null},...],"categoryList": [{"id": 1,"createTime": "2023-05-22 23:30:28","name": "数码办公","imageUrl": "https://lilishop-oss.oss-cn-beijing.aliyuncs.com/230f48f024a343c6be9be72597c2dcd0.png","parentId": 0,"status": 1,"orderNum": 1,"hasChildren": null,"children": null},...]}
}

3.3.1 IndexVo

定义一个实体类来封装要给前端详细的数据,如下所示:

// com.atguigu.spzx.model.vo.h5;
@Data
public class IndexVo {private List<Category> categoryList ;       // 一级分类的类别数据private List<ProductSku> productSkuList ;   // 畅销商品列表数据}

3.3.2 IndexController

操作模块:service-product

表现层代码:

// com.atguigu.spzx.product.controller;@Tag(name = "首页接口管理")
@RestController
@RequestMapping(value="/api/product/index")
@SuppressWarnings({"unchecked", "rawtypes"})
public class IndexController {@Autowiredprivate CategoryService categoryService;@Autowiredprivate ProductService productService;@Operation(summary = "获取首页数据")@GetMappingpublic Result<IndexVo> findData(){List<Category> categoryList = categoryService.findOneCategory();List<ProductSku> productSkuList = productService.findProductSkuBySale();IndexVo indexVo = new IndexVo() ;indexVo.setCategoryList(categoryList);indexVo.setProductSkuList(productSkuList);return Result.build(indexVo , ResultCodeEnum.SUCCESS);}}

3.3.3 商品一级分类接口

CategoryService

业务层代码实现

// 业务接口
public interface CategoryService {List<Category> findOneCategory();}// 接口实现类
@Service
public class CategoryServiceImpl implements CategoryService {@Autowiredprivate CategoryMapper categoryMapper;@Overridepublic List<Category> findOneCategory() {return categoryMapper.findOneCategory();}
}
CategoryMapper

持久层代码实现

@Mapper
public interface CategoryMapper {List<Category> findOneCategory();
}
CategoryMapper.xml

在映射文件中定义对应的sql语句

<?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.atguigu.spzx.product.mapper.CategoryMapper"><resultMap id="categoryMap" type="com.atguigu.spzx.model.entity.product.Category" autoMapping="true"></resultMap><!-- 用于select查询公用抽取的列 --><sql id="columns">id,name,image_url,parent_id,status,order_num,create_time,update_time,is_deleted</sql><select id="findOneCategory" resultMap="categoryMap">select <include refid="columns" />from categorywhereparent_id = 0and status = 1and is_deleted = 0order by order_num</select></mapper>

3.3.4 畅销商品列表接口

ProductService

业务层代码实现

// 业务接口
public interface ProductService {List<ProductSku> findProductSkuBySale();}// 接口实现类
@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate ProductSkuMapper productSkuMapper;@Overridepublic List<ProductSku> findProductSkuBySale() {return productSkuMapper.findProductSkuBySale();}
}
ProductSkuMapper

持久层代码实现

@Mapper
public interface ProductSkuMapper {List<ProductSku> findProductSkuBySale();
}
ProductSkuMapper.xml

在映射文件中定义对应的sql语句

<?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.atguigu.spzx.product.mapper.ProductSkuMapper"><resultMap id="productSkuMap" type="com.atguigu.spzx.model.entity.product.ProductSku" autoMapping="true"></resultMap><!-- 用于select查询公用抽取的列 --><sql id="columns">id,sku_code,sku_name,product_id,thumb_img,sale_price,market_price,cost_price,stock_num,sale_num,sku_spec,weight,volume,status,create_time,update_time,is_deleted</sql><select id="findProductSkuBySale" resultMap="productSkuMap">selectsku.id,sku.sku_code,sku.sku_name,sku.product_id,sku.thumb_img,sku.sale_price,sku.market_price,sku.cost_price,sku.stock_num,sku.sale_num,sku.sku_spec,sku.weight,sku.volume,sku.status,sku.create_time,sku.update_time,sku.is_deletedfrom product_sku skuleft join product p on p.id = sku.product_idwherep.status = 1and p.audit_status = 1and sku.is_deleted = 0and p.is_deleted = 0order by sku.sale_num desclimit 20</select></mapper>

3.3.5 Knife4j调试接口

配置前端H5接口

在common-service模块Knife4jConfig类添加配置信息:

@Bean
public GroupedOpenApi webApi() {      // 创建了一个api接口的分组return GroupedOpenApi.builder().group("web-api")         // 分组名称.pathsToMatch("/api/**")  // 接口请求路径规则.build();
}
Knife4j调试首页接口

在这里插入图片描述

H5对接本地接口

启动nginx,访问:http://ip

我的 => 设置 =》 接口base路径,改为本地网关地址:http://IP:端口

请求

在这里插入图片描述

数据

在这里插入图片描述

3.3.6 接口测试

测试方向:

1、后端接口单独测试

2、配合前端项目测试

后端地址配置:

在这里插入图片描述

解决跨域问题:在IndexController类上添加**@CrossOrigin**注解接口跨域问题

4 分类接口开发

4.1 需求分析

需求说明:当用户点击分类导航按钮的时候,那么此时就需要将系统中所对应的所有的分类数据查询出来,如下所示:

在这里插入图片描述

展示全部商品三级联动的分类数据,查询category数据表

查看接口文档:

分类数据接口地址及示例数据

get  /api/product/category/findCategoryTree
返回结果:
{"code": 200,"message": "成功","data": [{"id": 1,"createTime": "2023-05-22 23:30:28","name": "数码办公","imageUrl": "https://lilishop-oss.oss-cn-beijing.aliyuncs.com/230f48f024a343c6be9be72597c2dcd0.png","parentId": 0,"status": 1,"orderNum": 1,"hasChildren": null,"children": [{"id": 2,"createTime": "2023-05-22 23:30:28","name": "手机通讯","imageUrl": "","parentId": 1,"status": 1,"orderNum": 0,"hasChildren": null,"children": [{"id": 3,"createTime": "2023-05-22 23:30:28","name": "手机","imageUrl": "https://lilishop-oss.oss-cn-beijing.aliyuncs.com/1348576427264204943.png","parentId": 2,"status": 1,"orderNum": 0,"hasChildren": null,"children": null},{"id": 4,"createTime": "2023-05-22 23:30:28","name": "对讲机","imageUrl": "https://lilishop-oss.oss-cn-beijing.aliyuncs.com/1348576427264204944.png","parentId": 2,"status": 1,"orderNum": 0,"hasChildren": null,"children": null},...]},...]},...]
}

4.2 接口开发

操作模块:service-product

4.2.1 CategoryController

表现层代码:

@Tag(name = "分类接口管理")
@RestController
@RequestMapping(value="/api/product/category")
@SuppressWarnings({"unchecked", "rawtypes"})
public class CategoryController {@Autowiredprivate CategoryService categoryService;@Operation(summary = "获取分类树形数据")@GetMapping("findCategoryTree")public Result<List<Category>> findCategoryTree(){List<Category> list = categoryService.findCategoryTree();return Result.build(list,  ResultCodeEnum.SUCCESS);}}

4.2.2 CategoryService

业务层代码实现

// 业务接口
List<Category> findCategoryTree();// 接口实现类
@Override
public List<Category> findCategoryTree() {List<Category> categoryList = categoryMapper.findAll();//全部一级分类List<Category> oneCategoryList = categoryList.stream().filter(item -> item.getParentId().longValue() == 0).collect(Collectors.toList());if(!CollectionUtils.isEmpty(oneCategoryList)) {oneCategoryList.forEach(oneCategory -> {List<Category> twoCategoryList = categoryList.stream().filter(item -> item.getParentId().longValue() == oneCategory.getId().longValue()).collect(Collectors.toList());oneCategory.setChildren(twoCategoryList);if(!CollectionUtils.isEmpty(twoCategoryList)) {twoCategoryList.forEach(twoCategory -> {List<Category> threeCategoryList = categoryList.stream().filter(item -> item.getParentId().longValue() == twoCategory.getId().longValue()).collect(Collectors.toList());twoCategory.setChildren(threeCategoryList);});}});}return oneCategoryList;
}

4.2.3 CategoryMapper

持久层代码实现

List<Category> findAll();

4.2.4 CategoryMapper.xml

在映射文件中定义对应的sql语句

<select id="findAll" resultMap="categoryMap">select <include refid="columns" />from categorywherestatus = 1and is_deleted = 0order by order_num
</select>

4.2.5 接口测试

测试方向:

1、后端接口单独测试

2、配合前端项目测试

5 网关服务搭建

5.1 网关服务说明

后期针对前台系统会创建很多个后端微服务,前端在访问后端微服务的时候需要通过服务网关进行访问,如下图所示:

在这里插入图片描述

5.2 服务网关搭建

步骤:

1、在spzx-parent项目下创建一个spzx-server-gateway模块,并加入依赖

<dependencies><dependency><groupId>com.atguigu.spzx</groupId><artifactId>common-util</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.atguigu.spzx</groupId><artifactId>spzx-model</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!-- loadbalancer依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-loadbalancer</artifactId></dependency><!-- 服务注册 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 服务保护组件 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency></dependencies>

2、在classpath路径下编写两个配置文件:application.yml、application-dev.yml,文件内容分别如下所示:

application.yml文件内容:

spring:profiles:active: dev

application-dev.yml文件内容:

server:port: 8500
spring:application:name: spzx-server-gatewaycloud:nacos:discovery:server-addr: 192.168.136.142:8848sentinel:transport:dashboard: localhost:8080gateway:discovery: #是否与服务发现组件进行结合,通过 serviceId(必须设置成大写) 转发到具体的服务实例。默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。locator: #路由访问方式:http://Gateway_HOST:Gateway_PORT/大写的serviceId/**,其中微服务应用名默认大写访问。enabled: trueglobalcors:cors-configurations:'[/**]':allowedOriginPatterns: "*"# 允许请求中携带的头信息allowedHeaders: "*"# 运行跨域的请求方式allowedMethods: "*"# 跨域检测的有效期,单位smaxAge: 36000routes:- id: service-producturi: lb://service-productpredicates:- Path=/*/product/**

3、编写启动类

// com.atguigu.spzx.gateway;
@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class , args) ;}}

4、导入课程资料中提供的:logback-spring.xml配置文件,修改输出路径:

<property name="log.path" value="D://logs//spzx-server-gateway//logs" />

5.3 服务网关测试

具体步骤:

1、注释掉service-product微服务两个controller上的@CrossOrigin注解

2、后端地址配置

在这里插入图片描述

6 Redis缓存

分类数据一般情况下不会做过多的修改,因此可以将分类数据进行缓存,以提高页面的加载速度。

6.1 使用缓存

先将首页接口获取一级分类数据缓存

步骤:

1、在service-product微服务中集成Spring Data Redis,如下所示:

在service-product的pom.xml文件中添加如下依赖:

<!-- redis的起步依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在application-dev.yml文件中添加如下Redis的相关配置:

spring:# Redis的相关配置data:redis:host: 192.168.136.142port: 6379password: 1234

2、对CategoryServiceImpl的findOneCategory方法进行改造,如下所示:

@Autowired
private RedisTemplate<String , String> redisTemplate ;@Override
public List<Category> findOneCategory() {// 从Redis缓存中查询所有的一级分类数据String categoryListJSON = redisTemplate.opsForValue().get("category:one");if(!StringUtils.isEmpty(categoryListJSON)) {List<Category> categoryList = JSON.parseArray(categoryListJSON, Category.class);log.info("从Redis缓存中查询到了所有的一级分类数据");return categoryList ;}List<Category> categoryList = categoryMapper.findOneCategory();log.info("从数据库中查询到了所有的一级分类数据");redisTemplate.opsForValue().set("category:one" , JSON.toJSONString(categoryList) , 7 , TimeUnit.DAYS);return categoryList ;
}

3、启动程序进行测试:第一次查询从MySQL数据库获取,第二次查询从Redis获取

说明:针对查询所有分类的接口,也可以使用上述思想对分类数据进行缓存。

6.2 Spring Cache

6.2.1 介绍

Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,大大简化我们在业务中操作缓存的代码

Spring Cache只是提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheManager是Spring提供的各种缓存技术抽象接口。

针对不同的缓存技术需要实现不同的CacheManager:

CacheManager描述
EhCacheCacheManager使用EhCache作为缓存技术
GuavaCacheManager使用Google的GuavaCache作为缓存技术
RedisCacheManager使用Redis作为缓存技术

6.2.2 注解

在SpringCache中提供了很多缓存操作的注解,常见的是以下的几个:

注解说明
@EnableCaching开启缓存注解功能
@Cacheable在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
@CachePut将方法的返回值放到缓存中
@CacheEvict将一条或多条数据从缓存中删除

在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类上使用**@EnableCaching**开启缓存支持即可。

例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。

6.2.3 入门程序

接下来,我们将通过一个入门案例来演示一下SpringCache的常见用法。 上面我们提到,SpringCache可以集成不同的缓存技术,如Redis、Ehcache

本次我们直接使用Redis作为缓存技术。

需求:给spring-cache-demo项目中的查询用户方法添加查询缓存逻辑

具体步骤:

1、打开课程资料中所提供的spring-cache-demo项目

2、在spring-cache-demo项目的pom.xml文件中添加如下依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3、在application.yml文件中配置Redis的连接信息

spring:data:redis:host: 192.168.136.142port: 6379password: 1234

4、配置Redis的key的序列化器

// com.atguigu.spzx.cache.config;
@Configuration
public class RedisConfig {@Beanpublic CacheManager cacheManager(LettuceConnectionFactory connectionFactory) {//定义序列化器GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()//过期时间600秒.entryTtl(Duration.ofSeconds(600))// 配置序列化.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(config).build();return cacheManager;}}

5、在启动类上添加**@EnableCaching**注解

6、在UserServiceImpl类中的findById方法上添加**@Cacheable**注解

@Override
@Cacheable(value = "userCache" , key = "#userId")
public User findById(Long userId) {log.info("用户数据查询成功...");User user = new User() ;user.setAge(23);user.setUserName("尚硅谷");return user;
}

7、启动程序进行测试:第一次查询时候会打印日志,第二次查询的时候由于Redis中已经存在了数据,因此直接从Redis中进行命中

@Cacheable 说明:

1、作用: 在方法执行前,spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中

2、value: 缓存的名称,每个缓存名称下面可以有多个key

3、key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法

6.2.4 其他注解

@CachePut

作用: 将方法返回值,放入缓存

value: 缓存的名称, 每个缓存名称下面可以有很多key

key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法

当前UserController的save方法是用来保存用户信息的,我们希望在该用户信息保存到数据库的同时,也往缓存中缓存一份数据,我们可以在save方

法上加上注解 @CachePut,用法如下:

@CachePut(value = "userCache", key = "#user.userName")
public User saveUser(User user) {log.info("用户数据保存成功...");return user ;
}

key的写法如下

#user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ;

#user.userName: #user指的是方法形参的名称, name指的是user的name属性 ,也就是使用user的name属性作为key ;

#result.id : #result代表方法返回值,该表达式 代表以返回对象的id属性作为key ;

#result.userName: #result代表方法返回值,该表达式 代表以返回对象的name属性作为key ;

@CacheEvict

作用: 清理指定缓存

value: 缓存的名称,每个缓存名称下面可以有多个key

key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法

当我们在删除数据库user表的数据的时候,我们需要删除缓存中对应的数据,此时就可以使用**@CacheEvict**注解, 具体的使用方式如下:

@CacheEvict(value = "userCache" , key = "#userId")
public void deleteById(Long userId) {log.info("用户数据删除成功...");
}

6.3 缓存所有分类数据

需求:给查询所有的分类数据添加查询缓存,使用Spring Cache框架

步骤:

1、在service-product服务中的pom.xml文件中添加依赖

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

2、配置Redis的key的序列化器

// com.atguigu.spzx.cache.config;
@Configuration
public class RedisConfig {@Beanpublic CacheManager cacheManager(LettuceConnectionFactory connectionFactory) {//定义序列化器GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()//过期时间600秒.entryTtl(Duration.ofSeconds(600))// 配置序列化.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(config).build();return cacheManager;}}

3、在启动类上添加**@EnableCaching**注解

4、在CategoryServiceImpl类中的findCategoryTree方法上添加**@Cacheable**注解

@Cacheable(value = "category" , key = "'all'")
public List<Category> findAllCategory() {
..return oneCategoryList;
}

5、启动程序进行测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/735334.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

理解JavaScript中的WeakSet和WeakMap

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Yolov8-pose关键点检测:特征融合涨点篇 | 广义高效层聚合网络(GELAN) | YOLOv9

💡💡💡本文独家改进:即结合用梯度路径规划(CSPNet)和(ELAN)设计了一种广义的高效层聚合网络(GELAN),高效结合YOLOv8-pose,实现涨点。 将GELAN添加在backbone和head处,提供多个yaml改进方法 Yolov8-Pose关键点检测专栏介绍:https://blog.csdn.net/m0_6377421…

SSRF服务器请求伪造原理和pikachu靶场实验

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、SSRF简介 SSRF全称&#xff1a;Server-Side Request…

017集——圆弧(ARC)转多段线(lwpolyline)——cad vba 中按一定精度拟合加点实现

在国土资源管理项目中&#xff0c;我们经常会遇到CAD转gis数据实现入库&#xff0c;而cad中的arc圆弧转为gis数据只能转出弧的顶点坐标&#xff0c;导致图形变形失真。若一个一个对弧进行手工增加点转为多段线&#xff0c;耗时耗力&#xff0c;效率极其低下。这里给出解决方案&…

继承杂谈。

内容一览 前言继承的概念及定义继承的意义继承关系及访问限定符父类和子类对象之间的转化继承后的作用域继承与有元继承与静态成员多继承继承和组合的区别&#xff1a;继承的总结和反思 前言 面向对象的三大特性&#xff1a;封装继承和多态&#xff0c;这三种特性优者很紧密地联…

【Prometheus】PromQL

数据类型 即时向量&#xff08;instant vector&#xff09; node_cpu_seconds_total{instance"ahoj-dev-ubuntu-virtualbox",mode"idle"} 区间向量&#xff08;range vector&#xff09; node_cpu_seconds_total{instance"ahoj-dev-ubuntu-virtu…

手拉手RocketMQ基础

消息中间件的对比 消息中间件 ActiveMQ RabbitMQ RocketMQ kafka 开发语言 java erlang java scala 单击吞吐量 万级 万级 10万级 10万级 时效性 ms us ms ms 可用性 高(主从架构) 高(主从架构) 非常高(主从架构) 非常高(主从架构) 消息中间件: activ…

云上攻防-云产品篇堡垒机场景JumpServer绿盟SASTeleport麒麟齐治

知识点 1、云产品-堡垒机-产品介绍&攻击事件 2、云产品-堡垒机-安全漏洞&影响产品 章节点&#xff1a; 云场景攻防&#xff1a;公有云&#xff0c;私有云&#xff0c;混合云&#xff0c;虚拟化集群&#xff0c;云桌面等 云厂商攻防&#xff1a;阿里云&#xff0c;腾讯…

CSS拖曳盒子案例

让我为大家带来一个小案例吧&#xff01; <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>* {margin: 0;padding: 0;}.box1 {width: 100px;height: 100px;background-color: black;margin-bot…

iMazing3 2024详细解析数据备份与恢复备份

iMazing 3的备份功能支持增量备份&#xff08;类似苹果电脑里的Time Machine功能&#xff09;&#xff0c;意思是第一次把移动设备的数据全部备份下来&#xff0c;之后的备份就只针对数据有变化的那部分&#xff0c;这样可以节省大量的时间和存储空间&#xff0c;不会让使用者为…

LeetCode59:螺旋矩阵Ⅱ

题目描述 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]] 代码 class Solution { public:vector…

00-ESP-IDF 环境配置指南

ESP-IDF 环境配置指南 ESP-IDF安装 1.首先我们在浏览器搜索esp-idf&#xff0c;点击第一个选项 2.点击右边栏的安装 3.我们选择手动安装选择需要的系统版本 4.点击链接 5.这里我们选择一个版本&#xff0c;建议不要选择最新的&#xff0c;安装出现问题在网上不好找到解决办…

蓝桥杯备战刷题-滑动窗口

今天给大家带来的是滑动窗口的类型题&#xff0c;都是十分经典的。 1&#xff0c;无重复字符的最长子串 看例三&#xff0c;我们顺便来说一下子串和子序列的含义 子串是从字符串里面抽出来的一部分&#xff0c;不可以有间隔&#xff0c;顺序也不能打乱。 子序列也是从字符串里…

Vue+SpringBoot打造个人健康管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 健康档案模块2.2 体检档案模块2.3 健康咨询模块 三、系统展示四、核心代码4.1 查询健康档案4.2 新增健康档案4.3 查询体检档案4.4 新增体检档案4.5 新增健康咨询 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpri…

【周总结周末日常】

周总结 完成任务开发并且与前端联调通过 完成已开发功能的冒烟测试 修复测试中出现的一些数据显示问题 2024/3/10 晴 温度适宜 这周天气比上周好多了&#xff0c;最起码见到好几次太阳 周六在世纪公园溜达一会儿&#xff0c;偶尔呼吸下大自然&#xff0c;挺棒的…

【QT】创建第一个QT程序

下面的前7个可以先不看&#xff0c;直接从8开始看 1. 创建Qt程序 一个Qt程序的组成部分&#xff1a;应用程序类&#xff0c;窗口类应用程序类个数&#xff1a;有且只有一个QApplication a;如何查看类对应的模块&#xff1a;光标移动到类上&#xff0c;F1qmake模块的名字 2. …

【设计模式】(四)设计模式之工厂模式

1. 工厂模式介绍 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 工厂模式有三种实现方式&#xff1a; 简单工厂模式工厂方法模式抽象工厂模式 2. 工厂方…

前后端分离项目,如何解决跨域问题?

跨域问题是前后端分离项目中非常常见的一个问题&#xff0c;举例来说&#xff0c;编程猫学习网站的前端服务跑在 8080 端口下&#xff0c;后端服务跑在 9002 端口下&#xff0c;那么前端在请求后端接口的时候就会出现跨域问题。 403 Forbidden 是HTTP协议中的一个状态码&#x…

华容道问题求解_详细设计(五)之hash值和回放功能

&#xff08;续上文&#xff09; 布局的hash 值计算 笔者也参考了之前的一些文章&#xff0c;很多文章提到了怎么节省存贮空间来查找最优解&#xff0c;这不是笔者的目的。笔者的目的比较单一&#xff0c;就是找到最优解就行了。因此并没有在存贮上面进行过多的优化&#xff…

消息队列 MQ

文章目录 1. MQ 相关概念1.1 什么是 MQ1.2 为什么要用 MQ1.3 MQ 分类1.4 MQ 的选择 1. MQ 相关概念 1.1 什么是 MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#x…