【JAVA WEB实用与优化技巧】如何自己封装一个自定义UI的Swagger组件,包含Swagger如何处理JWT无状态鉴权自动TOKEN获取

news2024/11/16 14:22:13

目录

  • 一、Swagger 简介
    • 1. 什么是 Swagger?
    • 2. 如何使用 Swagger
    • 3. Springboot 中swagger的使用示例
      • 1. maven 引入安装
      • 2. java配置
  • 二、Swagger UI存在的缺点
    • 1.不够方便直观
    • 2.请求的参数没有缓存
    • 3.不够美观
    • 4.如果是JWT 无状态登录,Swagger使用起来就没有那么丝滑了
  • 三、封装以及讨论
    • 封装组件
      • 代码封装
      • 解决无状态登录问题
        • 1. 我们往swagger-bootstrap-ui的右上角加一个按钮,点击出现弹框来配置自动获取登录token
        • 2.javascript 脚本部分实现:
  • 总结

一、Swagger 简介

Swagger 是一款用于 API 设计、构建、文档化和测试的开源工具。它提供了一整套的解决方案,帮助开发者更好地构建和管理 RESTful APIs。以下是对 Swagger 的简要介绍:

1. 什么是 Swagger?

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful Web 服务。它基于 OpenAPI 规范(以前称为 Swagger 规范),该规范定义了 API 的结构。

2. 如何使用 Swagger

  • 定义 API:使用 Swagger Editor 编写 OpenAPI 规范文件,描述 API 的端点、请求参数、响应格式等。
  • 生成文档:通过 Swagger UI 或 Swagger Codegen,生成可视化的 API 文档。
  • 集成到项目:在项目中集成 Swagger 的相关工具,比如在 Spring Boot 项目中使用 springfox-swagger2springfox-swagger-ui 依赖,自动生成和托管 API 文档。

3. Springboot 中swagger的使用示例

以下是一个使用 Swagger 注解的简单示例,展示了如何在 Spring Boot 应用中集成 Swagger:

1. maven 引入安装

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

2. java配置

@EnableSwagger2
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.efficientnotes.boot.web"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Efficient notes api platform")
                .description("apis")
                .termsOfServiceUrl("http://localhost:9000/")
                .contact("yh4494@sina.com")
                .version("1.0")
                .build();
    }

}

title title就是swagger页面上展示的title,比如交ERP api平台
description 详情介绍
termsOfServiceUrl 机构首页地址
contact 联系方式
version 版本号

