golang底層深入_帶有Golang的GraphQL:從基礎到高級的深入研究

golang底層深入

by Ridham Tarpara

由里德姆·塔帕拉(Ridham Tarpara)

帶有Golang的GraphQL:從基礎到高級的深入研究 (GraphQL with Golang: A Deep Dive From Basics To Advanced)

GraphQL has become a buzzword over the last few years after Facebook made it open-source. I have tried GraphQL with the Node.js, and I agree with all the buzz about the advantages and simplicity of GraphQL.

在Facebook開源之后的最近幾年里,GraphQL已經成為流行語。 我已經使用Node.js嘗試了GraphQL,并且我對GraphQL的優點和簡單性一事都表示贊同。

So what is GraphQL? This is what the official GraphQL definition says:

那么,GraphQL是什么? 官方的GraphQL定義是這樣的:

GraphQL is a query language for APIs and runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
GraphQL是用于API和運行時的查詢語言,用于使用現有數據來完成這些查詢。 GraphQL為您的API中的數據提供完整且易于理解的描述,使客戶能夠準確地詢問他們所需的內容,僅此而已,使隨著時間的推移更易于開發API并啟用強大的開發人員工具。

I recently switched to Golang for a new project I’m working on (from Node.js) and I decided to try GraphQL with it. There are not many library options with Golang but I have tried it with Thunder, graphql, graphql-go, and gqlgen. And I have to say that gqlgen is winning among all the libraries I have tried.

我最近切換到Golang從事我正在研究的新項目(來自Node.js),我決定嘗試使用GraphQL。 Golang的庫選項不多,但我已使用Thunder , graphql , graphql-go和gqlgen對其進行了嘗試 。 我不得不說, gqlgen在我嘗試過的所有庫中勝出。

gqlgen is still in beta with latest version 0.7.2 at the time of writing this article, and it’s rapidly evolving. You can find their road-map here. And now 99designs is officially sponsoring them, so we will see even better development speed for this awesome open source project. vektah and neelance are major contributors, and neelance also wrote graphql-go.

在撰寫本文時, gqlgen仍處于beta版,最新版本為0.7.2 ,并且它正在Swift發展。 您可以在此處找到他們的路線圖。 現在99designs正式贊助了它們,因此我們將為這個很棒的開源項目看到更快的開發速度。 vektah和neelance是主要貢獻者, neelance還寫了graphql-go 。

So let’s dive into the library semantics assuming you have basic GraphQL knowledge.

因此,假設您具有基本的GraphQL知識,讓我們深入研究庫語義。

強調 (Highlights)

As their headline states,

作為他們的標題,

This is a library for quickly creating strictly typed GraphQL servers in Golang.
這是一個用于在Golang中快速創建嚴格類型的GraphQL服務器的庫。

I think this is the most promising thing about the library: you will never see map[string]interface{} here, as it uses a strictly typed approach.

我認為這是庫中最有前途的事情:在這里您永遠不會看到map[string]interface{} ,因為它使用嚴格類型化的方法。

Apart from that, it uses a Schema first Approach: so you define your API using the graphql Schema Definition Language. This has its own powerful code generation tools which will auto-generate all of your GraphQL code and you will just need to implement the core logic of that interface method.

除此之外,它使用Schema first方法 :因此,您可以使用graphql Schema Definition Language定義API。 它具有自己強大的代碼生成工具,可以自動生成所有GraphQL代碼,您只需要實現該接口方法的核心邏輯即可。

I have divided this article into two phases:

我將本文分為兩個階段:

  • The basics: Configuration, Mutations, Queries, and Subscription

    基礎知識:配置,突變,查詢和訂閱
  • The advanced: Authentication, Dataloaders, and Query Complexity

    高級:身份驗證,數據加載器和查詢復雜性

階段1:基礎知識-配置,變異,查詢和訂閱 (Phase 1: The Basics - Configuration, Mutations, Queries, and Subscriptions)

We will use a video publishing site as an example in which a user can publish a video, add screenshots, add a review, and get videos and related videos.

