微服务与中间件系列——GateWay整合Swagger3增强Knife4j

news2025/1/12 15:49:41

微服务与中间件系列——GateWay整合Swagger3增强Knife4j

  • GateWay整合Swagger3增强Knife4j(easy模式)
    • 目的
    • 服务端
      • 1.导入依赖
      • 2.编写配置类
      • 3.yaml配置
    • GateWay网关
      • 1.文档枚举
      • 2.SwaggerProvider
      • 3.yaml配置
    • 结果
  • 增强版
    • 服务端
      • 1.增加配置参数类
      • 2.修改配置类
      • 3.修改yaml配置
    • GateWay网关
      • 1.增加全局认证过滤器

GateWay整合Swagger3增强Knife4j(easy模式)

目的

统一进行文档管理,查看,避免swagger文档在微服务中使用繁琐的问题
本案例使用nacos作为服务的注册中心

服务端

1.导入依赖

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

2.编写配置类

package cn.fly.client.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * @author Syf200208161018
 * @date 2022/11/19 15:44
 * @ClassName:SwaggerConfig
 * @Effect:SwaggerConfig is used for
 */
@Configuration
@EnableOpenApi
@Data
@ConfigurationProperties(prefix = "swagger")
public class SwaggerConfig {


    /**
     * 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
     */
    private Boolean enable;

    /**
     * 项目应用名
     */
    private String applicationName;

    /**
     * 项目版本信息
     */
    private String applicationVersion;

    /**
     * 项目描述信息
     */
    private String applicationDescription;

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.OAS_30)
                .pathMapping("/")

                // 定义是否开启swagger,false为关闭,可以通过变量控制,线上关闭
                .enable(enable)

                //配置api文档元信息
                .apiInfo(apiInfo())

                // 选择哪些接口作为swagger的doc发布
                .select()

                //apis() 控制哪些接口暴露给swagger,
                // RequestHandlerSelectors.any() 所有都暴露
                // RequestHandlerSelectors.basePackage("net.xdclass.*")  指定包位置
                // withMethodAnnotation(ApiOperation.class)标记有这个注解 ApiOperation
                .apis(RequestHandlerSelectors.basePackage("cn.fly.client.controller.common"))

                .paths(PathSelectors.any())

                .build();
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(applicationName)
                .description(applicationDescription)
                .contact(new Contact("syf", "syf20020816@outlook.com", "syf20020816@outlook.com"))
                .version(applicationVersion)
                .build();
    }
}

3.yaml配置

  1. 配置服务名称
  2. 配置mvc路径策略
  3. 配置nacos路径
  4. 配置swagger(自定义非官方,看配置类就知道了)
spring:
  application:
    name: Eprop-client
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  cloud:
    nacos:
#      server-addr: 192.168.31.149:8848
      server-addr: 172.16.216.47:8848
swagger:
  enable: true
  application-name: Eprop-client
  application-version: 1.0.0
  application-description: client

GateWay网关

1.文档枚举

package cn.fly.gateway.swagger;

import io.netty.channel.nio.AbstractNioByteChannel;

/**
 * @author Syf200208161018
 * @date 2022/11/19 19:12
 * @ClassName:DocEnum
 * @Effect:DocEnum is used for
 */
public enum DocEnum {
    /**
     * 路由信息
     */
    EPROP_COMMON("Eprop-client","eprop-API模块");


    private String routeId;
    private String swaggerInfo;

    DocEnum(String routeId, String swaggerInfo) {
        this.routeId = routeId;
        this.swaggerInfo = swaggerInfo;
    }

    public String getRouteId() {
        return routeId;
    }

    public void setRouteId(String routeId) {
        this.routeId = routeId;
    }

    public String getSwaggerInfo() {
        return swaggerInfo;
    }

    public void setSwaggerInfo(String swaggerInfo) {
        this.swaggerInfo = swaggerInfo;
    }

    public static String getSwaggerInfoByRouteId(String routeId){
        for (DocEnum value : DocEnum.values()) {
            if (value.getRouteId().equals(routeId)){
                return value.getSwaggerInfo();
            }
        }
        return null;
    }


}

2.SwaggerProvider

实现SwaggerResourcesProvider对资源进行修改

package cn.fly.gateway.swagger;

import com.alibaba.cloud.commons.lang.StringUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Syf200208161018
 * @date 2022/11/19 16:55
 * @ClassName:SwaggerProvider
 * @Effect:SwaggerProvider is used for
 */
/**
 * 聚合系统接口
 * @author ROCKY
 */
@Component
@Primary

public class SwaggerProvider implements SwaggerResourcesProvider {