Spring security 排除拦截:

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/v2/*").permitAll()
                .antMatchers("/csrf").permitAll()
                .antMatchers("/").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
        ;
    }
}

控制器示例:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@RestController
@Api(value = "示例API", description = "这是一个示例API")
public class ExampleController {

    @GetMapping("/hello")
    @ApiOperation(value = "问候接口", notes = "通过传递名字来获得问候语")
    public String hello(@ApiParam(value = "用户的名字", required = true) @RequestParam String name) {
        return "Hello, " + name + "!";
    }
}

在完成上述步骤后,启动 Spring Boot 应用并访问 http://localhost:8080/swagger-ui.html,即可查看自动生成的 API 文档。
Swagger 是一个强大且灵活的工具集,为开发者提供了方便、高效的 API 管理解决方案。通过标准化和自动化,它极大地简化了 API 开发和维护的过程。

在这里插入图片描述
图 ①

二、Swagger UI存在的缺点

1.不够方便直观

swagger ui 布局是上下瀑布式的,比如我访问完A接口,想访问B接口,访问完B接口想继续访问A接口就必须往上翻,接口少还好操作。接口多的话来回就很烦。

2.请求的参数没有缓存

比如我想掉一个post接口来伪造一条数据,第一次访问完成之后,刷新页面后第二次还要重新造数据,就很麻烦,命名我只需要改部分字段重新请求就行,结果每次都要重新填写报文。字段躲起来兼职就是折磨。

3.不够美观

不用多说,当然一个工具类产品美观并不重要,但是美观的产品还是能给人带来心情愉悦的体验,就像你旁边坐着一位漂亮女孩,你整天心情都会好很多。不管如何对我来说工具颜值还是挺重要的。

4.如果是JWT 无状态登录,Swagger使用起来就没有那么丝滑了

因为JWT无状态登录这种需要每次在请求的Header中带上TOKEN,Swagger可没那么只能给你登录接口返回的token带过去,这样就导致无状态session的情况下Swagger的调试功能等于瘫痪状态。

三、封装以及讨论

我们来讨论下如何解决上述一些缺陷给Swagger换一层皮,并且将Swagger封装成组件

很久以前我就关注过一些swaggerui的项目了,比较优秀的是swagger-bootstrap-ui。现在好像升级过不叫这个名字了,但我保存了一份之前的swagger-bootstrap-ui的代码。github的地址是:https://github.com/xiaoymin/swagger-bootstrap-ui,直接可以下载的地址: swagger-bootstrap-ui。

这份UI解决了上述中前三个问题不够方便直观、请求的参数没有缓存、不够美观,虽然不是太好看,但也还好吧!如果对外观还是不够满意的话可以自己修改下样式,盖起来也很方便,我会在下面的文章中进行讨论和介绍。那么我们先看下具体的ui长什么样子。
在这里插入图片描述
图②

看起来是不是比图 ①要舒服多了。那么我们在下面异步异步的讨论如何将这个ui封装成一个组件可以直接引用以及如何解决缺陷的第四点:JWT无状态登录如何自动拼装token。

封装组件

现在我们有了前端代码,可以参考swagger原生的ui就是做成的一个jar包,引入的这个jar包就拥有了swagger-ui。我们也参考下这种方式,前后端代码结合自动配置,项目引入我们的依赖就能直接拥有提供接口文档的能力。

代码封装

我们想让我们的组件提供完整的swagger能力,那么首先我们自己的封装的swagger组件中要引入所有的swagger的依赖。

<dependencies>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
        <exclusions>
            <exclusion>
                <artifactId>spring-context</artifactId>
                <groupId>org.springframework</groupId>
            </exclusion>
            <exclusion>
                <artifactId>spring-aop</artifactId>
                <groupId>org.springframework</groupId>
            </exclusion>
            <exclusion>
                <artifactId>jackson-annotations</artifactId>
                <groupId>com.fasterxml.jackson.core</groupId>
            </exclusion>
            <exclusion>
                <artifactId>slf4j-api</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
            <exclusion>
                <artifactId>spring-beans</artifactId>
                <groupId>org.springframework</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

swagger2是通过EnableSwagger2来启用swagger,我们也可以写一个注解来做这件事情,引用我们自己定义的注解就可以自动配置启用我们的swagger组件。

EnableAllensSwagger

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(SwaggerConfig.class)
public @interface EnableAllensSwagger {
}

然后我们需要将所有的配置都配置好,提供我们自己自定义的配置出去,然需要引入的应用项目配置我们提供的配置来自定义Swagger。

SwaggerProperties

/**
 * SwaggerProperties
 *
 * @author allens
 * @since 2024/5/21
 */
@Component
@ConfigurationProperties(prefix = "allens.swagger")
@Setter
@Getter
public class SwaggerProperties {

    private String packages;

    private String title;

    private String description;

    private String termsOfServiceUrl;

    private String version;

    private String contact;
}

SwaggerConfig 通过这个类来做组件的autoconfig,当Springboot中启用@EnableAllensSwagger注解的时候,@Import(SwaggerConfig.class)就会自动加载注入 SwaggerConfig,SwaggerConfig回去扫描com.allens.swagger下的所有bean来自动加载组件。

@EnableSwagger2
@Configuration
@ComponentScan("com.allens.swagger")
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerConfig {

    @Resource
    SwaggerProperties swaggerProperties;

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getPackages()))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
                .contact(swaggerProperties.getContact())
                .version(swaggerProperties.getVersion())
                .build();
    }

}

接着我们需要把前端的代码copy到项目中,同时项目打包的时候可以把swagger-bootstrap-ui打包到jar包中,同时我们需要访问/${servletContextPath}/doc.html的时候可以正常访问到前端界面。

① 拷贝swagger-boot-ui 到项目中
在这里插入图片描述

② 配置路由映射规则,如果是SpringSecurity也是要忽略doc.html//webjars/**这两个地址。

@Configuration
public class SwaggerWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/resources/webjars/");
    }
}
@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests().and().csrf().disable()
            .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests()
            .antMatchers(" "/doc.html",
                    "/webjars/**",
                    "/v2/api-docs/**",
                    "/swagger-resources/**")
            .anonymous()
            .anyRequest().authenticated();

    http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    // 添加CORS filter
    http.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
    http.addFilterBefore(corsFilter, LogoutFilter.class);
}

然后我们就可以直接到项目中引入我们的组件并且配置了

