微服务如何集成swagger3

文章目录

  • 引言
  • 一、项目结构
  • 二、顶级pom依赖准备
  • 三、common-swagger模块
  • 四、gateway模块配置
  • 五、结果演示


引言

我们在用springboot开发应用时,经常使用swagger来作为我们的接口文档可视化工具,方便前端同事调用,集成也是比较简单的,那在微服务系统中,如何使用swagger呢?总不能每个服务都集成一次吧,别急,笔者接下来的内容将十分详细的给大家展示如何集成swagger3到我们的系统中。


一、项目结构

在这里插入图片描述
上面是笔者正在开发的AI智能分析平台项目结构(开发中,还有很多模块待开发),我为几个红框标注的微服务模块集成了swagger3,文档的统一访问入口就在gateway模块。

环境如下:

  • JDK17
  • sping boot 版本:3.3.5
  • sping cloud 版本:2023.0.3
  • spring-cloud-alibaba 版本:2023.0.1.2

二、顶级pom依赖准备

上面的 ai-platform-server 根目录下的pom.xml即为我的顶级聚合pom,在其中引入如下依赖

            <!-- SpringDoc OpenAPI 这是网关gateway模块专用,因为它是webflux,不是webmvc--><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webflux-ui</artifactId><version>${springdoc.version}</version></dependency><!-- SpringDoc webmvc --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>${springdoc.version}</version></dependency><dependency><groupId>io.swagger.core.v3</groupId><artifactId>swagger-annotations-jakarta</artifactId><version>${swagger-annotations-jakarta.version}</version></dependency>

这几个依赖的版本如下

        <springdoc.version>2.6.0</springdoc.version><swagger-annotations-jakarta.version>2.2.28</swagger-annotations-jakarta.version>

重点说明

springdoc-openapi-starter-webmvc-ui

这是为Spring MVC(传统Servlet栈)应用程序设计的SpringDoc OpenAPI集成模块。它适用于使用spring-boot-starter-web(基于Servlet)的项目。

主要特点:

  • 专为Spring MVC设计
  • 集成了Swagger UI界面
  • 适用于传统的Spring Boot Web应用程序
  • 基于Servlet API

springdoc-openapi-starter-webflux-ui

这是为Spring WebFlux(响应式栈)应用程序设计的SpringDoc OpenAPI集成模块。它适用于使用spring-boot-starter-webflux(基于Reactive)的项目。

主要特点:

  • 专为Spring WebFlux设计
  • 集成了Swagger UI界面
  • 适用于响应式Spring Boot应用程序
  • 基于Reactive Streams

网关模块基于Spring Cloud Gateway,它使用的是WebFlux响应式编程模型。所以网关gateway模块使用springdoc-openapi-starter-webflux-ui,其他模块使用springdoc-openapi-starter-webmvc-ui。

总结:

  • springdoc-openapi-starter-webmvc-ui:用于传统的基于Servlet的Spring MVC应用程序
  • springdoc-openapi-starter-webflux-ui:用于响应式的基于WebFlux的应用程序

以上的疑问解决掉后,再看具体模块怎么集成的


三、common-swagger模块

在这里插入图片描述

这个模块是干啥的呢,是除了gateway模块以外,其他微服务想要集成swagger需要引入的依赖,为了避免每个模块都引入重复的依赖,同时方便统一管理,我自定义一个模块,把对应的依赖集中到了一起,这个模块中的pom依赖内容如下

 <dependencies><!-- SpringDoc webmvc 非gateway网关模块使用这个 --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId></dependency><dependency><groupId>io.swagger.core.v3</groupId><artifactId>swagger-annotations-jakarta</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>

这个common-swagger模块中定义了一些配置类

在这里插入图片描述


SpringDocProperties