我們將以視頻發布網站為例,用戶可以在其中發布視頻,添加屏幕截圖,添加評論以及獲取視頻和相關視頻。

mkdir -p $GOPATH/src/github.com/ridhamtarpara/go-graphql-demo/

Create the following schema in the project root:

在項目根目錄中創建以下架構:

Here we have defined our basic models and one mutation to publish new videos, and one query to get all videos. You can read more about the graphql schema here. We have also defined one custom type (scalar), as by default graphql has only 5 scalar types that include Int, Float, String, Boolean and ID.

在這里,我們定義了基本模型,定義了一種版本來發布新視頻,并定義了一種查詢來獲取所有視頻。 您可以在此處閱讀有關graphql 模式的更多信息。 我們還定義了一種自定義類型(標量),因為默認情況下graphql只有5種標量類型 ,包括Int,Float,String,Boolean和ID。

So if you want to use custom type, then you can define a custom scalar in schema.graphql (like we have defined Timestamp) and provide its definition in code. In gqlgen, you need to provide marshal and unmarshal methods for all custom scalars and map them to gqlgen.yml.

因此,如果要使用自定義類型,則可以在schema.graphql定義自定義標量(就像我們已經定義了Timestamp ),并在代碼中提供其定義。 在gqlgen中,您需要為所有自定義標量提供編組和解編方法,并將它們映射到gqlgen.yml

Another major change in gqlgen in the last version is that they have removed the dependency on compiled binaries. So add the following file to your project under scripts/gqlgen.go.

最新版本中gqlgen的另一個主要變化是,它們刪除了對已編譯二進制文件的依賴。 因此,將以下文件添加到腳本/gqlgen.go下的項目中。

and initialize dep with:

并使用以下命令初始化dep:

dep init

Now it’s time to take advantage of the library’s codegen feature which generates all the boring (but interesting for a few) skeleton code.

現在是時候利用該庫的codegen功能,該功能生成所有無聊的(但有一些有趣的)骨架代碼。

go run scripts/gqlgen.go init

which will create the following files:

這將創建以下文件:

gqlgen.yml — Config file to control code generation.generated.go — The generated code which you might not want to see.models_gen.go — All the models for input and type of your provided schema.resolver.go — You need to write your implementations.server/server.go — entry point with an http.Handler to start the GraphQL server.

gqlgen.yml —用于控制代碼生成的配置文件。 created.go —您可能不想看到的生成的代碼。 models_gen.go —用于提供的模式的輸入和類型的所有模型。 resolver.go-您需要編寫實現。 server / server.go —帶有http.Handler的入口點,用于啟動GraphQL服務器。

Let’s have a look at one of the generated models of the Video type:

讓我們看一下Video類型的生成模型之一:

Here, as you can see, ID is defined as a string and CreatedAt is also a string. Other related models are mapped accordingly, but in the real world you don’t want this — if you are using any SQL data type you want your ID field as int or int64, depending on your database.

如您所見,此處ID定義為字符串,CreatedAt也是字符串。 其他相關的模型也進行了相應的映射,但是在現實世界中,您不需要這樣做-如果您使用任何SQL數據類型,則希望ID字段為int或int64,具體取決于數據庫。

For example I am using PostgreSQL for demo so of course I want ID as an int and CreatedAt as a time.Time. So we need to define our own model and instruct gqlgen to use our model instead of generating a new one.

例如,我正在使用PostgreSQL進行演示,因此當然希望ID為int且CreatedAt為time.Time 。 因此,我們需要定義自己的模型,并指示gqlgen使用我們的模型,而不是生成新模型。

and update gqlgen to use these models like this:

并更新gqlgen以使用以下模型:

So, the focal point is the custom definitions for ID and Timestamp with the marshal and unmarshal methods and their mapping in a gqlgen.yml file. Now when the user provides a string as ID, UnmarshalID will convert a string into an int. While sending the response, MarshalID will convert int to string. The same goes for Timestamp or any other custom scalar you define.

