Swagger在php和java项目中的应用

Swagger在php和java项目中的应用

  • Swagger简介
  • Swagger在java项目中的应用
    • 步骤
    • 常用注解
  • Swagger在php项目中的应用

Swagger简介

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger 让部署管理和使用功能强大的 API 从未如此简单。

  • 对于后端开发人员来说
  1. 不用再手写WiKi接口拼大量的参数,避免手写错误
  2. 对代码侵入性低,采用全注解的方式,开发简单
  3. 方法参数名修改、增加、减少参数都可以直接生效,不用手动维护
  4. 增加了开发成本,写接口还得再写一套参数配置
  • 对于前端开发来说
  1. 后端只需要定义好接口,会自动生成文档,接口功能、参数一目了然
  2. 联调方便,如果出问题,直接测试接口,实时检查参数和返回值,就可以快速定位是前端还是后端的问题
  • 对于测试来说
  1. 对于某些没有前端界面UI的功能,可以用它来测试接口
  2. 操作简单,不用了解具体代码就可以操作

Swagger在java项目中的应用

knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案

步骤

  1. 导入knife4j的maven坐标
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.2</version>
</dependency>
  1. 导入knife4j相关配置类(WebMvcConfig)
  2. 设置静态资源,否则接口文档页面无法访问
