SpringBoot項目架構實戰之“網關zuul搭建“

第三章?網關zuul搭建


前言:

1、主要功能

? ? ? ? zuul主要提供動態路由(內置ribbon實現)和過濾(可以做統一鑒權過濾器、灰度發布過濾器、黑白名單IP過濾器、服務限流過濾器(可以配合Sentinel實現))功能;

2、和Spring Cloud GateWay的區別

? ? ? ? 屬于兩個不同開源組織提供的網關解決方案。spring cloud GateWay使用非阻塞API,內置限流過濾器,支持長連接(比如?websockets),在高并發和后端服務響應慢的場景下比Zuul1的表現要好;zuul無內置限流過濾器,但是可以與Sentinel(是阿里開源的一款高性能的限流框架)集成使用。


一、創建zuul服務module

參考第二章eureka的創建

二、配置文件

1、pom文件配置

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><modelVersion>4.0.0</modelVersion><parent><groupId>com.hq</groupId><artifactId>taxi-online</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>taxi-online-zuul</artifactId><name>taxi-online-zuul</name><description>personal test for zuul</description><url>org.apache</url><packaging>jar</packaging><dependencies><!-- zuul --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><!-- eureka-client --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies>
</project>

2、application.yml文件配置

#服務端口
server:port: 9100
#服務名  
spring:application:name: taxi-online-zuul
#服務注冊    
eureka:client:service-url:defaultZone: http://localhost:9001/eureka/,http://localhost:9002/eureka/enabled: true # 是否啟用Eureka clientinstance:hostname: localhostinstance-id: taxi-online-zuul # 實例id

3、啟動類

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class StartSpringCloudZuul {public static void main(String[] args) {SpringApplication.run(StartSpringCloudZuul.class,args);}
}

三、zuul功能

1、動態路由

2、統一鑒權

3、過濾器

4、灰度發布

5、限流

四、底層源碼

1、啟動原理

類似注冊中心:

1)boot啟動類

boot啟動類上添加@EnableZuulProxy注解;

2)EnableZuulProxy注解

EnableZuulProxy注解中導入ZuulProxyMarkerConfiguration配置類

@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {}
3)ZuulProxyMarkerConfiguration配置類

ZuulProxyMarkerConfiguration配置類往容器添加了一個空的Marker對象,這個對象是作為容器是否添加ZuulProxyAutoConfiguration類的條件,因為ZuulProxyAutoConfiguration類上面加了@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)的注解

@Configuration(proxyBeanMethods = false)
public class ZuulProxyMarkerConfiguration {@Beanpublic Marker zuulProxyMarkerBean() {return new Marker();}class Marker {}}
4)spring.factories文件

zuul包下面的spring.factories文件指定了兩個引入類,只要導包就會被引進去(由SpringFactoriesLoader?進行讀取)--見下方截圖。如果沒有這個文件,boot的自動掃描不會掃描這些外部包的類。這兩個引入類被注入容器的條件分別是:

@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)

@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)

,分別可以通過在啟動類上添加下面注解來引入相應的Marker類:

@EnableZuulProxy

@EnableZuulServer。


@EnableZuulServer、@EnableZuulProxy兩個注解的區別:
@EnableZuulServer - 普通Zuul Server,只支持基本的route與filter功能.
@EnableZuulProxy - 普通Zuul Server+服務發現與熔斷等功能的增強版,具有反向代理功能。
@EnableZuulProxy簡單理解為@EnableZuulServer的增強版,當Zuul與Eureka、Ribbon等組件配合使用時,我們使用@EnableZuulProxy。所以我們做SpringCloud微服務系統一般都是使用@EnableZuulProxy。

5)ZuulServerAutoConfiguration配置類

ZuulServerAutoConfiguration配置類(源碼見下方)主要做的事情有:

1、往容器注入了ZuulServlet,該類是zuul的核心類。

2、往容器注入了 一些前置過濾器和后置過濾器。

3、注入ZuulFilterInitializer類并初始化,初始化邏輯中將所有過濾器交給FilterRegistry類進行管理。FilterRegistry類源碼如下:

/*** @author mhawthorne*/
public class FilterRegistry {private static final FilterRegistry INSTANCE = new FilterRegistry();public static final FilterRegistry instance() {return INSTANCE;}private final ConcurrentHashMap<String, ZuulFilter> filters = new ConcurrentHashMap<String, ZuulFilter>();private FilterRegistry() {}public ZuulFilter remove(String key) {return this.filters.remove(key);}public ZuulFilter get(String key) {return this.filters.get(key);}public void put(String key, ZuulFilter filter) {this.filters.putIfAbsent(key, filter);}public int size() {return this.filters.size();}public Collection<ZuulFilter> getAllFilters() {return this.filters.values();}}

ZuulServerAutoConfiguration源碼如下(有刪減):

/*** @author Spencer Gibb* @author Dave Syer* @author Biju Kunjummen*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ ZuulProperties.class })
@ConditionalOnClass({ ZuulServlet.class, ZuulServletFilter.class })
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)
// Make sure to get the ServerProperties from the same place as a normal web app would
// FIXME @Import(ServerPropertiesAutoConfiguration.class)
public class ZuulServerAutoConfiguration {@Bean@ConditionalOnMissingBean(name = "zuulServlet")@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false",matchIfMissing = true)public ServletRegistrationBean zuulServlet() {ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(new ZuulServlet(), this.zuulProperties.getServletPattern());// The whole point of exposing this servlet is to provide a route that doesn't// buffer requests.servlet.addInitParameter("buffer-requests", "false");return servlet;}// pre filters@Beanpublic ServletDetectionFilter servletDetectionFilter() {return new ServletDetectionFilter();}@Bean@ConditionalOnMissingBeanpublic FormBodyWrapperFilter formBodyWrapperFilter() {return new FormBodyWrapperFilter();}@Bean@ConditionalOnMissingBeanpublic DebugFilter debugFilter() {return new DebugFilter();}@Bean@ConditionalOnMissingBeanpublic Servlet30WrapperFilter servlet30WrapperFilter() {return new Servlet30WrapperFilter();}// post filters@Beanpublic SendResponseFilter sendResponseFilter(ZuulProperties properties) {return new SendResponseFilter(zuulProperties);}@Beanpublic SendErrorFilter sendErrorFilter() {return new SendErrorFilter();}@Beanpublic SendForwardFilter sendForwardFilter() {return new SendForwardFilter();}//@Configuration(proxyBeanMethods = false)protected static class ZuulFilterConfiguration {@Autowiredprivate Map<String, ZuulFilter> filters;@Beanpublic ZuulFilterInitializer zuulFilterInitializer(CounterFactory counterFactory,TracerFactory tracerFactory) {FilterLoader filterLoader = FilterLoader.getInstance();FilterRegistry filterRegistry = FilterRegistry.instance();return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory,filterLoader, filterRegistry);}}
}
6)ZuulProxyAutoConfiguration配置類

繼承了ZuulServerAutoConfiguration類,是ZuulServerAutoConfiguration的增強版,在ZuulServerAutoConfiguration的基礎上增加eureka、ribbon、hystrix等功能。源碼如下:

/*** @author Spencer Gibb* @author Dave Syer* @author Biju Kunjummen*/
@Configuration(proxyBeanMethods = false)
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,HttpClientConfiguration.class })
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {// pre filters@Bean@ConditionalOnMissingBean(PreDecorationFilter.class)public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator,ProxyRequestHelper proxyRequestHelper) {return new PreDecorationFilter(routeLocator,this.server.getServlet().getContextPath(), this.zuulProperties,proxyRequestHelper);}// route filters@Bean@ConditionalOnMissingBean(RibbonRoutingFilter.class)public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,RibbonCommandFactory<?> ribbonCommandFactory) {RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory,this.requestCustomizers);return filter;}@Bean@ConditionalOnMissingBean({ SimpleHostRoutingFilter.class,CloseableHttpClient.class })public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper,ZuulProperties zuulProperties,ApacheHttpClientConnectionManagerFactory connectionManagerFactory,ApacheHttpClientFactory httpClientFactory) {return new SimpleHostRoutingFilter(helper, zuulProperties,connectionManagerFactory, httpClientFactory);}@Bean@ConditionalOnMissingBean({ SimpleHostRoutingFilter.class })public SimpleHostRoutingFilter simpleHostRoutingFilter2(ProxyRequestHelper helper,ZuulProperties zuulProperties, CloseableHttpClient httpClient) {return new SimpleHostRoutingFilter(helper, zuulProperties, httpClient);}@Bean@ConditionalOnMissingBean(ServiceRouteMapper.class)public ServiceRouteMapper serviceRouteMapper() {return new SimpleServiceRouteMapper();}@Configuration(proxyBeanMethods = false)@ConditionalOnMissingClass("org.springframework.boot.actuate.health.Health")protected static class NoActuatorConfiguration {@Beanpublic ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {ProxyRequestHelper helper = new ProxyRequestHelper(zuulProperties);return helper;}}@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Health.class)protected static class EndpointConfiguration {@Autowired(required = false)private HttpTraceRepository traces;@Bean@ConditionalOnAvailableEndpointpublic RoutesEndpoint routesEndpoint(RouteLocator routeLocator) {return new RoutesEndpoint(routeLocator);}@ConditionalOnAvailableEndpoint@Beanpublic FiltersEndpoint filtersEndpoint() {FilterRegistry filterRegistry = FilterRegistry.instance();return new FiltersEndpoint(filterRegistry);}@Beanpublic ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {TraceProxyRequestHelper helper = new TraceProxyRequestHelper(zuulProperties);if (this.traces != null) {helper.setTraces(this.traces);}return helper;}}}

2、核心類ZuulServlet

1)作用