因此,重點是具有marshal和unmarshal方法的ID和Timestamp的自定義定義,以及它們在gqlgen.yml文件中的映射。 現在,當用戶提供字符串作為ID時,UnmarshalID會將字符串轉換為int。 發送響應時,MarshalID會將int轉換為字符串。 時間戳或您定義的任何其他自定義標量也是如此。

Now it’s time to implement real logic. Open resolver.go and provide the definition to mutation and queries. The stubs are already auto-generated with a not implemented panic statement so let’s override that.

現在該實現真正的邏輯了。 打開resolver.go并提供突變和查詢的定義。 存根已經通過未實現的panic語句自動生成,因此我們將其覆蓋。

and hit the mutation:

并擊中突變:

Ohh it worked….. but wait, why is my user empty ?? So here there is a similar concept like lazy and eager loading. As graphQL is extensible, you need to define which fields you want to populate eagerly and which ones lazily.

哦,行得通……..但是,為什么我的用戶為空? 因此,這里有類似的概念,例如延遲加載和渴望加載。 由于graphQL是可擴展的,因此您需要定義要急切填充的字段和懶散地填充的字段。

I have created this golden rule for my organization team working with gqlgen:

我為與gqlgen合作的組織團隊創建了這一黃金法則:

Don’t include the fields in a model which you want to load only when requested by the client.

不要僅在客戶要求時才在要加載的模型中包括字段。

For our use-case, I want to load Related Videos (and even users) only if a client asks for those fields. But as we have included those fields in the models, gqlgen will assume that you will provide those values while resolving video — so currently we are getting an empty struct.

對于我們的用例,僅當客戶要求這些字段時,我才想加載相關視頻(甚至用戶)。 但是,由于我們已將這些字段包括在模型中,因此gqlgen會假設您在解析視頻時會提供這些值-因此當前我們得到的是一個空結構。

Sometimes you need a certain type of data every time, so you don’t want to load it with another query. Rather you can use something like SQL joins to improve performance. For one use-case (not included in the article), I needed video metadata every time with the video which is stored in a different place. So if I loaded it when requested, I would need another query. But as I knew my requirements (that I need it everywhere on the client side), I preferred it to load eagerly to improve the performance.

有時您每次都需要某種類型的數據,因此您不想使用其他查詢來加載它。 而是可以使用諸如SQL連接之類的方法來提高性能。 對于一個用例(本文未包含),每次將視頻存儲在不同位置時,我都需要視頻元數據。 因此,如果我在請求時加載了它,則需要另一個查詢。 但是,由于我知道自己的要求(在客戶端的任何地方都需要它),所以我希望它能夠熱切地加載以提高性能。

So let’s rewrite the model and regenerate the gqlgen code. For the sake of simplicity, we will only define methods for the user.

因此,讓我們重寫模型并重新生成gqlgen代碼。 為了簡單起見,我們將只為用戶定義方法。

So we have added UserID and removed User struct and regenerated the code:

因此,我們添加了UserID并刪除了User結構并重新生成了代碼:

go run scripts/gqlgen.go -v

This will generate the following interface methods to resolve the undefined structs and you need to define those in your resolver:

這將生成以下接口方法來解析未定義的結構,您需要在解析器中定義它們:

And here is our definition:

這是我們的定義:

Now the result should look something like this:

現在結果應如下所示:

So this covers the very basics of graphql and should get you started. Try a few things with graphql and the power of Golang! But before that, let’s have a look at subscription which should be included in the scope of this article.

因此,這涵蓋了graphql的基礎知識,應該可以幫助您入門。 嘗試使用graphql和Golang的強大功能! 但是在此之前,讓我們看一下應該包含在本文范圍內的訂閱。

訂閱內容 (Subscriptions)

Graphql provides subscription as an operation type which allows you to subscribe to real tile data in GraphQL. gqlgen provides web socket-based real-time subscription events.

Graphql提供訂閱作為一種操作類型,使您可以訂閱GraphQL中的實際切片數據。 gqlgen提供基于Web套接字的實時訂閱事件。