<dependency>
    <groupId>com.efficientnotes</groupId>
    <artifactId>allens-swagger</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

yml文件配置:

allens:
  swagger:
    packages: com.efficientnotes.boot.web
    title: Efficient notes api platform
    description: apis
    termsOfServiceUrl: http://localhost:9000/
    version: 1.0
    contact: allens@sina.com

启动服务并访问: http://localhost:9000/${servletContextPath}/doc.html
在这里插入图片描述

解决无状态登录问题

如果说你的项目是Session模式的方案,那么到这里就结束了。但假如说你是无状态登录的方案,那么就要继续往下看了。无状态登录我们需要把token塞进header中进行请求,那么我们就需要拦截截取登录接口的报文中的token。而且每次请求的时候都要把header中的token拼接上去。

注意只有无状态JWT模式才需要这样做!!!

1. 我们往swagger-bootstrap-ui的右上角加一个按钮,点击出现弹框来配置自动获取登录token

在这里插入图片描述
点击之后是一个弹窗,这个弹窗会要求输入登录接口路径、登录token提取路径以及Token名称。如果走自动获取HeaderJSON是不需要填的。如果想手动塞Header,那么可以使用JSON格式塞TOKEN塞进行去,这种方式不需要配置登录接口路径和登录token提取路径以及token名称。

  • 登录接口路径 你系统的登录接口路径
  • 登录接口提取路径 json path,比如登录接口返回的是{“data”: {token: “xxx”, “other”: “ok”},“msg”: “”},那么登录接口提取路径为:data.token
  • TOKEN名称 接口请求需要携带的Header Token名称
  • Header JSON 有两种情况,如果不填上述三个配置,header JSON就可以手动设置,设置完成之后,每次请求都会自动携带你配置的Header上去。如果配置了上述三个配置,那么每次自动获取完登录的TOKEN之后会自动带出来。

在这里插入图片描述
来看看代码怎么实现的:
doc.html

<div class="sbu-header-right" style="margin-top:12px">
    <div class="col-sm-6">
        <button style="background: #0d5aa7" onclick="showPromoteDefaultHeader()" type="button" class="btn btn-info">通用头设置</button>
    </div>
</div>
2.javascript 脚本部分实现:
function showPromoteDefaultHeader() {

   var test = layer.open({
        type: 1, // page 层类型
        area: ['700px', '500px'],
        title: '配置头信息',
        shade: 0.6, // 遮罩透明度
        shadeClose: true, // 点击遮罩区域,关闭弹层
        maxmin: true, // 允许全屏最小化
        anim: 0, // 0-6 的动画形式,-1 不开启
        content:
            `
            <div class="allens-dialog">
                <div class="element">
                    <span>登录接口路径</span>
                    <input id="allens-dialog-login-interface-name" name="loginInterfaceName" />
                </div>
                <div class="element">
                    <span>登录token提取路径</span>
                    <input id="allens-dialog-json-path" name="jsonPath" />
                </div>
                <div class="element">
                    <span>TOKEN名称</span>
                    <input id="allens-dialog-token-name" name="tokenName" />
                </div>
                <div class="element">
                    <span>Header JSON</span>
                    <textarea id="allens-dialog-header-json" style="width: 100%;" cols="10" rows="8" name="" id=""></textarea>
                </div>
                <button class="btn btn-primary btn-lg" id="allens-dialog-submit">提交</button>
            </div>
            `
    });

    function notEmpty (variable) {
        if (variable === null || variable === undefined || variable === '') {
            // 变量为空
            return false;
        }
        return true;
    }

    var button = document.querySelector('#layui-layer' + test + ' #allens-dialog-submit');
    var loginInterFaceName = document.querySelector('#layui-layer' + test + ' #allens-dialog-login-interface-name');
    var jsonPath = document.querySelector('#layui-layer' + test + ' #allens-dialog-json-path');
    var headerJson = document.querySelector('#layui-layer' + test + ' #allens-dialog-header-json');
    var tokenName = document.querySelector('#layui-layer' + test + ' #allens-dialog-token-name');

    button.onclick = () => {
        if (notEmpty(loginInterFaceName)) {
            localStorage.setItem('LOGININTERFACENAME', loginInterFaceName.value)
        }

        if (notEmpty(jsonPath)) {
            localStorage.setItem('JSONPATH', jsonPath.value)
        }

        if (notEmpty(headerJson)) {
            localStorage.setItem('HEADERJSON', headerJson.value)
        }

        if (notEmpty(tokenName)) {
            localStorage.setItem('TOKENNAME', tokenName.value)
        }

        layer.close(test);
    }

    // text.setAttribute('placeholder', '格式为JSON:{"headerName": "headerValue"}')
    var data = localStorage.getItem('HEADERJSON');
    if (data) {
        const jsonObject = JSON.parse(data);
        const jsonString = JSON.stringify(jsonObject, null, 2);
        headerJson.value = jsonString;
    }
    loginInterFaceName.value = localStorage.getItem('LOGININTERFACENAME')
    jsonPath.value = localStorage.getItem('JSONPATH')
    tokenName.value = localStorage.getItem('TOKENNAME')
}