    public static final String API_URI = "/v3/api-docs";
    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;

    public SwaggerProvider(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
        this.routeLocator = routeLocator;
        this.gatewayProperties = gatewayProperties;
    }

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        // 取出gateway的route
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        // 结合配置的route-路径(Path),和route过滤,只获取在枚举中说明的route节点
        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                        // 目前只处理Path断言  Header或其他路由需要另行扩展
                        .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                        .forEach(predicateDefinition -> {
                                    String routeId = routeDefinition.getId();
                                    String swaggerInfo = DocEnum.getSwaggerInfoByRouteId(routeId);
                                    if (StringUtils.isNotEmpty(swaggerInfo)) {
                                        resources.add(swaggerResource(swaggerInfo, predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", API_URI)));
                                    }
                                }
                        ));
        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("3.0");
        return swaggerResource;
    }
}

3.yaml配置

  1. 注意路由的ID要对应服务的名称
    在这里插入图片描述

  2. 注意过滤器的StripPrefix=3一定要和你前面指定的断言- Path=/api/v1/eprop/**匹配上,比如我这个就是去除3个前缀,如果是/api/hello/**,就是去除2个前缀,这个一定不能错,因为这和swagger请求地址有关
    在这里插入图片描述

server:
  port: 21301
spring:
  application:
    name: gateway
  cloud:
    nacos:
#      server-addr: 192.168.31.149:8848
      server-addr: 172.16.216.47:8848
#     server-addr: 192.168.1.103:8848
    gateway:
      routes:
        - id: Eprop-client
          uri: lb://Eprop-client
          predicates:
            - Path=/api/v1/eprop/**
          filters:
            - StripPrefix=3
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站进行跨域请求
              - "http://localhost:8080"
            allowedMethods:
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许所有请求头
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 跨域监测有效期
        add-to-simple-url-handler-mapping: true #解决options请求拦截
      discovery:
        locator:
          lower-case-service-id: true

结果

启动gateway浏览器访问ip:端口/doc.html
成功如下:
在这里插入图片描述

增强版

其实也就是做了一下对于配置的处理

服务端

1.增加配置参数类

package cn.fly.client.properties;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;


import java.util.ArrayList;
import java.util.List;

/**
 * @author Syf200208161018
 * @date 2022/11/20 0:44
 * @ClassName:SwaggerProperties
 * @Effect:SwaggerProperties is used for
 */
@ConfigurationProperties(prefix = "swagger-api")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SwaggerProperties {
    private String title="EPROP-API文档";
    private String groupName = "default";
    private String des="default API doc";
    private String version="1.1.0";
//    private Contact contact = new Contact("syf","syf20020816@outlook.com","syf20020816@outlook.com");
    private String docMaker = "syf";
    private String docUrl = "syf20020816@Outlook.com";
    private String makerEmail="syf20020816@Outlook.com";
    private String basePackage="cn.fly.client.controller";
    //解析的url规则
    private List<String> basePath = new ArrayList<>();
    //需要排除的url
    private List<String> excludePath = new ArrayList<>();
    /**
     * 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
     */
    private Boolean enable;

    /**
     * 项目应用名
     */
    private String applicationName;

    /**
     * 项目版本信息
     */
    private String applicationVersion;

    /**
     * 项目描述信息
     */
    private String applicationDescription;

}

2.修改配置类

package cn.fly.client.config;

import cn.fly.client.properties.SwaggerProperties;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * @author Syf200208161018
 * @date 2022/11/19 15:44
 * @ClassName:SwaggerConfig
 * @Effect:SwaggerConfig is used for
 */
@Configuration
@EnableOpenApi
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerConfig {
    @Autowired
    private SwaggerProperties swaggerProperties;

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.OAS_30)
                .pathMapping("/")
                // 定义是否开启swagger,false为关闭,可以通过变量控制,线上关闭
                .enable(swaggerProperties.getEnable())
                //配置api文档元信息
                .apiInfo(apiInfo())
                // 选择哪些接口作为swagger的doc发布
                .select()
                //apis() 控制哪些接口暴露给swagger,
                // RequestHandlerSelectors.any() 所有都暴露
                // RequestHandlerSelectors.basePackage("net.xdclass.*")  指定包位置
                // withMethodAnnotation(ApiOperation.class)标记有这个注解 ApiOperation
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                .paths(PathSelectors.any())
                .build();
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getApplicationDescription())
                .contact(new Contact(swaggerProperties.getDocMaker(),swaggerProperties.getDocUrl(),swaggerProperties.getMakerEmail()))
                .version(swaggerProperties.getApplicationVersion())
                .build();
    }
}

3.修改yaml配置