You need to define your subscription in the schema.graphql file. Here we are subscribing to the video publishing event.

您需要在schema.graphql文件中定義您的訂閱。 在這里,我們正在訂閱視頻發布活動。

Regenerate the code by running: go run scripts/gqlgen.go -v.

通過運行以下命令來重新生成代碼: go run scripts/gqlgen.go -v

As explained earlier, it will make one interface in generated.go which you need to implement in your resolver. In our case, it looks like this:

如前所述,它將在generate.go中創建一個接口,您需要在解析器中實現該接口。 在我們的例子中,它看起來像這樣:

Now, you need to emit events when a new video is created. As you can see on line 23 we have done that.

現在,您需要在創建新視頻時發出事件。 如您在第23行所看到的,我們已經做到了。

And it’s time to test the subscription:

現在可以測試訂閱了:

GraphQL comes with certain advantages, but everything that glitters is not gold. You need to take care of a few things like authorizations, query complexity, caching, N+1 query problem, rate limiting, and a few more issues — otherwise it will put you in performance jeopardy.

GraphQL具有某些優勢,但所有閃閃發光的東西都不是金子。 您需要注意一些事情,例如授權,查詢復雜性,緩存,N + 1查詢問題,速率限制以及其他一些問題,否則將使您陷入性能危機。

階段2:高級-身份驗證,數據加載器和查詢復雜性 (Phase 2: The advanced - Authentication, Dataloaders, and Query Complexity)

Every time I read a tutorial like this, I feel like I know everything I need to know and can get my all problems solved.

每次閱讀這樣的教程時,我都會感覺自己知道需要知道的一切,并且可以解決所有問題。

But when I start working on things on my own, I usually end up getting an internal server error or never-ending requests or dead ends and I have to dig deep into that to carve my way out. Hopefully we can help prevent that here.

但是,當我自己開始工作時,通常會遇到內部服務器錯誤或永無休止的請求或死胡同,而我必須深入研究該問題以找出出路。 希望我們可以在這里幫助防止這種情況。

Let’s take a look at a few advanced concepts starting with basic authentication.

讓我們看一些從基本身份驗證開始的高級概念。

認證方式 (Authentication)

In a REST API, you have a sort of authentication system and some out of the box authorizations on particular endpoints. But in GraphQL, only one endpoint is exposed so you can achieve this with schema directives.You need to edit your schema.graphql as follows:

在REST API中,您具有某種身份驗證系統,并且在特定端點上具有一些現成的授權。 但是在GraphQL中,僅公開了一個端點,因此您可以使用架構指令來實現此目的。您需要按如下方式編輯schema.graphql:

We have created an isAuthenticated directive and now we have applied that directive to createVideo subscription. After you regenerate code you need to give a definition of the directive. Currently, directives are implemented as struct methods instead of the interface so we have to give a definition.I have updated the generated code of server.go and created a method to return graphql config for server.go as follows:

我們已經創建了一個isAuthenticated指令,現在已經將該指令應用于createVideo訂閱。 重新生成代碼后,需要提供指令的定義。 當前,指令是作為struct方法而不是接口實現的,因此我們必須給出一個定義。我已經更新了server.go的生成代碼,并創建了一種方法來返回server.go的graphql config,如下所示:

We have read the userId from the context. Looks strange right? How was userId inserted in the context and why in context? Ok, so gqlgen only provides you the request contexts at the implementation level, so you can not read any of the HTTP request data like headers or cookies in graphql resolvers or directives. Therefore, you need to add your middleware and fetch those data and put the data in your context.

我們已經從上下文中讀取了userId。 看起來很奇怪吧? 如何將userId插入上下文中,為什么要插入上下文中? 好的,因此gqlgen僅在實現級別為您提供請求上下文,因此您無法讀取任何HTTP請求數據,例如graphql解析器或指令中的標頭或cookie。 因此,您需要添加中間件并獲取這些數據并將數據放入您的上下文中。

So we need to define auth middleware to fetch auth data from the request and validate.