可以下载下源码看下具体的实现,暂时只支持CSDN下载,后续我会传到github。https://download.csdn.net/download/yh4494/89335880

总结

至此我们讨论的四个swagger的缺点就全部解决了,当然你也可以自己去修改样式,源码都有的怎么该都可以,只要不要有大的bug就行。甚至可以上传到中央仓库给大家使用。

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

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

相关文章

简化跨网文件传输摆渡过程,降低IT人员工作量

在当今数字化时代&#xff0c;IT企业面临着日益增长的数据交换需求。随着网络安全威胁的不断演变&#xff0c;网关隔离成为了保护企业内部网络不受外部威胁的重要手段。然而&#xff0c;隔离的同时&#xff0c;企业也需要在不同网络间安全、高效地传输文件&#xff0c;这就催生…

harmony开发遇到的问题

arkt-no-props-by-indexProperty ‘name’ has no initializer and is not definitely assigned in the constructor.arkts-no-any-unknown typescript 中的报错 Property ‘name’ has no initializer and is not definitely assigned in the construc… ArkTs编译常见错误汇…

全网爆火Remini 粘土滤镜风格,我用ComfyUI一键生成了(保姆级教程)!

一、火爆全网的Remini&#xff01; Remini真的火爆了&#xff01;最近大家的朋友应该都被粘土滤镜刷屏了。 小红书上粘土滤镜、粘土特效的帖子动不动就是几百万浏览量&#xff0c;几千赞。 在有些电商平台上还有人接单&#xff0c;帮忙定制remini粘土风格的照片&#xff01; …

Shell编程之正则表达式与文本处理器

一、正则表达式 之前学习了 Shell 脚本的基础用法&#xff0c;已经可以利用条件判断、循环等语句编辑 Shell 脚本。接下来我们将开始介绍一个很重要的概念——正则表达式&#xff08;RegularExpression&#xff0c;RE&#xff09;。 1.1正则表达式概述 下面先来了解一下正则表…

软件产品测试报告模版分享,获取专业测试报告所需时间和费用

软件产品测试是一个系统性的、全面的质量保障过程&#xff0c;旨在发现和修复软件产品中的缺陷和错误&#xff0c;以确保软件的功能完善、性能卓越、安全可靠。 软件产品测试报告是软件测试过程中的重要文档之一&#xff0c;它主要记录了测试人员对软件产品进行测试的结果和结…

LLM 大模型学习必知必会系列(十三):基于SWIFT的VLLM推理加速与部署实战

LLM 大模型学习必知必会系列(十三)&#xff1a;基于SWIFT的VLLM推理加速与部署实战 1.环境准备 GPU设备: A10, 3090, V100, A100均可. #设置pip全局镜像 (加速下载) pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ #安装ms-swift pip install ms-…

[链表]求中间节点、反转链表、回文链表

一、求链表的中间节点 876. 链表的中间结点 - 力扣&#xff08;LeetCode&#xff09; 快慢指针法: 分别定义两个节点的指针(pSlow和pFast)指向链表的第一个节点&#xff0c;然后两个指针一起往后遍历链表&#xff0c;pFast一次移动两个节点&#xff0c;pSlow一次移动一个节点&…

打工人好用的大模型问答,还需要一款可靠的文档解析工具

如果说三四年前&#xff0c;我们对AI的展望还停留在科幻片的话&#xff0c;现在&#xff0c;通向AI智能的路径已经初现端倪。各行各业的朋友们不约而同地嗅到了大模型带来的生产方式变革气息。 LLM宣布了AI时代的正式到来。 2022年11月30日&#xff0c;ChatGPT发布&#xff0…

牛客NC362 字典序排列【中等 DFS Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/de49cf70277048518314fbdcaba9b42c 解题方法 DFS&#xff0c;剪枝Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回…