swagger-api:
  enable: true
  application-name: Eprop-client
  application-version: 1.0.0
  application-description: Eprop API文档Swagger3版本
  title: EPROP-API 文档
  groupName: Eprop-client
  des: Eprop API文档Swagger3版本
  version: 1.0.0
  docMaker: syf
  docUrl: www.eprop.fly.cn
  markerEmail: syf20020816@Outlook.com
  basePackage: cn.fly.client.controller

GateWay网关

1.增加全局认证过滤器

package cn.fly.gateway.filter;

import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @author Syf200208161018
 * @date 2022/10/28 13:16
 * @ClassName:AuthorizeFilter
 * @Effect:AuthorizeFilter is used for filtering user
 * the request header must have a token-eprop and then getUserInfo
 */
@Component
@Order(-1)
public class AuthorizeFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println(exchange.getRequest().getURI().getPath());
            if (exchange.getRequest().getURI().getPath().equals("/v3/api-docs")){
                return chain.filter(exchange);
            }else{
                //get request params
                final ServerHttpRequest request = exchange.getRequest();
                //get header: token-eprop
                final HttpHeaders requestHeaders = request.getHeaders();
                final List<String> values = requestHeaders.get("token-eprop");
                for (String value : values) {
                    System.out.println(value);
                }
                final String tokenValue = values.get(0);
                System.out.println(tokenValue);
                //if tokenValue is empty or null intercept the request
                if (StringUtils.isBlank(tokenValue)){
                    return exchange.getResponse().setComplete();
                }
                return chain.filter(exchange);
            }
    }
}

其他无需更改

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

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

相关文章

Spring框架一文带你吃透IOC技术

本文目录 文章目录本文目录✨loC的技术实现✨实现步骤✨创建接口和实现类✨创建Spring的配置文件和声明bean✨创建spring容器对象✨spring容器创建对象的特点✨创建非自定义类的对象✨创建没有接口的类的对象✨获取容器中对象的信息loC&#xff0c;Inversion ofControl:控制反转…

肿瘤NGS测序行业背景介绍

肿瘤NGS测序行业背景介绍1、行业基本情况1.1 行业分类1.2 主管部门1.3 行业监管1.4 行业法规1.5 医保报销流程2、肿瘤基本介绍2.1 肿瘤基础概念2.2 癌症分期2.3 致癌风险2.4 肿瘤早期检测3、分子诊断在肿瘤早检的场景3.1 传统肿瘤早期检测方式3.2 分子诊断3.3 技术性能评价指标…

SpringBoot SpringBoot 开发实用篇 4 数据层解决方案 4.9 MongoDB 下载与安装

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇4 数据层解决方案4.9 MongoDB 下载与安装4.9.1 MongoDB 下载4.9.2 安…

PLATFORMIO学习文档之esp8266 驱动SSD1306 128x64OLED显示屏示例

写文章也是为了记录自己的学习过程&#xff0c;顺便给后来人指指路&#xff0c;迷路了可别怪我~~~~~~ 开发环境&#xff1a;PLATFORMIO 1、首先上一张我用的ESP8266开发板ESP-12E 首先新建一个工程&#xff0c;输入项目名称&#xff0c;选择自己所用的开发板&#xff0c; …

灵界的科学丨二、耳朵及手指识字的实验启示

摘自李嗣涔教授《灵界的科学》 如果有一天&#xff0c; 能教会盲人用手指或耳朵来「看」&#xff0c; 用触觉来取代眼睛&#xff0c; 人类社会中&#xff0c;将不再存在「盲」这种残疾。 发现人体潜能――耳朵与手指识字 眼睛可以观赏五彩缤纷的世界&#xff0c;耳朵可以听…

Joe 主题 Halo 移植版搭建部署教程

搭建成功之后的效果图如下 Halo安装部署 Docker 安装 Halo docker pull halohub/halo:1.5.4 # docker 从远程仓库下载镜像 docker run -it -d --name fl1906 -p 666:8090 -v ~/fl1906:/root/.halo halohub/halo:1.5.4 --restartalwaysdocker run -it -d --name walktop -p 7…

【算法系列】非线性最小二乘-列文伯格马夸尔和狗腿算法

系列文章目录 【算法系列】卡尔曼滤波算法 【算法系列】非线性最小二乘求解-直接求解法 【算法系列】非线性最小二乘求解-梯度下降法 【算法系列】非线性最小二乘-高斯牛顿法 【算法系列】非线性最小二乘-列文伯格马夸尔和狗腿算法 文章目录 系列文章 文章目录 前言 …