package com.demo.config;import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.List;@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {/*** 设置静态资源映射* @param registry*/protected void addResourceHandlers (ResourceHandlerRegistry registry) {    				registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}@Beanpublic Docket createRestApi () {// 文档类型return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.demo.controller")) // swagger扫描的包.paths(PathSelectors.any()).build();}/*** 介绍接口信息*/private ApiInfo apiInfo () {return new ApiInfoBuilder().title("Robin's Swagger documents").version("1.0").description("Robin's Swagger documents").build();}
}
  1. 在LoginCheckFilter中设置不需要处理的请求路径
package com.demo.filter;import com.alibaba.fastjson.JSON;
import com.demo.common.BaseContext;
import com.demo.common.R;
import com.demo.entity.Employee;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 检查用户是否已经完成登录*/@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {// 路径匹配器,支持通配符public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();// 定义不需要处理的请求路径public static final String[] urls = new String[]{"/employee/login", // 登录接口"/employee/logout", // 退出接口"/backend/**", // 放行后台静态资源"/front/**", // 放行前台静态资源"/common/download", // 文件下载接口"/user/login", // 移动端登录"/user/sendMsg", // 获取验证码接口"/doc.html", // swagger文档路径"/webjars/**","/swagger-resources/**","/v2/api-docs",};@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// 1、获取本次请求的URIString requestUri = request.getRequestURI();// 2、判断本次请求是否需要处理,如果不需要处理,则直接放行if (check(requestUri)) {filterChain.doFilter(request, response);return;}// 3、判断登录状态,如果已登录,则直接放行Long empId = (Long) request.getSession().getAttribute("employee");Long userId = (Long) request.getSession().getAttribute("user");if (empId != null || userId != null) {// 将当前登录的用户id保存到ThreadLocal中if (empId != null) BaseContext.setCurrentId(empId);if (userId != null) BaseContext.setCurrentId(userId);filterChain.doFilter(request, response);return;}// 4、如果未登录,则返回未登录结果log.info("拦截到请求:{}", request.getRequestURI());response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));}/*** 路径匹配,检测本次请求是否需要放行* @param requestUri 本次请求资源* @return 路径匹配结果,true-放行,false-不放行*/public boolean check (String requestUri) {for (String url:urls) {if (PATH_MATCHER.match(url, requestUri)) {return true;}}return false;}
}

访问域名/doc.html,在这里插入图片描述

常用注解

注解说明
@Api用在请求的类上,例如Controller,表示对类的说明
@ApiModel用在类上,通常是实体类,表示一个返回响应数据的信息
@ApiModelProperty用在属性上,描述响应类的属性
@ApiOperation用在请求的方法上,说明方法的用途、作用
@ApiImplicitParams用在请求的方法上,表示一组参数说明
@ApiImplicitParam用在@ApilmplicitParams 注解中,指定一个请示参数的各个方面

R实体类补充注解:

package com.demo.common;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;/*** 通用返回结果,服务端响应的数据最终都会封装成此对象* @param <T>*/
@Data
@ApiModel("返回结果")
public class R<T> implements Serializable {@ApiModelProperty("编码:1成功,0和其它数字为失败")private Integer code; //编码:1成功,0和其它数字为失败@ApiModelProperty("错误信息")private String msg; //错误信息@ApiModelProperty("数据")private T data; //数据@ApiModelProperty("动态数据")private Map map = new HashMap(); //动态数据public static <T> R<T> success(T object) {R<T> r = new R<T>();r.data = object;r.code = 1;return r;}public static <T> R<T> error(String msg) {R r = new R();r.msg = msg;r.code = 0;return r;}public R<T> add(String key, Object value) {this.map.put(key, value);return this;}}

套餐实体类补充注解:

package com.demo.entity;import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 套餐*/
@Data
@ApiModel("套餐")
public class Setmeal implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("主键")private Long id;//分类id@ApiModelProperty("分类id")private Long categoryId;//套餐名称@ApiModelProperty("套餐名称")private String name;//套餐价格@ApiModelProperty("套餐价格")private BigDecimal price;//状态 0:停用 1:启用@ApiModelProperty("状态 0:停用 1:启用")private Integer status;//编码@ApiModelProperty("编码")private String code;//描述信息@ApiModelProperty("描述信息")private String description;//图片@ApiModelProperty("图片")private String image;@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private Long createUser;@TableField(fill = FieldFill.INSERT_UPDATE)private Long updateUser;//是否删除@ApiModelProperty("是否删除")private Integer isDeleted;
}

套餐接口补充注解:

package com.demo.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.demo.common.R;
import com.demo.dto.SetmealDto;
import com.demo.entity.Category;
import com.demo.entity.Setmeal;
import com.demo.service.CategoryService;
import com.demo.service.SetmealDishService;
import com.demo.service.SetmealService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;/*** 套餐管理*/
@Slf4j
@RestController
@RequestMapping("/setmeal")
@Api(tags = "套餐相关接口")
public class SetmealController {@Autowiredprivate SetmealService setmealService;@Autowiredprivate SetmealDishService setmealDishService;@Autowiredprivate CategoryService categoryService;/*** 新增套餐* @param setmealDto 套餐实体* @return 返回信息*/@CacheEvict(value = "setmealCache", allEntries = true)@PostMapping@ApiOperation(value = "新增套餐接口")public R<String> save(@RequestBody SetmealDto setmealDto) {setmealService.saveWithDish(setmealDto);return R.success("新增套餐成功");}/*** 套餐分页查询* @param page 页码* @param pageSize 单页数据量* @param name 套餐名称* @return 列表数据*/@GetMapping("/page")@ApiOperation(value = "套餐分页查询")@ApiImplicitParams({@ApiImplicitParam(name = "page", value = "页码", required = true),@ApiImplicitParam(name = "pageSize", value = "每页记录数", required = true),@ApiImplicitParam(name = "name", value = "套餐名称", required = false),})public R<Page<SetmealDto>> page (int page, int pageSize, String name) {// 构建分页构造器Page<Setmeal> pageInfo = new Page<>(page, pageSize);LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();// 添加查询条件,根据name进行模糊查询lambdaQueryWrapper.like(name != null, Setmeal::getName, name);// 添加排序条件,根据更新时间降序排列lambdaQueryWrapper.orderByAsc(Setmeal::getStatus).orderByDesc(Setmeal::getUpdateTime);setmealService.page(pageInfo, lambdaQueryWrapper);// 对象拷贝,补充分类信息Page<SetmealDto> dtoPage = new Page<>(page, pageSize);BeanUtils.copyProperties(pageInfo, dtoPage, "'records'");List<Setmeal> records = pageInfo.getRecords();List<SetmealDto> list = records.stream().map((item) -> {// 对象拷贝SetmealDto setmealDto = new SetmealDto();BeanUtils.copyProperties(item, setmealDto);// 设置分类名称Category category = categoryService.getById(item.getCategoryId());if (category != null) {setmealDto.setCategoryName(category.getName());}return setmealDto;}).collect(Collectors.toList());dtoPage.setRecords(list);return R.success(dtoPage);}/*** 批量删除套餐* @param ids 套餐id* @return 返回信息*/@CacheEvict(value = "setmealCache", allEntries = true)@DeleteMapping@ApiOperation(value = "批量删除套餐")public R<String> delete(@RequestParam List<Long> ids) {setmealService.removeWithDish(ids);return R.success("套餐数据删除成功");}/*** 批量上下架* @param ids 套餐id* @param status 上下架状态* @return 返回信息*/@PostMapping("/status/{status}")@ApiOperation(value = "批量上下架")public R<String> updateStatus(@RequestParam List<Long> ids, @PathVariable int status) {List<Setmeal> setmealList = ids.stream().map((item) -> {Setmeal setmeal = new Setmeal();setmeal.setId(item);setmeal.setStatus(status);return setmeal;}).collect(Collectors.toList());setmealService.updateBatchById(setmealList);return R.success("更新成功");}/*** 获取套餐详情数据* @param id 套餐id* @return 套餐实体信息*/@GetMapping("/{id}")@ApiOperation(value = "获取套餐详情数据")public R<SetmealDto> detail(@PathVariable Long id) {SetmealDto setmealDto = setmealService.getSetmealWithDish(id);return R.success(setmealDto);}/*** 修改套餐* @param setmealDto 套餐实体* @return 舞台信息*/@PutMapping@ApiOperation(value = "修改套餐")public R<String> update(@RequestBody SetmealDto setmealDto) {setmealService.updateWithDish(setmealDto);return R.success("编辑成功");}/*** 根据条件查询套餐数据* @param setmeal 套餐过滤条件* @return 套餐列表*/@GetMapping("/list")@Cacheable(value = "setmealCache", key="#setmeal.categoryId + '_' + #setmeal.status", unless = "#result.data.size() == 0")@ApiOperation(value = "根据条件查询套餐数据")public R<List<Setmeal>> list(Setmeal setmeal) {log.info("未命中缓存查询");LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();// 分类条件lambdaQueryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());// 上下架状态lambdaQueryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());// 排序lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);List<Setmeal> list = setmealService.list(lambdaQueryWrapper);return R.success(list);}
}

重新启动服务,查看实体和接口文档

在这里插入图片描述
在这里插入图片描述

Swagger在php项目中的应用

  1. 安装swagger包

zircote/swagger-php是swagger的php版,是一个扩展库,可以通过composer来进行安装

composer require zircote/swagger-php
  1. 安装Swagger ui

将swagger-ui下载下来以后,把dist目录下的文件复制到项目public/docs目录下, 这个目录可以自定义, 通俗来讲就是放到项目能访问到的目录下, 然后再将dist目录下的swagger-initializer.js文件中的url改成./openapi.yaml, 这里的openapi.yaml是生成文档后的文件名,意思是访问本地的openapi.yaml文件

在这里插入图片描述

<?php
namespace app\controller;use app\BaseController;
use think\App;
use think\facade\Request;/*** @OA\Info (*     title = "Robins's API documetns",*     version = "1.0",*     description="本文档仅限于测试"* )*/
class Index extends BaseController
{public function getDoc() {$openapi = \OpenApi\Generator::scan([__ROOT__ . '/../app']);// 生成yaml文件file_put_contents(__ROOT__ . '\doc\dist\openapi.yaml', $openapi->toYaml());}/*** @OA\Get (*     path="/",*     tags = {"用户订单列表接口"},*     summary = "用户订单列表接口",*     description = "获取用户订单信息",*     @OA\Parameter (name = "order_id", in = "query", description = "订单号", required = true),*     @OA\Parameter (name = "account_id", in = "query", description = "账户id", required = true),*     @OA\Response(response = "200",description = "The data"),*     @OA\MediaType(*          mediaType="application/json",*          @OA\Schema(ref="#/components/schemas/Info"),*     )* )* @return \think\response\Json*/public function index(){      $accountId = Request::post('account_id', 0);       $orderId = Request::post('order_id', '');       $data = Order::where(['account_id' => $accountId, 'order_id' => $orderId])->select()->toArray();return json($data);}
}

swagger在php项目中的注解还需要一点点摸索熟练

在这里插入图片描述

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

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

相关文章

MyBatis的功能架构,MyBatis的框架架构设计,Mybatis都有哪些Executor执行器,Mybatis中如何指定使用哪一种Executor执行器

文章目录 MyBatis的功能架构是怎样的把Mybatis的功能架构分为三层&#xff1a; **MyBatis的框架架构设计**是怎么样的架构图如下Mybatis都有哪些Executor执行器&#xff1f;它们之间的区别是什么&#xff1f;Mybatis中如何指定使用哪一种Executor执行器&#xff1f; MyBatis的功…

SASS的导入文件详细教程

文章目录 前言导入SASS文件使用SASS部分文件默认变量值嵌套导入原生的CSS导入后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努…

人工智能入门教学——AI代理(AI Agent)

目录 一、简介 二、特征 三、结构 四、工作流程 五、类型 六、应用 一、简介 AI代理 (Artificial Intelligence Agent)是指使用人工智能技术和算法来执行特定任务、解决问题或实现目标的程序或系统。这些代理可以是简单的程序&#xff0c;也可以是复杂的系统&#xff0c…

面向对象编程:Rust的面向对象特性

欢迎关注我的公众号lincyang新自媒体&#xff0c;回复关键字【程序员经典书单】&#xff0c;领取程序员的100本经典书单 大家好&#xff01;我是lincyang。 今天我们将深入探讨Rust语言中的面向对象编程&#xff08;OOP&#xff09;特性&#xff0c;并将其与其他流行编程语言进…

基于U-Net的视网膜血管分割(Pytorch完整版)

基于 U-Net 的视网膜血管分割是一种应用深度学习的方法&#xff0c;特别是 U-Net 结构&#xff0c;用于从眼底图像中分割出视网膜血管。U-Net 是一种全卷积神经网络&#xff08;FCN&#xff09;&#xff0c;通常用于图像分割任务。以下是基于 U-Net 的视网膜血管分割的内容&…

mysql高级知识点

一、mysql架构 连接层&#xff1a;负责接收客户端的连接请求&#xff0c;可以进行授权、认证(验证账号密码)。服务层&#xff1a;负责调用sql接口&#xff0c;对sql语法进行解析&#xff0c;对查询进行优化&#xff0c;缓存。引擎层&#xff1a;是真正进行执行sql的地方&#x…

Linux面试题(二)

目录 17、怎么使一个命令在后台运行? 18、利用 ps 怎么显示所有的进程? 怎么利用 ps 查看指定进程的信息&#xff1f; 19、哪个命令专门用来查看后台任务? 20、把后台任务调到前台执行使用什么命令?把停下的后台任务在后台执行起来用什么命令? 21、终止进程用什么命令…

Vue框架学习笔记——事件修饰符

文章目录 前文提要事件修饰符prevent&#xff08;常用&#xff09;stop&#xff08;不常用&#xff09;事件冒泡stop使用方法三层嵌套下的stop三层嵌套看出的stop&#xff1a; once&#xff08;常用&#xff09;capture&#xff08;不常用&#xff09;self&#xff08;不常用&a…

Vue轻松入门,附带学习笔记和相关案例

目录 一Vue基础 什么是Vue&#xff1f; 补充&#xff1a;mvvm框架 mvvm的组成 详解 Vue的使用方法 1.直接下载并引入 2.通过 CDN 使用 Vue 3.通过npm安装 4.使用Vue CLI创建项目 二插值表达式 什么是插值表达式&#xff1f; 插值表达式的缺点 解决方法 相关代…

【数据结构】树与二叉树(廿五):树搜索指定数据域的结点(算法FindTarget)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲3. 搜索指定数据域的结点a. 算法FindTargetb. 算法解析c. 代码实现a. 使用指向指针的指针b. 直接返回找到的节点 4. 代码整合 5.3.1 树的存储结构 5.…

VUE限制文件上传大小和上传格式

<el-form-item label"图片&#xff1a;" prop"tempImagePath"><el-uploadclass"upload"accept"image/jpeg":show-file-list"false"list-type"picture-card":headers"{ token: token}":action&…

linux的netstat命令和ss命令

1. 网络状态 State状态LISTENING监听中&#xff0c;服务端需要打开一个socket进行监听&#xff0c;侦听来自远方TCP端口的连接请求ESTABLISHED已连接&#xff0c;代表一个打开的连接&#xff0c;双方可以进行或已经在数据交互了SYN_SENT客户端通过应用程序调用connect发送一个…

人力资源管理后台 === 基础环境+登陆

目录 1.人力资源项目介绍 1.1 项目架构和解决方案 1.2 课程安排 1.3 课程具备能力 1.4 课程地址 2. 拉取项目基础代码 3.项目目录和入口文件介绍 4.App.vue根组件解析 5.基础设置settings.js和导航守卫permission.js 6.Vuex的结构 7.使用模板中的Icon图标 8.扩展…

最新世界银行WDI面板数据(1960-2022年)

The World Development Indicators 是由世界银行编制和发布的全面数据集&#xff0c;旨在提供全球发展的详尽统计信息。这份数据集收录了1960-2022年间&#xff0c;世界266个国家共计1477个指标&#xff0c;涵盖经济、社会、环境、教育、公共卫生等20个领域 一、数据介绍 数据…

chromium通信系统-mojo系统(一)-ipcz系统代码实现-同Node通信

在chromium通信系统-mojo系统(一)-ipcz系统基本概念一文中我们介绍了ipcz的基本概念。 本章我们来通过代码分析它的实现。 handle系统 为了不对上层api暴露太多细节&#xff0c;实现解耦&#xff0c;也方便于传输&#xff0c;ipcz系统使用handle表示一个对象&#xff0c;hand…

MySQL基本SQL语句(下)

MySQL基本SQL语句&#xff08;下&#xff09; 一、扩展常见的数据类型 1、回顾数据表的创建语法 基本语法&#xff1a; mysql> create table 数据表名称(字段名称1 字段类型 字段约束,字段名称2 字段类型 字段约束,...primary key(主键字段 > 不能为空、必须唯一) ) …

WebSocket协议测试实战

当涉及到WebSocket协议测试时&#xff0c;有几个关键方面需要考虑。在本文中&#xff0c;我们将探讨如何使用Python编写WebSocket测试&#xff0c;并使用一些常见的工具和库来简化测试过程。 1、什么是WebSocket协议&#xff1f; WebSocket是一种在客户端和服务器之间提供双向…

KubeVela核心控制器原理浅析

前言 在学习 KubeVela 的核心控制器之前&#xff0c;我们先简单了解一下 KubeVela 的相关知识。 KubeVela 本身是一个应用交付与管理控制平面&#xff0c;它架在 Kubernetes 集群、云平台等基础设施之上&#xff0c;通过开放应用模型来对组件、云服务、运维能力、交付工作流进…

4G模块(EC600N)通过MQTT连接华为云

目录 一、前言 二、EC600N模块使用 1&#xff0e;透传模式 2&#xff0e;非透传模式 3、华为云的MQTT使用教程&#xff1a; 三、具体连接步骤 1、初始化检测 2、打开MQTT客户端网络 3、创建产品 4、创建模型 5、注册设备 6、连接客户端到MQTT服务器 7、发布主题消…

Redis面试题:Redis的数据过期策略有哪些?

目录 面试官&#xff1a;Redis的数据过期策略有哪些 ? 惰性删除 定期删除 面试官&#xff1a;Redis的数据过期策略有哪些 ? 候选人&#xff1a; 嗯~&#xff0c;在redis中提供了两种数据过期删除策略 第一种是惰性删除&#xff0c;在设置该key过期时间后&#xff0c;我们…