package com.aip.common.swagger.properties;import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;/*** Swagger 配置属性*/
@Setter
@Getter
@ConfigurationProperties(prefix = "springdoc")
public class SpringDocProperties {/*** 网关*/private String gatewayUrl;/*** 文档基本信息*/@NestedConfigurationPropertyprivate InfoProperties info = new InfoProperties();/*** <p>* 文档的基础属性信息* </p>** @see io.swagger.v3.oas.models.info.Info* <p>* 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来*/@Setter@Getterpublic static class InfoProperties {/*** 标题*/private String title = null;/*** 描述*/private String description = null;/*** 联系人信息*/@NestedConfigurationPropertyprivate Contact contact = null;/*** 许可证*/@NestedConfigurationPropertyprivate License license = null;/*** 版本*/private String version = null;}}

SpringDocAutoConfiguration

package com.aip.common.swagger;import com.aip.common.swagger.properties.SpringDocProperties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;import java.util.ArrayList;
import java.util.List;/*** Swagger 文档配置*/
@AutoConfiguration(before = SpringDocConfiguration.class)
@EnableConfigurationProperties(SpringDocProperties.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
public class SpringDocAutoConfiguration {@Bean@ConditionalOnMissingBean(OpenAPI.class)public OpenAPI openApi(SpringDocProperties properties) {return new OpenAPI().components(new Components()// 设置认证的请求头.addSecuritySchemes("apikey", securityScheme())).addSecurityItem(new SecurityRequirement().addList("apikey")).info(convertInfo(properties.getInfo())).servers(servers(properties.getGatewayUrl()));}public SecurityScheme securityScheme() {return new SecurityScheme().type(SecurityScheme.Type.APIKEY).name("Authorization").in(SecurityScheme.In.HEADER).scheme("Bearer");}private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {Info info = new Info();info.setTitle(infoProperties.getTitle());info.setDescription(infoProperties.getDescription());info.setContact(infoProperties.getContact());info.setLicense(infoProperties.getLicense());info.setVersion(infoProperties.getVersion());return info;}public List<Server> servers(String gatewayUrl) {List<Server> serverList = new ArrayList<>();serverList.add(new Server().url(gatewayUrl));return serverList;}
}

resources文件下的那个是自动配置的,这个不用多说了里面就一行

com.aip.common.swagger.SpringDocAutoConfiguration

四、gateway模块配置

pom文件需要引入如下

        <!-- swagger,这里需要引入响应式的 --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webflux-ui</artifactId></dependency>

这个之前的顶级pom已经做好依赖管理了,这里直接引入就行

gateway模块配置要特殊点了,因为它是swagger访问入口,所以会有一些配置和接口访问权限的问题,首先是配置类 SpringDocConfig

package com.aip.gateway.config;import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springdoc.core.properties.AbstractSwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Configuration;import java.util.Set;
import java.util.stream.Collectors;/*** SpringDoc配置类*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "springdoc.api-docs.enabled", matchIfMissing = true)
public class SpringDocConfig implements InitializingBean {@Resourceprivate SwaggerUiConfigProperties swaggerUiConfigProperties;@Resourceprivate DiscoveryClient discoveryClient;/*** 在初始化后调用的方法*/@Overridepublic void afterPropertiesSet() {NotifyCenter.registerSubscriber(new SwaggerDocRegister(swaggerUiConfigProperties, discoveryClient));}
}/*** Swagger文档注册器*/
class SwaggerDocRegister extends Subscriber<InstancesChangeEvent> {@Resourceprivate SwaggerUiConfigProperties swaggerUiConfigProperties;@Resourceprivate DiscoveryClient discoveryClient;//需要排除api的微服务模块应用名称private final static String[] EXCLUDE_ROUTES = new String[]{"ai-platform-auth","ai-platform-gateway"};public SwaggerDocRegister(SwaggerUiConfigProperties swaggerUiConfigProperties, DiscoveryClient discoveryClient) {this.swaggerUiConfigProperties = swaggerUiConfigProperties;this.discoveryClient = discoveryClient;}/*** 事件回调方法,处理InstancesChangeEvent事件** @param event 事件对象*/@Overridepublic void onEvent(InstancesChangeEvent event) {Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> swaggerUrlSet = discoveryClient.getServices().stream().flatMap(serviceId -> discoveryClient.getInstances(serviceId).stream()).filter(instance -> !StringUtils.equalsAny(instance.getServiceId(), EXCLUDE_ROUTES)).map(instance -> {AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();swaggerUrl.setName(instance.getServiceId());//这里是v2还是v3看你的swagger-ui访问地址的请求路径swaggerUrl.setUrl(String.format("/%s/v3/api-docs", instance.getServiceId()));return swaggerUrl;}).collect(Collectors.toSet());swaggerUiConfigProperties.setUrls(swaggerUrlSet);}/*** 订阅类型方法,返回订阅的事件类型** @return 订阅的事件类型*/@Overridepublic Class<? extends Event> subscribeType() {return InstancesChangeEvent.class;}
}

这个类的主要作用是注册各个子服务的接口文档访问url,以及排除哪些服务不需要展示接口文档


再有一个就是接口文档这个访问地址应该排除在我们的请求认证体系之外,比如笔者用的是JWT认证,这里把代码放上仅供参考

package com.aip.gateway.filter;import com.aip.common.constants.CommonConstants;
import com.aip.common.utils.JwtUtils;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Arrays;
import java.util.List;/*** JWT认证过滤器* 网关统一处理JWT认证,避免各服务重复验证*/
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {@Resourceprivate JwtUtils jwtUtils;private final AntPathMatcher pathMatcher = new AntPathMatcher();// 不需要认证的路径private static final List<String> EXCLUDE_PATHS = Arrays.asList("/api/v1/auth/login","/api/v1/auth/refresh","/api/v1/auth/register","/api/v1/auth/send-verification-code","/api/v1/auth/verify-code","/api/v1/auth/forgot-password","/api/v1/auth/reset-password","/actuator/**","/swagger-ui/**","/**/v3/api-docs/**","/health/**","/ping/**","/error");// 不需要租户ID的路径private static final List<String> NO_TENANT_PATHS = Arrays.asList("/api/v1/auth/login","/api/v1/auth/register","/api/v1/auth/forgot-password","/api/v1/auth/reset-password","/actuator/**","/swagger-ui/**","/**/v3/api-docs/**");@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();String path = request.getPath().value();String method = request.getMethod().name();log.debug("网关JWT过滤器处理请求: {} {}", method, path);// 检查是否是需要排除的路径if (isExcludePath(path)) {log.debug("跳过JWT认证: {}", path);return chain.filter(exchange);}// 获取Authorization头String authorization = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);if (!StringUtils.hasText(authorization) || !authorization.startsWith("Bearer ")) {log.warn("请求缺少有效的Authorization头: {}", path);return unauthorizedResponse(exchange, "缺少认证Token");}// 提取TokenString token = authorization.substring(7);// 验证Token格式(这里只做基本验证,详细验证由各服务完成)if (!isValidTokenFormat(token)) {log.warn("Token格式无效: {}", path);return unauthorizedResponse(exchange, "Token格式无效");}// 获取租户IDString tenantId = getTenantId(request);if (!StringUtils.hasText(tenantId) && isTenantRequired(path)) {log.warn("请求缺少租户ID: {}", path);return unauthorizedResponse(exchange, "缺少租户ID");}// 将Token和租户ID添加到请求头,传递给下游服务// 下游服务可以直接使用这些信息,无需再次解析JWTServerHttpRequest modifiedRequest = request.mutate().header(CommonConstants.Security.GATEWAY_TOKEN_HEADER, token).header(CommonConstants.Security.GATEWAY_TENANT_ID_HEADER, tenantId != null ? tenantId : "").header(CommonConstants.Security.GATEWAY_USER_ID_HEADER, extractUserIdFromToken(token)) // 从Token中提取用户ID.header(CommonConstants.Security.GATEWAY_USERNAME_HEADER, extractUsernameFromToken(token)) // 从Token中提取用户名.build();log.debug("JWT认证通过: path={}, tenantId={}, userId={}", path, tenantId, extractUserIdFromToken(token));return chain.filter(exchange.mutate().request(modifiedRequest).build());}@Overridepublic int getOrder() {return -100; // 高优先级}/*** 检查是否为排除路径*/private boolean isExcludePath(String requestPath) {return EXCLUDE_PATHS.stream().anyMatch(pattern -> pathMatcher.match(pattern, requestPath));}/*** 检查是否需要租户ID*/private boolean isTenantRequired(String requestPath) {return NO_TENANT_PATHS.stream().noneMatch(pattern -> pathMatcher.match(pattern, requestPath));}/*** 获取租户ID*/private String getTenantId(ServerHttpRequest request) {// 优先从请求头获取String tenantId = request.getHeaders().getFirst(CommonConstants.Tenant.TENANT_ID_HEADER);if (StringUtils.hasText(tenantId)) {return tenantId;}// 从请求参数获取String query = request.getURI().getQuery();if (StringUtils.hasText(query) && query.contains("tenantId=")) {String[] params = query.split("&");for (String param : params) {if (param.startsWith("tenantId=")) {return param.substring("tenantId=".length());}}}// 从请求路径获取(如:/api/v1/tenant/{tenantId}/...)String path = request.getPath().value();String[] pathParts = path.split("/");for (int i = 0; i < pathParts.length - 1; i++) {if ("tenant".equals(pathParts[i]) && i + 1 < pathParts.length) {return pathParts[i + 1];}}return null;}/*** 验证Token格式(基本验证)*/private boolean isValidTokenFormat(String token) {if (!StringUtils.hasText(token)) {return false;}// JWT Token应该包含两个点,分为三部分String[] parts = token.split("\\.");if (parts.length != 3) {return false;}// 每部分都不应该为空for (String part : parts) {if (!StringUtils.hasText(part)) {return false;}}return true;}/*** 从Token中提取用户ID*/private String extractUserIdFromToken(String token) {return jwtUtils.extractUserIdFromToken(token);}/*** 从Token中提取用户名*/private String extractUsernameFromToken(String token) {return jwtUtils.extractUsernameFromToken(token);}/*** 返回未授权响应*/private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String message) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);exchange.getResponse().getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");String responseBody = String.format("{\"code\":%d,\"message\":\"%s\",\"data\":null}",401, message);return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(responseBody.getBytes())));}
}

其中的 EXCLUDE_PATHS 即为跳过JWT认证的url路径列表,其中就包含了下面两个路径

"/swagger-ui/**",
"/**/v3/api-docs/**"

以上就是集成过程中的主要内容,各个子服务当然也需要一定的配置,就以ai-platform-user这个子模块为例
首先是在该模块的pom下添加该之前创建的 common-swagger依赖

        <!-- Swagger 模块 --><dependency><groupId>com.aip</groupId><artifactId>ai-platform-common-swagger</artifactId></dependency>

然后是配置文件application.yml中配置如下内容

springdoc:# 网关场景下的 API 文档地址(需网关路由支持)gatewayUrl: http://localhost:8080/api/${spring.application.name}api-docs:enabled: truepath: /v3/api-docsswagger-ui:path: /swagger-ui.htmlinfo:title: '用户模块接口文档'version: 1.0.0description: '用户模块接口描述'contact:name: ai-platformurl: https://www.baidu.com

这个gatewayUrl在前面的 SpringDocAutoConfiguration 这个类中有用到读取这个属性

其他的模块如engine、file模块、config模块等都按照这个来配置即可


五、结果演示

按照上面的步骤集成好后,启动你的微服务系统,浏览器访问如下地址

http://localhost:8080/swagger-ui.html

在这里插入图片描述
具体controller的参数和实体类上配套使用swagger3给定的一些参数注解,这个自行去查找资料

对于每个子服务的启动类上可加上以下注解,这样每个服务接口文档就会有标题了,如上图的 ai-platform-user: 用户模块

在这里插入图片描述
到这里,集成swagger3的教程就结束了,诸位如果对微服务架构比较熟悉,按照笔者的教程集成起来应该不是难事

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

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

相关文章

特种行业许可证识别技术:通过图像处理、OCR和结构化提取,实现高效、准确的许可证核验与管理

在酒店、娱乐场所、典当行、危化品经营等特种行业管理中&#xff0c;许可证是合法经营的“生命线”。传统人工核验方式效率低下、易出错&#xff0c;且难以应对海量数据和复杂伪造手段。特种行业许可证识别技术应运而生&#xff0c;成为智慧监管和优化服务的关键工具。特种行业…

零售行业新店网络零接触部署场景下,如何选择SDWAN

一家连锁超市在新疆偏远地区的新店开业申请网络专线&#xff0c;市政审批和架设电线杆的流程花了半个月&#xff0c;成本高企——而它的竞争对手在隔壁新店部署SD-WAN&#xff0c;从开箱到业务上线仅用了10分钟。近年来&#xff0c;零售企业疯狂扩张与下沉市场的趋势愈演愈烈。…

python发布文章和同步文章到社区的工具小脚本

在开发过程中&#xff0c;开发者们往往需要频繁地在社区中分享文章、解决方案以及技术文章来交流与成长。为了简化这一过程&#xff0c;我将为你们介绍两个基于Python脚本的自动化工具&#xff0c;可以帮助你发布文章到开发者社区&#xff0c;提高效率。一、从Markdown文件批量…

23.CNN系列网络思考

为什么是卷积、池化的交替进行? 卷积做的是特征提取,池化做的是一种降采样。 早期学习的主要是:低级特征(边缘、角点、纹理、颜色)。这些特征分布相对局部且空间位置信息很重要。 卷积将这些特征学习出来,然后通过池化降采样,突出其位置信息。然后再卷积进行学习池化后…

MySQL 8.x的性能优化文档整理

一、内存与缓冲优化 # InnoDB缓冲池&#xff08;内存的60%-80%&#xff09; innodb_buffer_pool_size 12G # 核心参数 innodb_buffer_pool_instances 8 # 8核CPU建议分8个实例# 日志缓冲区与Redo日志 innodb_log_buffer_size 256M # 事务日志缓冲区 innodb_log_…

个人使用AI开发的《PlSqlRewrite4GaussDB(PLSQL自动转换工具)1.0.1 BETA》发布

个人使用AI开发的《PlSqlRewrite4GaussDB(PLSQL自动转换工具)1.0.1 BETA》发布 前言 基于语法树的SQL自动改写工具开发系列&#xff08;1&#xff09;-离线安装语法树解析工具antlr4 基于语法树的SQL自动改写工具开发系列&#xff08;2&#xff09;-使用PYTHON进行简单SQL改写…

python的校园研招网系统

前端开发框架:vue.js 数据库 mysql 版本不限 后端语言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 数据库工具&#xff1a;Navicat/SQLyog等都可以 摘要&…

如何高效撰写AI领域学术论文——学习笔记

最开始写的时候最好仿照着顶会来写1. 标题(Title)​标题是论文的"门面"&#xff0c;需要同时具备简洁性和信息量&#xff1a;采用"XX方法 for XXX任务"的标准格式&#xff0c;包含核心创新点和应用领域&#xff0c;避免使用模糊词汇&#xff0c;力求精准&a…

elasticsearch8.12.0安装分词

上篇说到&#xff0c;安装了es后正常运行es分词下载地址从 GitHub Release 下载&#xff08;推荐&#xff09; &#x1f449; https://github.com/medcl/elasticsearch-analysis-ik/releases或https://release.infinilabs.com/analysis-ik/stable/安装&#xff1a;选择与你 ES …

强化学习算法分类与介绍(含权重更新公式)

强化学习算法种类丰富&#xff0c;可按学习目标&#xff08;基于价值 / 基于策略 / 演员 - 评论家&#xff09;、数据使用方式&#xff08;在线 / 离线&#xff09;、是否依赖环境模型&#xff08;无模型 / 有模型&#xff09;等维度分类。以下按核心逻辑梳理常见算法&#xff…

基于STM32F103单片机智能门禁热释人体感应报警设计

1 系统功能介绍 本设计基于 STM32F103C8T6 单片机&#xff0c;通过多种传感器、执行器以及通信模块实现智能门禁和安防报警功能。其主要功能是检测门外人员情况&#xff0c;结合环境光照强度判断是否需要照明&#xff0c;同时结合 GSM 模块在异常情况下发送报警信息&#xff0c…

imx6ull-驱动开发篇33——platform 平台驱动模型

目录 Linux 驱动的分离与分层 驱动的分隔与分离 驱动的分层 platform 平台驱动模型 platform 总线 bus_type 结构体 platform 总线 platform_match函数 platform 驱动 platform_driver 结构体 device_driver 结构体 platform_driver_register 函数 platform_drive…

Win/Linux笔记本合盖不睡眠设置指南

在 笔记本电脑上&#xff0c;当你合上屏幕时&#xff0c;默认系统可能会进入“睡眠”或“休眠”状态。如果你希望合上屏幕时系统继续正常运行&#xff08;例如后台下载、运行程序、远程访问等&#xff09;&#xff0c;需要修改系统的电源设置。 一、以下是 Windows 10 / Windo…

(栈)Leetcode155最小栈+739每日温度

739. 每日温度 - 力扣&#xff08;LeetCode&#xff09; while要把stack的判断放在前面&#xff0c;否则stack[-1]可能报错 class Solution(object):def dailyTemperatures(self, temperatures):""":type temperatures: List[int]:rtype: List[int]""…

【NLP(01)】NLP(自然语言处理)基础

目录NLP基础一、基本概念1. 自然语言处理的基本介绍1.1 与语言相关的概念1.2 为什么使用NLP2. NLP的应用方向2.1 **自然语言理解**2.2 自然语言转换2.3 自然语言生成3. NLP基础概念4. NLP的发展历史5. NLP的基本流程二、NLP中的特征工程0. 引入1. 词向量2. 传统NLP中的特征工程…

Python工程师进阶学习道路分析

本文将分为以下几个核心部分&#xff1a; 心态与基础重塑&#xff1a;从“会用”到“精通”核心语言深度&#xff1a;窥探Python的奥秘编程范式与设计模式&#xff1a;写出优雅的代码并发与异步编程&#xff1a;释放多核时代的威力性能分析与优化&#xff1a;让代码飞起来深入…

IntelliJ IDEA中Maven的“Sync“与“Reload“详解:小白的避坑指南

在IntelliJ IDEA中使用Maven时&#xff0c;Sync All Maven Projects&#xff08;同步&#xff09;和 Reload All Maven Projects&#xff08;重新加载&#xff09;是两个最常用的操作按钮。它们看似相似&#xff0c;实则承担着完全不同的职责。本文将通过通俗易懂的对比和场景分…

网络地址的详细计算说明

IP地址分类与计算 IP地址分5类A类 &#xff1a;0开头&#xff0c;适用于大型网络 B类 &#xff1a;10开头&#xff0c;适用于中型网络 C类 &#xff1a;110开头&#xff0c;适用于小型网络 D类 &#xff1a;1110开头&#xff0c;用于组播 E类 &#xff1a; 1110开头&#xff0c…

人工智能驱动的现代电商前端开发:从基础到智能体验

引言&#xff1a;AI如何重塑电商体验电子商务行业正在经历一场人工智能革命。从个性化推荐到视觉搜索&#xff0c;从智能客服到预测分析&#xff0c;AI技术正在彻底改变用户与电商平台的交互方式。作为前端开发者&#xff0c;了解如何集成AI功能已成为必备技能。本文将带您深入…

mimic数据统计

是否能联通 psql -h 127.0.0.1 -U Shinelon-d mimic --password pgadmin建库 psql -d mimiciv -f mimic-iv/buildmimic/postgres/create.sql 也可以pgadmin直接运行create.sql 导入csv.gz数据 psql -d mimic -v ON_ERROR_STOP1 -v mimic_data_dirH:/mimic-iv-2.2 -f C:\Users\S…