期末网页设计作业素材 (民宿 5页 带地图)

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 游景点介绍 | 旅游风景区 | 家乡介绍 | 等网站的设计与制作 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&#xff1a;结构 CSS&…

JSON解析看这一篇就够了

目录 文章目录[toc]一、JSON是什么 &#xff08;&#xffe3;︶&#xffe3;&#xff09;↗总而言之&#xff1a;二、为什么要用JSON三、不同的JSON解析方式3.1 gson和[fastjson](https://so.csdn.net/so/search?qfastjson&spm1001.2101.3001.7020)简而言之3.2 gson案例3.…

15.Servlet

目录 1.Servlet的日常开发 1.WebServlet(...此处填写资源路径) 1.那么什么时候Tomcat会启动失败&#xff1f; 2.响应体是文本内容&&字符集编码是uft-8 3.读取请求参数 4.资源的重定向&#xff08;redirect&#xff09; 2.面试问题&#xff1a;GET和POST有什么区…

代码随想录算法训练营三期 day 23 - 二叉树(9)

669. 修剪二叉搜索树 原文链接&#xff1a;669. 修剪二叉搜索树 题目链接&#xff1a;669. 修剪二叉搜索树 视频链接&#xff1a;669. 修剪二叉搜索树 在上图中我们发现结点 000 并不符合区间要求&#xff0c;那么将结点 000 的右孩子 结点 222 直接赋给 结点 333 的左孩子就…

Java设计模式 (1) —— Iterator迭代器模式

拿到这个话题&#xff0c;首先搞清楚&#xff1a;什么是迭代器&#xff1f; 大家都学过 for-i 循环&#xff0c;for-i循环的本质就是 通过i 或者 i-- &#xff0c;以实现 从数据的一端 一个一个地遍历数据元素&#xff0c;直到另一端的最后一个元素&#xff0c;将这里 i 的通用…

【Linux】基础IO —— 深入理解文件系统 | 软硬链接

&#x1f308;欢迎来到Linux专栏~~ 深入理解文件系统 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的…

安全需求和挑战

安全需求和挑战 从风险管理的角度讲&#xff0c;主要就是管理资产、威胁、脆弱性 和防护措施及其相关关系&#xff0c;最终保障云计算平台的持续安全&#xff0c;以及 其所支撑的业务的安全。 云计算平台是在传统 IT技术的基础上&#xff0c;增加了一个虚拟化 层&#xff0c;并…

大数据之——Hive

目录1. Hive 基本概念1.1 什么是 Hive1.2 Hive 的优缺点1.2.1 优点1.2.2 缺点1.3 Hive 架构原理2. Hive 安装2.1 Hive 安装地址2.2Hive 安装部署2.3MySQL 安装2.4 Hive 元数据配置到 MySQL2.4.1 拷贝驱动2.4.2 配置 Metastore 到 MySQL2.4.3 再次启动 Hive2.5 使用元数据服务的…

让学前端不再害怕英语单词(二)

写了本专栏的第一章让学前端不再害怕英语单词&#xff08;一&#xff09;后&#xff0c;反响热度还是比较高的&#xff0c;截止现在已经有20个收藏量了&#xff0c;所以趁热打铁来更第二章 第一章我们简单的介绍了html&#xff0c;css和js的部分高频单词&#xff0c;因为html要…

S32K144的GPIO使用

程序初始化前线使用Components工具对时钟和GPIO进行配置&#xff0c;然后再main函数里面初始化。 时钟配置参考&#xff1a; S32K144之时钟配置 - 明明1109 - 博客园 (cnblogs.com) gpio配置 S32K SDK使用详解之PinSettings组件配置与使用详解(S32K1xx PORT 和GPIO模块)_嵌…

jdk1.8新特性简介

一、引言 jdk1.8出来已经一段时间了&#xff0c;现在1.9也已经出来了&#xff0c;但是很多公司&#xff08;我们公司也一样&#xff09;不太愿意升级到高版本的jdk&#xff0c;主要是有老的项目要维护&#xff0c;还有升级的话配套的框架也要升级&#xff0c;要考虑的细节事情太…

实训素材纯HTML+CSS代码 (教育主题 3页 )

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 家乡旅游景点 | 家乡民生变化 | 介绍自己的家乡 | 我的家乡 | 家乡主题 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&#xff1a;结…

SpringMVC具体工作流程(保姆教学)

目录 文章目录[toc]一、SpingMVC的常用组件二、[SpringMVC](https://so.csdn.net/so/search?qSpringMVC&spm1001.2101.3001.7020)的工作流程一、SpingMVC的常用组件 1&#xff09;DispatcherServlet 是一种前端控制器&#xff0c;由框架提供。 作用&#xff1a;统一处理请…