因此,我們需要定義身份驗證中間件,以從請求中獲取身份驗證數據并進行驗證。

I haven’t defined any logic there, but instead I passed the userId as authorization for demo purposes. Then chain this middleware in server.go along with the new config loading method.

我在那里沒有定義任何邏輯,但是我出于演示目的將userId作為授權傳遞。 然后將此中間件與新的配置加載方法鏈接到server.go

Now, the directive definition makes sense. Don’t handle unauthorized users in your middleware as it will be handled by your directive.

現在,指令定義變得有意義了。 不要處理中間件中未經授權的用戶,因為它將由您的指令處理。

Demo time:

演示時間:

You can even pass arguments in the schema directives like this:

您甚至可以在模式指令中傳遞參數,如下所示:

directive @hasRole(role: Role!) on FIELD_DEFINITIONenum Role { ADMIN USER }

數據加載器 (Dataloaders)

This all looks fancy, doesn’t it? You are loading data when needed. Clients have control of the data, there is no under-fetching and no over-fetching. But everything comes with a cost.

這一切看起來都不錯,不是嗎? 您將在需要時加載數據。 客戶端可以控制數據,不會出現數據提取不足和過度提取的情況。 但是,一切都是有代價的。

So what’s the cost here? Let’s take a look at the logs while fetching all the videos. We have 8 video entries and there are 5 users.

那這里的費用是多少? 在獲取所有視頻時,讓我們看一下日志。 我們有8個視頻條目,有5個用戶。

query{  Videos(limit: 10){    name    user{      name    }  }}
Query: Videos : SELECT id, name, description, url, created_at, user_id FROM videos ORDER BY created_at desc limit $1 offset $2Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1

Why 9 queries (1 videos table and 8 users table)? It looks horrible. I was just about to have a heart attack when I thought about replacing our current REST API servers with this…but dataloaders came as a complete cure for it!

為什么要查詢9個(1個視頻表和8個用戶表)? 看起來太恐怖了。 當我想到用此替換當前的REST API服務器時,我正要心臟病發作……但是數據加載器可以完全治愈它!

This is known as the N+1 problem, There will be one query to get all the data and for each data (N) there will be another database query.

這稱為N + 1問題,將有一個查詢來獲取所有數據,對于每個數據(N),將有另一個數據庫查詢。

This is a very serious issue in terms of performance and resources: although these queries are parallel, they will use your resources up.

就性能和資源而言,這是一個非常嚴重的問題:盡管這些查詢是并行的,但它們會耗盡您的資源。

We will use the dataloaden library from the author of gqlgen. It is a Go- generated library. We will generate the dataloader for the user first.

我們將使用gqlgen的作者的dataloaden庫。 這是一個Go生成的庫。 我們將首先為用戶生成數據加載器。

go get github.com/vektah/dataloadendataloaden github.com/ridhamtarpara/go-graphql-demo/api.User

This will generate a file userloader_gen.go which has methods like Fetch, LoadAll, and Prime.

這將生成一個文件userloader_gen.go ,該文件具有Fetch, userloader_gen.go和Prime等方法。

Now, we need to define the Fetch method to get the result in bulk.

現在,我們需要定義Fetch方法來批量獲取結果。

Here, we are waiting for 1ms for a user to load queries and we have kept a maximum batch of 100 queries. So now, instead of firing a query for each user, dataloader will wait for either 1 millisecond for 100 users before hitting the database. We need to change our user resolver logic to use dataloader instead of the previous query logic.

在這里,我們等待用戶加載查詢的時間為1毫秒,并且我們最多保留了100個查詢。 因此,現在,數據加載器將不再為每個用戶觸發查詢,而是會在100個用戶之前等待1毫秒,然后再命中數據庫。 我們需要更改用戶解析器邏輯以使用數據加載器,而不是先前的查詢邏輯。

After this, my logs look like this for similar data:

在此之后,我的日志如下所示:

Query: Videos : SELECT id, name, description, url, created_at, user_id FROM videos ORDER BY created_at desc limit $1 offset $2Dataloader: User : SELECT id, name, email from users WHERE id IN ($1, $2, $3, $4, $5)