調度不同階段的filters,處理異常。所有的Request都要經過ZuulServlet的處理。三個核心的方法preRoute(),route(), postRoute(),zuul對request處理邏輯都在這三個方法里。源碼如下:

public class ZuulServlet extends HttpServlet {private static final long serialVersionUID = -3374242278843351500L;private ZuulRunner zuulRunner;@Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);String bufferReqsStr = config.getInitParameter("buffer-requests");boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false;zuulRunner = new ZuulRunner(bufferReqs);}@Overridepublic void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {try {init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);// Marks this request as having passed through the "Zuul engine", as opposed to servlets// explicitly bound in web.xml, for which requests will not have the same data attachedRequestContext context = RequestContext.getCurrentContext();context.setZuulEngineRan();try {preRoute();} catch (ZuulException e) {error(e);postRoute();return;}try {route();} catch (ZuulException e) {error(e);postRoute();return;}try {postRoute();} catch (ZuulException e) {error(e);return;}} catch (Throwable e) {error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));} finally {RequestContext.getCurrentContext().unset();}}/*** executes "post" ZuulFilters** @throws ZuulException*/void postRoute() throws ZuulException {zuulRunner.postRoute();}/*** executes "route" filters** @throws ZuulException*/void route() throws ZuulException {zuulRunner.route();}/*** executes "pre" filters** @throws ZuulException*/void preRoute() throws ZuulException {zuulRunner.preRoute();}/*** initializes request** @param servletRequest* @param servletResponse*/void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {zuulRunner.init(servletRequest, servletResponse);}/*** sets error context info and executes "error" filters** @param e*/void error(ZuulException e) {RequestContext.getCurrentContext().setThrowable(e);zuulRunner.error();}
}
2)調用鏈路:

以preRoute()為例:

1、ZuulServlet——》ZuulRunner,源碼見四-2-1);

2、ZuulRunner——》FilterProcessor,源碼如下:

public void preRoute() throws ZuulException {FilterProcessor.getInstance().preRoute();}

3、FilterProcessor調自己的runFilters方法,涉及調用其他類:

FilterProcessor——》FilterLoader,源碼見下方4

實際執行過濾器邏輯是在調用自己processZuulFilter方法中的下方的代碼邏輯。

ZuulFilterResult result = filter.runFilter();(runFilter里面調用了子類的run方法)