SaltStack

SaltStack 官方文档 1.简介 作用&#xff1a;批量处理状态管理&#xff08;配置管理&#xff09;事件驱动&#xff08;通过事件触发操作&#xff09;管理私有云/公有云 yum仓库&#xff1a;http://repo.saltstack.com 安装1.master和minionrpm --import https://repo.saltproj…

政府鼓励社会力量建设气膜体育场馆—轻空间

2023年12月1日&#xff0c;国家体育安全总局发布的《关于政协第十四届全国委员会第一次会议第00374号&#xff08;文体宣传类020号&#xff09;提案答复的函》中指出&#xff0c;2016年和2020年国务院发布的文件中均涉及推动气膜场馆建设及完善装配式建筑相关政策。下一步&…

Git学习篇

目录 使用命令导入项目 使用命令导入项目 1. 使用git init 命令初始化一个新的Git仓库。 git init 是 Git 命令&#xff0c;用于初始化一个新的 Git 仓库。当您想要开始跟踪一个新项目的版本控制时&#xff0c;可以运行 git init 命令来初始化一个空的 Git 仓库。 如果出现以下…

项目文件上传宝塔后只有一个文件内容不同且没有报错该如解决?

一、遇到此类问题不要慌先检查文件是否上传正确&#xff1b; 二、检查文件是否可以在浏览器中正常运行&#xff1b; 三、检查文件是否存在某些不明显的报错&#xff1b; 四、检查此页面的是否存在代码错误&#xff1b; 五、标签链接是否错误&#xff1b; 我所遇到的错误是…

白酒:不同产地白酒的风格特点与比较

云仓酒庄豪迈白酒&#xff0c;作为中国白酒的一部分&#xff0c;其风格特点深受产区的影响。不同产地的白酒&#xff0c;由于自然环境、酿造工艺等因素的差异&#xff0c;形成了各自与众不同的风味和特点。下面让云仓酒庄豪迈白酒来比较一下不同产地白酒的风格特点。 首先&…

使用Python操作Jenkins

大家好&#xff0c;Python作为一种简洁、灵活且功能丰富的编程语言&#xff0c;可以与各种API轻松集成&#xff0c;Jenkins的API也不例外。借助于Python中的python-jenkins模块&#xff0c;我们可以轻松地编写脚本来连接到Jenkins服务器&#xff0c;并执行各种操作&#xff0c;…

香橙派 AIpro开发板开箱测评(代码开源)

前言&#xff1a;有幸能够收到一块梦寐以求的 AI 边缘计算开发板 OrangePi AIpro&#xff0c;非常感谢官方大大给予的宝贵机会。OrangePi AIpro是香橙派官方跟华为昇腾合作的新一代边缘计算产品&#xff0c;其使用华为昇腾 AI 技术路线&#xff0c;搭配集成图像处理器&#xff…

odoo17 hooks使用

odoo17 hooks函数&#xff1a; 1、pre_init_hook 安装引擎开始前执行的函数 2、post_init_hook 安装引擎开始后执行的函数 3、uninstall_hook 卸载执行的函数 以pre_init_hook为例&#xff1a; 1)hooks.py 定义函数&#xff1a; 2&#xff09;init.py引用定义的函数 3)manifest…

RabbitMQ不完整的笔记

同步的不足 1、拓展性差&#xff0c;当要添加功能时&#xff0c;需要在原来的功能代码上做修改&#xff0c;高耦合。 2、性能下降&#xff0c;调用者需要等待服务提供者执行完返回结果后&#xff0c;才能继续向下执行 3、级联失败&#xff0c;由于我们是基于OpenFeign调用交易…

江协科技STM32学习-0 购买套件

前言&#xff1a; 本文是根据哔哩哔哩网站上“江协科技STM32”视频的学习笔记&#xff0c;在这里会记录下江协科技STM32开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技STM32教学视频和链接中的内容。 引用&#xff1a; STM32入门教程-2023版 细致讲…

芋道源码 / yudao-cloud:前端技术架构探索与实践

摘要&#xff1a; 随着企业信息化建设的深入&#xff0c;后台管理系统在企业运营中扮演着至关重要的角色。本文将以芋道源码的yudao-cloud项目为例&#xff0c;深入探讨其前端技术架构的设计思路、关键技术与实现细节&#xff0c;并分享在开发过程中遇到的挑战与解决方案。 一、…