Now only two queries are fired, so everyone is happy. The interesting thing is that only five user keys are given to query even though 8 videos are there. So dataloader removed duplicate entries.

現在僅觸發兩個查詢,因此每個人都很高興。 有趣的是,即使有8個視頻,也只有五個用戶鍵可以查詢。 因此,數據加載器刪除了重復的條目。

查詢復雜度 (Query Complexity)

In GraphQL you are giving a powerful way for the client to fetch whatever they need, but this exposes you to the risk of denial of service attacks.

在GraphQL中,您為客戶端提供了一種獲取所需內容的強大方法,但這使您面臨拒絕服務攻擊的風險。

Let’s understand this through an example which we’ve been referring to for this whole article.

讓我們通過一個在整篇文章中一直引用的示例來理解這一點。

Now we have a related field in video type which returns related videos. And each related video is of the graphql video type so they all have related videos too…and this goes on.

現在,我們在視頻類型中有一個相關字段,該字段返回相關視頻。 每個相關視頻都是graphql視頻類型,因此它們也都具有相關視頻……而且這種情況還在繼續。

Consider the following query to understand the severity of the situation:

考慮以下查詢以了解情況的嚴重性:

{  Videos(limit: 10, offset: 0){    name    url    related(limit: 10, offset: 0){      name      url      related(limit: 10, offset: 0){        name        url        related(limit: 100, offset: 0){          name          url        }      }    }  }}

If I add one more subobject or increase the limit to 100, then it will be millions of videos loading in one call. Perhaps (or rather definitely) this will make your database and service unresponsive.

如果我再添加一個子對象或將限制增加到100,則一次調用將加載數百萬個視頻。 也許(或者絕對是肯定的)這會使您的數據庫和服務無響應。

gqlgen provides a way to define the maximum query complexity allowed in one call. You just need to add one line (Line 5 in the following snippet) in your graphql handler and define the maximum complexity (300 in our case).

gqlgen提供了一種定義一次調用中允許的最大查詢復雜度的方法。 您只需要在graphql處理程序中添加一行(以下代碼段中的第5行),然后定義最大復雜度(本例中為300)。

gqlgen assigns fix complexity weight for each field so it will consider struct, array, and string all as equals. So for this query, complexity will be 12. But we know that nested fields weigh too much, so we need to tell gqlgen to calculate accordingly (in simple terms, use multiplication instead of just sum).

gqlgen為每個字段分配固定復雜度權重,因此它將結構,數組和字符串都視為相等。 因此,對于該查詢,復雜度將為12。但是我們知道嵌套字段的權重太大,因此我們需要告訴gqlgen進行相應的計算(簡單來說,請使用乘法而不是求和)。

Just like directives, complexity is also defined as struct, so we have changed our config method accordingly.

就像指令一樣,復雜度也定義為struct,因此我們相應地更改了config方法。

I haven’t defined the related method logic and just returned the empty array. So related is empty in the output, but this should give you a clear idea about how to use the query complexity.

我還沒有定義相關的方法邏輯,只是返回了空數組。 因此,輸出中的related是空的,但這應該使您對如何使用查詢復雜度有一個清晰的了解。

最后說明 (Final Notes)

This code is on Github. You can play around with it, and if you have any questions or concerns let me know in the comment section.

這段代碼在Github上 。 您可以嘗試一下,如果有任何疑問或疑慮,請在評論部分告訴我。

Thanks for reading! A few (hopefully 50) claps? are always appreciated. I write about JavaScript, the Go Language, DevOps, and Computer Science. Follow me and share this article if you like it.

謝謝閱讀! 拍手(希望有50個)? 總是很感激。寫有關JavaScript,Go語言,DevOps和計算機科學的文章。 關注我,如果您喜歡它,請分享這篇文章。

Reach out to me on @Twitter @Linkedin. Visit www.ridham.me for more.

通過@ Twitter @ Linkedin與我聯系。 有關更多信息,請訪問www.ridham.me 。