public void preRoute() throws ZuulException {try {runFilters("pre");} catch (ZuulException e) {throw e;} catch (Throwable e) {throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());}}/*** runs all filters of the filterType sType/ Use this method within filters to run custom filters by type** @param sType the filterType.* @return* @throws Throwable throws up an arbitrary exception*/public Object runFilters(String sType) throws Throwable {if (RequestContext.getCurrentContext().debugRouting()) {Debug.addRoutingDebug("Invoking {" + sType + "} type filters");}boolean bResult = false;List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);if (list != null) {for (int i = 0; i < list.size(); i++) {ZuulFilter zuulFilter = list.get(i);Object result = processZuulFilter(zuulFilter);if (result != null && result instanceof Boolean) {bResult |= ((Boolean) result);}}}return bResult;}public Object processZuulFilter(ZuulFilter filter) throws ZuulException {RequestContext ctx = RequestContext.getCurrentContext();boolean bDebug = ctx.debugRouting();final String metricPrefix = "zuul.filter-";long execTime = 0;String filterName = "";try {long ltime = System.currentTimeMillis();filterName = filter.getClass().getSimpleName();RequestContext copy = null;Object o = null;Throwable t = null;if (bDebug) {Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);copy = ctx.copy();}ZuulFilterResult result = filter.runFilter();ExecutionStatus s = result.getStatus();execTime = System.currentTimeMillis() - ltime;switch (s) {case FAILED:t = result.getException();ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);break;case SUCCESS:o = result.getResult();ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);if (bDebug) {Debug.addRoutingDebug("Filter {" + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + "} Execution time = " + execTime + "ms");Debug.compareContextState(filterName, copy);}break;default:break;}if (t != null) throw t;usageNotifier.notify(filter, s);return o;} catch (Throwable e) {if (bDebug) {Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + e.getMessage());}usageNotifier.notify(filter, ExecutionStatus.FAILED);if (e instanceof ZuulException) {throw (ZuulException) e;} else {ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);throw ex;}}}