翻譯自: https://www.freecodecamp.org/news/deep-dive-into-graphql-with-golang-d3e02a429ac3/

golang底層深入

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

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

相關文章

spring—Bean實例化三種方式

1&#xff09; 使用無參構造方法實例化 它會根據默認無參構造方法來創建類對象&#xff0c;如果bean中沒有默認無參構造函數&#xff0c;將會創建失敗 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.o…

bzoj 3439: Kpm的MC密碼

Description 背景 想Kpm當年為了防止別人隨便進入他的MC&#xff0c;給他的PC設了各種奇怪的密碼和驗證問題&#xff08;不要問我他是怎么設的。。。&#xff09;&#xff0c;于是乎&#xff0c;他現在理所當然地忘記了密碼&#xff0c;只能來解答那些神奇的身份驗證問題了。。…

python創建類統計屬性_輕松創建統計數據的Python包

python創建類統計屬性介紹 (Introduction) Sometimes you may need a distribution figure for your slide or class. Since you are not using data, you want a quick solution.有時&#xff0c;您的幻燈片或課程可能需要一個分配圖。 由于您不使用數據&#xff0c;因此需要快…

pytorch深度學習_在本完整課程中學習在PyTorch中應用深度學習

pytorch深度學習In this complete course from Fawaz Sammani you will learn the key concepts behind deep learning and how to apply the concepts to a real-life project using PyTorch. 在Fawaz Sammani的完整課程中&#xff0c;您將學習深度學習背后的關鍵概念&#x…

html讓a標簽左右一樣寬,button和a標簽設置相同的css樣式,但是寬度不同

登錄注冊.btn {display: block;-moz-appearance: none;background: rgba(0, 0, 0, 0) none repeat scroll 0 0;border-radius: 0.25rem;box-sizing: border-box;cursor: pointer;font-family: inherit;font-size: 0.8rem;height: 2rem;line-height: 1.9rem;margin: 0;padding: …

淺析STM32之usbh_def.H

【溫故而知新】類似文章淺析USB HID ReportDesc (HID報告描述符) 現在將en.stm32cubef1\STM32Cube_FW_F1_V1.4.0\Middlewares\ST\STM32_USB_Host_Library\Core\Inc\usbh_def.H /********************************************************************************* file us…

spring—依賴注入

依賴注入&#xff08;Dependency Injection&#xff09; 它是 Spring 框架核心 IOC 的具體實現。 在編寫程序時&#xff0c;通過控制反轉&#xff0c;把對象的創建交給了 Spring&#xff0c;但是代碼中不可能出現沒有依賴的情況。 IOC 解耦只是降低他們的依賴關系&#xff0c;…

C# (類型、對象、線程棧和托管堆)在運行時的相互關系

在介紹運行時的關系之前,先從一些計算機基礎只是入手,如下圖: 該圖展示了已加載CLR的一個windows進程,該進程可能有多個線程,線程創建時會分配到1MB的棧空間.棧空間用于向方法傳遞實參,方法定義的局部變量也在實參上,上圖的右側展示了線程的棧內存,棧從高位內存地址向地位內存地…

2019-08-01 紀中NOIP模擬賽B組

T1 [JZOJ2642] 游戲 題目描述 Alice和Bob在玩一個游戲&#xff0c;游戲是在一個N*N的矩陣上進行的&#xff0c;每個格子上都有一個正整數。當輪到Alice/Bob時&#xff0c;他/她可以選擇最后一列或最后一行&#xff0c;并將其刪除&#xff0c;但必須保證選擇的這一行或這一列所有…

knn分類 knn_關于KNN的快速小課程

knn分類 knnAs the title says, here is a quick little lesson on how to construct a simple KNN model in SciKit-Learn. I will be using this dataset. It contains information on students’ academic performance.就像標題中所說的&#xff0c;這是關于如何在SciKit-Le…

spring—配置數據源

數據源&#xff08;連接池&#xff09;的作用 數據源(連接池)是提高程序性能如出現的 事先實例化數據源&#xff0c;初始化部分連接資源 使用連接資源時從數據源中獲取 使用完畢后將連接資源歸還給數據源 常見的數據源(連接池)&#xff1a;DBCP、C3P0、BoneCP、Druid等 開發步…

大型網站系統與Java中間件實踐pdf

下載地址&#xff1a;網盤下載 基本介紹 編輯內容簡介 到底是本什么書&#xff0c;擁有這樣一份作序推薦人列表&#xff1a;阿里集團章文嵩博士|新浪TimYang|去哪網吳永強|丁香園馮大輝|蘑菇街岳旭強|途牛湯崢嶸|豆瓣洪強寧|某電商陳皓/林昊…… 這本書出自某電商技術部總監之手…

office漏洞利用--獲取shell

環境&#xff1a; kali系統&#xff0c; windows系統 流程&#xff1a; 在kali系統生成利用文件&#xff0c; kali系統下監聽本地端口&#xff0c; windows系統打開doc文件&#xff0c;即可中招 第一種利用方式&#xff0c; 適合測試用&#xff1a; 從git下載代碼&#xff1a; …

pandas之DataFrame合并merge

一、merge merge操作實現兩個DataFrame之間的合并&#xff0c;類似于sql兩個表之間的關聯查詢。merge的使用方法及參數解釋如下&#xff1a; pd.merge(left, right, onNone, howinner, left_onNone, right_onNone, left_indexFalse, right_indexFalse,    sortFalse, suffi…

typescript_如何掌握高級TypeScript模式

typescriptby Pierre-Antoine Mills皮埃爾安托萬米爾斯(Pierre-Antoine Mills) 如何掌握高級TypeScript模式 (How to master advanced TypeScript patterns) 了解如何為咖喱和Ramda創建類型 (Learn how to create types for curry and Ramda) Despite the popularity of curry…

html函數splice,js數組的常用函數(slice()和splice())和js引用的三種方法總結—2019年1月16日...

總結&#xff1a;slice()和splice()slice(參數1,參數2)可以查找數組下對應的數據&#xff0c;參數1為起始位置&#xff0c;參數2為結束位置&#xff0c;參數2可以為負數&#xff0c;-1對應的是從后向前數的第一個數值。splice()可以進行增刪改查數據操作&#xff0c;splice(參數…

leetcode 643. 子數組最大平均數 I(滑動窗口)

給定 n 個整數&#xff0c;找出平均數最大且長度為 k 的連續子數組&#xff0c;并輸出該最大平均數。 示例&#xff1a; 輸入&#xff1a;[1,12,-5,-6,50,3], k 4 輸出&#xff1a;12.75 解釋&#xff1a;最大平均數 (12-5-650)/4 51/4 12.75 代碼 class Solution {publ…

python ==字符串

字符串類型(str)&#xff1a; 包含在引號&#xff08;單&#xff0c;雙&#xff0c;三&#xff09;里面&#xff0c;由一串字符組成。 用途&#xff1a;姓名&#xff0c;性別&#xff0c;地址&#xff0c;學歷&#xff0c;密碼 Name ‘zbk’ 取值: 首先要明確&#xff0c;字符…

認證鑒權與API權限控制在微服務架構中的設計與實現(一)

作者&#xff1a; [Aoho’s Blog] 引言&#xff1a; 本文系《認證鑒權與API權限控制在微服務架構中的設計與實現》系列的第一篇&#xff0c;本系列預計四篇文章講解微服務下的認證鑒權與API權限控制的實現。 1. 背景 最近在做權限相關服務的開發&#xff0c;在系統微服務化后&a…

mac下完全卸載程序的方法

在國外網上看到的&#xff0c;覺得很好&#xff0c;不僅可以長卸載的知識&#xff0c;還對mac系統有更深的認識。比如偏好設置文件&#xff0c;我以前設置一個程序壞了&#xff0c;打不開了&#xff0c;怎么重裝都打不開&#xff0c;后來才知道系統還保留著原來的偏好設置文件。…