4、FilterLoader——》filterRegistry,通過filterRegistry拿到所有的過濾器并篩選返回符合要求類型的集合并按優先級排序,放入緩存。

 /*** Returns a list of filters by the filterType specified** @param filterType* @return a List<ZuulFilter>*/public List<ZuulFilter> getFiltersByType(String filterType) {List<ZuulFilter> list = hashFiltersByType.get(filterType);if (list != null) return list;list = new ArrayList<ZuulFilter>();Collection<ZuulFilter> filters = filterRegistry.getAllFilters();for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {ZuulFilter filter = iterator.next();if (filter.filterType().equals(filterType)) {list.add(filter);}}Collections.sort(list); // sort by priorityhashFiltersByType.putIfAbsent(filterType, list);return list;}

5、FilterRegistry調用自己的getAllFilters方法返回所有的過濾器

private final ConcurrentHashMap<String, ZuulFilter> filters = new ConcurrentHashMap<String, ZuulFilter>();
public Collection<ZuulFilter> getAllFilters() {return this.filters.values();}

3、頂級抽象父類ZuulFilter

所有的過濾器都應繼承該抽象類,重寫shouldFilter、filterType、filterOrder、run方法。

shouldFilter:該過濾器是否生效 ?返回true:有效;false:無效

filterType:指定過濾器類型,FilterConstants包含下面圖中幾種類型:filterOrder:在過濾器鏈中的順序,返回值越小越靠前;

run:過濾器的邏輯。

public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {abstract boolean shouldFilter();abstract Object run() throws ZuulException;abstract public String filterType();/*** filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not* important for a filter. filterOrders do not need to be sequential.** @return the int order of a filter*/abstract public int filterOrder();public int compareTo(ZuulFilter filter) {return Integer.compare(this.filterOrder(), filter.filterOrder());}
}

4、過濾器熱加載

參考下方博客:

zuul 1.x 源碼解析 (結合本人過去2年工作經歷整理,超詳細)_zuulproxyautoconfiguration.predecorationfilter-CSDN博客文章瀏覽閱讀428次,點贊6次,收藏4次。zuul 1.x 源碼解析,全程斷點調試,超詳細(結合本人過去2年工作經歷,花了1周時間整理并記錄)_zuulproxyautoconfiguration.predecorationfilterhttps://blog.csdn.net/qq_22270363/article/details/132052278

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/44653.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/44653.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/44653.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學會創建虛擬網卡

此電腦-----管理 一直點擊下一頁 選擇網絡適配器 選擇Microsoft----Microsoft KM-TEST環回適配器 然后點擊下一頁 完成的界面如下&#xff1a; 手動改IP

Git分支結構

目錄 1. 線性分支結構 2. 分叉與合并結構 3. 分支與標簽的關系 4. 并行開發與分支管理策略 測試&#xff08;本機系統為Rocky_linux9.4&#xff09; 合并失敗解決 刪除分支 刪除本地分支 刪除遠程分支 Git 中的分支結構是版本控制中非常重要的概念之一&#xff0c;它描…

政安晨:【Keras機器學習示例演繹】(五十四)—— 使用神經決策森林進行分類

目錄 導言 數據集 設置 準備數據 定義數據集元數據 為訓練和驗證創建 tf_data.Dataset 對象 創建模型輸入 輸入特征編碼 深度神經決策樹 深度神經決策森林 實驗 1&#xff1a;訓練決策樹模型 實驗 2&#xff1a;訓練森林模型 政安晨的個人主頁&#xff1a;政安晨 歡…

Python | Leetcode Python題解之第228題匯總區間

題目&#xff1a; 題解&#xff1a; class Solution:def summaryRanges(self, nums: List[int]) -> List[str]:def f(i: int, j: int) -> str:return str(nums[i]) if i j else f{nums[i]}->{nums[j]}i 0n len(nums)ans []while i < n:j iwhile j 1 < n …

Codeforces Round #956 (Div. 2) and ByteRace 2024 E. I Love Balls(概率期望)

題目 思路來源 官方題解 題解 特殊球不會改變普通球的順序&#xff0c;所以都是alice拿一半里較多的部分 n-k1一半向上取整就是(n-k2)/2&#xff0c;同理n-k個一般向上取整(n-k1)/2 每個特殊球獨立地來看&#xff0c;在每個空隙的概率相同 所以分別統計特殊球和非特殊球的…

LLM+Agent技術

&#x1f4a1; Agent可以理解為某種能自主理解、規劃決策、執行復雜任務的智能體。Agent 是讓 LLM 具備目標實現的能力&#xff0c;并通過自我激勵循環來實現這個目標。它可以是并行的&#xff08;同時使用多個提示&#xff0c;試圖解決同一個目標&#xff09;和單向的&#xf…

14-63 劍和詩人37 - 分布式系統中的數據訪問設計

?? 在分布式系統中,跨服務和數據庫提供統一、可靠的數據訪問至關重要,但又極具挑戰性。微服務和數據庫的拓撲結構為分布、緩存、復制和同步帶來了復雜性。 讓我們探索有助于解決這些復雜性并簡化構建強大、高性能分布式系統的常見數據訪問模式。 概述 我們將通過示例介紹…

探索AI數字人的開源解決方案

引言 隨著人工智能&#xff08;AI&#xff09;技術的迅猛發展&#xff0c;AI數字人&#xff08;或虛擬人&#xff09;正逐漸走進我們的生活&#xff0c;從虛擬助手到虛擬主播&#xff0c;再到虛擬客服&#xff0c;AI數字人在各個領域展現出巨大的潛力。開源解決方案的出現&…

解碼生命語言:Transformer模型在基因序列分析的突破性應用

解碼生命語言&#xff1a;Transformer模型在基因序列分析的突破性應用 基因序列分析是現代生物學和醫學研究的基石&#xff0c;它涉及對DNA或RNA序列的識別、比較和解釋。隨著深度學習技術的興起&#xff0c;特別是Transformer模型的出現&#xff0c;基因序列分析領域迎來了新…

[vite] Pre-transform error: Cannot find package pnpm路徑過長導致運行報錯

下了套vue3的代碼&#xff0c;執行pnpm install初始化&#xff0c;使用vite啟動&#xff0c;啟動后訪問就會報錯 報錯信息 ERROR 16:40:53 [vite] Pre-transform error: Cannot find package E:\work\VSCodeProjectWork\jeecg\xxxxxxxxx-next\xxxxxxxxx-next-jeecgBoot-vue3\…

AC修煉計劃(AtCoder Regular Contest 180) A~C

A - ABA and BAB A - ABA and BAB (atcoder.jp) 這道題我一開始想復雜了&#xff0c;一直在想怎么dp&#xff0c;沒注意到其實是個很簡單的規律題。 我們可以發現我們住需要統計一下類似ABABA這樣不同字母相互交替的所有子段的長度&#xff0c;而每個字段的的情況有&#xff…

Postman中的API安全堡壘:全面安全性測試指南

&#x1f6e1;? Postman中的API安全堡壘&#xff1a;全面安全性測試指南 在當今的數字化世界中&#xff0c;API安全性是保護數據和系統不可或缺的一環。Postman作為API開發和測試的領先工具&#xff0c;提供了多種功能來幫助開發者進行API安全性測試。本文將深入探討如何在Po…

交互式AI的新紀元:Transformer模型的革新應用

交互式AI的新紀元&#xff1a;Transformer模型的革新應用 隨著人工智能技術的不斷進步&#xff0c;交互式人工智能&#xff08;AI&#xff09;逐漸成為提升用戶體驗的關鍵技術。Transformer模型&#xff0c;以其卓越的處理序列數據的能力&#xff0c;已成為推動交互式AI發展的…

利用 AI 解放雙手:把“賈維斯”帶進現實 | 開源專題 No.64

Significant-Gravitas/AutoGPT Stars: 160k License: MIT AutoGPT 是開源 AI 代理生態系統的核心工具包。 提供構建、測試和委托 AI 代理的工具。AutoGPT 處于 AI 創新前沿&#xff0c;提供文檔、貢獻指南以及快速開始創建自己的代理。包含強大的組件如 Forge 和 Benchmark&…

【教程】Hexo 部署到 Github Page 后,自定義域名失效的問題

目錄 前言&問題描述解決方案細節 前言&問題描述 近期給 Github Page 上托管的靜態網站映射了自定義域名&#xff08;aiproducthome.top&#xff09;&#xff0c;之后發現每次更新并部署 hexo 到 Github Page &#xff08;hexo d&#xff09;后就會出現自定義域名失效的…

探索SQL Server查詢優化的奧秘:數據庫查詢優化器深度解析

探索SQL Server查詢優化的奧秘&#xff1a;數據庫查詢優化器深度解析 在數據庫管理的世界里&#xff0c;查詢優化器是確保查詢效率的關鍵組件。SQL Server的查詢優化器采用先進的算法&#xff0c;將用戶的SQL查詢轉換成高效的執行計劃。本文將深入探討SQL Server查詢優化器的工…

高效利用iCloud:全面指南與技術深度解析

引言 在數字化時代&#xff0c;數據的同步、備份和跨設備協作變得尤為重要。蘋果公司的iCloud服務憑借其強大的云存儲和同步功能&#xff0c;為用戶提供了一個無縫的數據管理解決方案。本文將全面介紹如何高效利用iCloud&#xff0c;幫助用戶更好地管理數據、提升工作效率&…

Python如何進行游戲開發?

使用Python進行游戲開發可以通過以下幾個步驟來實現。Python有多個游戲開發框架和庫&#xff0c;最常用的是Pygame。下面是一個簡要的指南&#xff0c;介紹如何使用Pygame進行游戲開發。 安裝Pygame 首先&#xff0c;你需要安裝Pygame庫。你可以使用pip進行安裝&#xff1a; …

前端如何去看藍湖

首先加入團隊&#xff0c;在內容中我們可以看到點擊圖片&#xff0c;右邊出現的圖 包含了像素甚至有代碼&#xff0c;我們可以參考這個代碼。 那么在使用之前我們需要調整好像素&#xff0c;例如我們的像素寬為375&#xff0c;不用去管高&#xff0c;然后這個寬度我們可以去自…

QT——Excel實現自繪區域選擇邊框

文章目錄 一、自繪區域邊框1.1、效果展示2.2、問題整理2.2.1、重繪單元格選擇區2.2.2、選擇區域的大小 一、自繪區域邊框 1.1、效果展示 單選 多選 2.2、問題整理 2.2.1、重繪單元格選擇區 誤區: 繼承QStyledItemDelegate重寫paint,測試發現只能在單元格內繪制。 通過繼…