akka 簡介_Akka HTTP路由簡介

akka 簡介

by Miguel Lopez

由Miguel Lopez

Akka HTTP路由簡介 (An introduction to Akka HTTP routing)

Akka HTTP’s routing DSL might seem complicated at first, but once you get the hang of it you’ll see how powerful it is.

Akka HTTP的路由DSL乍一看似乎很復雜,但是一旦掌握了它,您就會發現它的功能強大。

In this tutorial we will focus on creating routes and their structure. We won’t cover parsing to and from JSON, we have other tutorials that cover that topic.

在本教程中,我們將重點介紹創建路線及其結構。 我們將不介紹與JSON之間的解析,也有涉及該主題的其他教程 。

什么是指令? (What are directives?)

One of the first concepts we’ll find when learning server-side Akka HTTP (there’s a client-side library as well) is directives.

當學習服務器端Akka HTTP(也有一個客戶端庫)時,我們會發現第一個概念是指令

So, what are they?

那是什么

You can think of them as building blocks, Lego pieces if you will, that you can use to construct your routes. They are composable, which means we can create directives on top of other directives.

您可以將它們視為積木,也可以視作樂高積木,用于構建路線。 它們是可組合的,這意味著我們可以在其他指令之上創建指令。

If you want a more in-depth reading, feel free to check out Akka HTTP’s official documentation.

如果您想更深入地閱讀,請隨時查閱Akka HTTP的官方文檔 。

Before moving on, let’s discuss what we’ll build.

在繼續之前,讓我們討論一下我們將要構建的內容。

類博客API (Blog-like API)

We’ll create a sample of a public facing API for a blog, where we will allow users to:

我們將為博客創建一個面向公眾的API樣本,我們將允許用戶執行以下操作:

  • query a list of tutorials

    查詢教程列表
  • query a single tutorial by ID

    通過ID查詢單個教程
  • query the list of comments in a tutorial

    查詢教程中的評論列表
  • add comments to a tutorial

    在教程中添加評論

The endpoints will be:

端點將是:

- List all tutorials GET /tutorials
- Create a tutorial GET /tutorials/:id
- Get all comments in a tutorial GET /tutorials/:id/comments
- Add a comment to a tutorial POST /tutorials/:id/comments

We will only implement the endpoints, no logic in them. This way we’ll learn how to create this structure and the common pitfalls when starting with Akka HTTP.

我們將只實現端點,而沒有邏輯。 這樣,我們將學習從Akka HTTP開始如何創建此結構以及常見的陷阱。

項目設置 (Project Setup)

We’ve created a repo for this tutorial, in it you’ll find a branch per each section that requires coding. Feel free to clone it and use it as a base project or even just change between branches to look at the differences.

我們已經為本教程創建了一個倉庫 ,其中每個需要編碼的部分都會找到一個分支。 隨意克隆它并將其用作基礎項目,甚至只是在分支之間進行更改以查看差異。

Otherwise, create a new SBT project, and then add the dependencies in the build.sbt file:

否則,請創建一個新的SBT項目,然后在build.sbt文件中添加依賴build.sbt

name := "akkahttp-routing-dsl"
version := "0.1"
scalaVersion := "2.12.7"
val akkaVersion = "2.5.17" val akkaHttpVersion = "10.1.5"
libraryDependencies ++= Seq(   "com.typesafe.akka" %% "akka-actor" % akkaVersion,   "com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test,  "com.typesafe.akka" %% "akka-stream" % akkaVersion,   "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % Test,   "com.typesafe.akka" %% "akka-http" % akkaHttpVersion,   "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test,      "org.scalatest" %% "scalatest" % "3.0.5" % Test )

We added Akka HTTP and its dependencies, Akka Actor and Streams. And we will also use Scalatest for testing.

我們添加了Akka HTTP及其依賴項,Akka Actor和Streams。 我們還將使用Scalatest進行測試。

列出所有教程 (Listing all the tutorials)

We’ll take a TDD approach to build our directive hierarchy, creating the tests first to make sure when don’t break our routes when adding others. Taking this approach is quite helpful when starting with Akka HTTP.

我們將采用TDD方法來構建指令層次結構,首先創建測試以確保添加其他路由時不中斷我們的路由。 從Akka HTTP開始時,采用這種方法非常有幫助。

Let’s start with our route to listing all the tutorials. Create a new file under src/test/scala (if the folders don't exist, create them) named RouterSpec:

讓我們從列出所有教程的路線開始。 在src/test/scala下創建一個名為RouterSpec的新文件(如果文件夾不存在,請創建它們):

import akka.http.scaladsl.testkit.ScalatestRouteTest import org.scalatest.{Matchers, WordSpec}
class RouterSpec extends WordSpec with Matchers with ScalatestRouteTest {
}

WordSpec and Matchers are provided by Scalatest, and we'll use them to structure our tests and assertions. ScalatestRouteTest is a trait provided by Akka HTTP's test kit, it will allow us to test our routes in a convenient way. Let's see how we can accomplish that.

WordSpecMatchers是由Scalatest提供,我們將用它們來構建我們的測試和斷言。 ScalatestRouteTest是Akka HTTP測試工具提供的特征,它將使我們能夠以方便的方式測試路由。 讓我們看看我們如何做到這一點。

Because we’re using Scalatest’s WordSpec, we’ll start by creating a scope for our Router object that we will create soon and the first test:

因為我們使用的是Scalatest的WordSpec ,所以我們將從為我們的Router對象創建一個范圍開始,這將是我們即將創建的第一個測試:

"A Router" should {   "list all tutorials" in {   } }

Next, we want to make sure can send a GET request to the path /tutorials and get the response we expect, let's see how we can accomplish that:

接下來,我們要確保可以將GET請求發送到路徑/tutorials并獲得我們期望的響應,讓我們看一下如何實現:

Get("/tutorials") ~> Router.route ~> check {   status shouldBe StatusCodes.OK   responseAs[String] shouldBe "all tutorials" }

It won’t even compile because we haven’t created our Router object. Let's do that now.

它甚至不會編譯,因為我們還沒有創建Router對象。 現在開始吧。

Create a new Scala object under src/main/scala named Router. In it we will create a method that will return a Route:

src/main/scala下創建一個名為Router的新Scala對象。 在其中,我們將創建一個將返回Route

import akka.http.scaladsl.server.Route
object Router {
def route: Route = ???
}

Don’t worry too much about the ???, it's just a placeholder to avoid compilation errors temporarily. However, if that code is executed, it'll throw a NotImplementedError as we'll see soon.

不用擔心??? ,這只是暫時避免編譯錯誤的占位符。 但是,如果執行了該代碼,它將拋出NotImplementedError ,我們將很快看到。

Now that our tests and project are compiling, let’s run the tests (Right-click the spec and “Run ‘RouterSpec’”).

現在我們的測試和項目正在編譯,讓我們運行測試(右鍵單擊spec并“運行'RouterSpec'”)。

The test failed with the exception we were expecting, we haven’t implemented our routes. Let’s begin!

測試失敗,除了我們所期望的例外,我們還沒有實現我們的路線。 讓我們開始!

創建上市路線 (Creating the listing route)

By looking into the official documentation we see that the route begins with the path directive. Let's mimic what they're doing and build our route:

通過查看官方文檔,我們發現路由以path指令開頭。 讓我們模仿他們在做什么,并建立我們的路線:

import akka.http.scaladsl.server.{Directives, Route}
object Router extends Directives {
def route: Route = path("tutorials") {    get {      complete("all tutorials")    }  }}

Seems reasonable, let’s run our spec. And it passes, great!

似乎合理,讓我們運行我們的規范。 它過去了,太好了!

For reference, our entire RouterSpec now looks like:

作為參考,我們的整個RouterSpec現在看起來像:

import akka.http.scaladsl.model.StatusCodesimport akka.http.scaladsl.testkit.ScalatestRouteTestimport org.scalatest.{Matchers, WordSpec}class RouterSpec extends WordSpec with Matchers with ScalatestRouteTest {  "A Router" should {    "list all tutorials" in {      Get("/tutorials") ~> Router.route ~> check {        status shouldBe StatusCodes.OK        responseAs[String] shouldBe "all tutorials"      }    }  }}

通過ID獲取單個教程 (Getting a single tutorial by ID)

Next, we will allow our users to retrieve a single tutorial.

接下來,我們將允許我們的用戶檢索單個教程。

Let’s add a test for our new route:

讓我們為新路線添加一個測試:

"return a single tutorial by id" in {  Get("/tutorials/hello-world") ~> Router.route ~> check {    status shouldBe StatusCodes.OK    responseAs[String] shouldBe "tutorial hello-world"  }}

We expect to get back a message that includes the tutorial ID.

我們希望獲得一條包含教程ID的消息。

The test will fail because we haven’t created our route, let’s do that now.

由于我們尚未創建路線,因此測試將失敗,讓我們現在開始。

From the same resource we used earlier to base our route on, we can see how we can place multiple directives at the same level in the hierarchy using the ~ directive.

從之前使用的相同資源開始,我們可以看到如何使用~指令將多個指令放置在層次結構中的同一級別上。

We will have to nest path directives because need another segment after the /tutorials route for the tutorial ID. In the documentation they use IntNumber to extract a number from the path, but we'll use a string and for that we use can Segment instead.

我們將必須嵌套path指令,因為在/tutorials路由后需要另一個段來獲取教程ID。 在文檔中,他們使用IntNumber從路徑中提取數字,但是我們將使用字符串,為此,我們可以使用Segment

Our route looks like:

我們的路線如下:

def route: Route = path("tutorials") {  get {    complete("all tutorials")  } ~ path(Segment) { id =>    get {      complete(s"tutorial $id")    }  }}

Let’s run the tests. And you should get a similar error:

讓我們運行測試。 而且您應該得到類似的錯誤:

Request was rejectedScalaTestFailureLocation: RouterSpec at (RouterSpec.scala:17)org.scalatest.exceptions.TestFailedException: Request was rejected

What’s going on?!

這是怎么回事?!

Well, a request is rejected when it doesn’t match our directive hierarchy. This is one of the things that got me when starting.

好吧,當請求與我們的指令層次結構不匹配時,該請求將被拒絕。 這是開始時讓我著迷的事情之一。

Now is probably a good time to look into how these directives match the incoming request as it goes through the hierarchy.

現在可能是研究這些指令如何與傳入請求通過層次結構進行匹配的好時機。

Different directives will match different aspects of an incoming request, we’ve seen path and get, one matches the URL of the request and the other the method. If a request matches a directive it will go inside it, if it doesn't it will continue to the next one. This also tells us that order matters. If it doesn't match any directive the request is rejected.

不同的指令將匹配傳入請求的不同方面,我們已經看到pathget ,一個匹配請求的URL,另一個匹配方法。 如果一個請求與一個指令相匹配,它將進入其中,如果不匹配,它將繼續到下一個指令。 這也告訴我們訂單很重要。 如果它與任何指令都不匹配,則請求被拒絕。

Now that we now that our request is not matching our directives, let’s start looking into why.

現在,我們的請求與指令不匹配,讓我們開始研究原因。

If we look the documentation for the path directive (Cmd + Click on Mac) we'll find:

如果我們查看path指令的文檔(Cmd +在Mac上單擊),我們會發現:

/** * Applies the given [[PathMatcher]] to the remaining unmatched path after consuming a leading slash. * The matcher has to match the remaining path completely. * If matched the value extracted by the [[PathMatcher]] is extracted on the directive level. * * @group path */

So, the path directive has to match exactly the path, meaning our first path directive will only match /tutorials and never /tutorials/:id.

因此, path指令必須與路徑完全匹配,這意味著我們的第一個path指令將僅匹配/tutorials而不會匹配/tutorials/:id

In the same PathDirectives trait that contains the path directive we can see another directive named pathPrefix:

在包含path指令的同一PathDirectives特性中,我們可以看到另一個名為pathPrefix指令:

/** * Applies the given [[PathMatcher]] to a prefix of the remaining unmatched path after consuming a leading slash. * The matcher has to match a prefix of the remaining path. * If matched the value extracted by the PathMatcher is extracted on the directive level. * * @group path */

pathPrefix matches only a prefix and removes it. Sounds like this is what we're looking for, let's update our routes:

pathPrefix僅匹配前綴,并將其刪除。 聽起來這就是我們想要的,讓我們更新路線:

def route: Route = pathPrefix("tutorials") {  get {    complete("all tutorials")  } ~ path(Segment) { id =>    get {      complete(s"tutorial $id")    }  }}

Run the tests, and… we get another error. ?

運行測試,然后…我們得到另一個錯誤。 ?

"[all tutorials]" was not equal to "[tutorial hello-world]"ScalaTestFailureLocation: RouterSpec at (RouterSpec.scala:18)Expected :"[tutorial hello-world]"Actual   :"[all tutorials]"

Looks like our request matched the first get directive. It now matches the pathPrefix, and because it also is a GET request it will match the first get directive. Order matters.

看起來我們的請求與第一個get指令匹配。 現在,它與pathPrefix匹配,并且由于它也是一個GET請求,因此它將與第一個get指令匹配。 順序很重要。

There are a couple of things we can do. The simplest solution would be to move the first get request to the end of the hierarchy, however, we would have to remember this or document it. Not ideal.

我們可以做幾件事。 最簡單的解決方案是將第一個get請求移至層次結構的末尾,但是,我們必須記住此要求或將其記錄下來。 不理想。

Personally, I prefer avoiding such solutions and instead make the intend clear through code. If we look in the PathDirectives trait from earlier, we'll find a directive called pathEnd:

就我個人而言,我更喜歡避免此類解決方案,而是通過代碼明確意圖。 如果我們從較早的版本開始查看PathDirectives特性,我們將找到一個名為pathEnd的指令:

/** * Rejects the request if the unmatchedPath of the [[RequestContext]] is non-empty, * or said differently: only passes on the request to its inner route if the request path * has been matched completely. * * @group path */

That’s exactly what we want, so let’s wrap our first get directive with pathEnd:

這正是我們想要的,所以讓我們用pathEnd包裝第一個get指令:

def route: Route = pathPrefix("tutorials") {  pathEnd {    get {      complete("all tutorials")    }  } ~ path(Segment) { id =>    get {      complete(s"tutorial $id")    }  }}

Run the tests again, and… finally, the tests are passing! ?

再次運行測試,……最后,測試通過了! ?

列出教程中的所有評論 (Listing all comments in a tutorial)

Let’s put into practice what we learned about nesting routes by taking it a bit further.

讓我們進一步實踐嵌套路由所學到的知識。

First the test:

首先測試:

"list all comments of a given tutorial" in {  Get("/tutorials/hello-world/comments") ~> Router.route ~> check {    status shouldBe StatusCodes.OK    responseAs[String] shouldBe "comments for the hello-world tutorial"  }}

It’s a similar case as before: we know we’ll need to place a route next to another one, which means we need to:

這與之前的情況類似:我們知道我們需要在另一條路線旁邊放置一條路線,這意味著我們需要:

  • change the path(Segmenter) to pathPrefix(Segmenter)

    path(Segmenter)更改為pathPrefix(Segmenter)

  • wrap the first get with the pathEnd directive

    pathEnd指令包裝第一個get

  • place the new route next to the pathEnd

    將新路線放置在pathEnd

Our routes end up looking like:

我們的路線最終看起來像:

def route: Route = pathPrefix("tutorials") {  pathEnd {    get {      complete("all tutorials")    }  } ~ pathPrefix(Segment) { id =>    pathEnd {      get {        complete(s"tutorial $id")      }    } ~ path("comments") {      get {        complete(s"comments for the $id tutorial")      }    }  }}

Run the tests, and they should pass! ?

運行測試,它們應該通過! ?

在教程中添加評論 (Adding comments to a tutorial)

Our last endpoint is similar to the previous, but it will match POST requests. We’ll use this example to see the difference between implementing and testing a GET request versus a POST request.

我們的最后一個端點與先前的端點相似,但是它將匹配POST請求。 我們將使用此示例查看實現和測試GET請求與POST請求之間的區別。

The test:

考試:

"add comments to a tutorial" in {  Post("/tutorials/hello-world/comments", "new comment") ~> Router.route ~> check {    status shouldBe StatusCodes.OK    responseAs[String] shouldBe "added the comment 'new comment' to the hello-world tutorial"  }}

We’re using the Post method instead of the Get we've been using, and we're giving it an additional parameter which is the request body. The rest is familiar to us now.

我們使用的是Post方法而不是我們一直使用的Get方法,并且為其提供了一個附加參數,即請求正文。 其余的現在對我們來說已經很熟悉了。

To implement our last route, we can refer to the documentation and look at how it’s usually done.

要實現我們的最后一條路線,我們可以參考文檔并查看它通常是如何完成的。

We have a post directive just as we have a get one. To extract the request body we need two directives, entity and as, to which we supply the type we expect. In our case it's a string.

我們有一個post指令,就像我們有一個get指令。 為了提取請求主體,我們需要兩個指令, entityas ,我們向它們提供期望的類型。 在我們的例子中,它是一個字符串。

Let’s give that a try:

讓我們嘗試一下:

post {  entity(as[String]) { comment =>    complete(s"added the comment '$comment' to the $id tutorial")  }}

Looks reasonable. We extract the request body as a string and use it in our response. Let’s add it to our route method next to the previous route we worked on:

看起來很合理。 我們將請求主體提取為字符串,并在響應中使用它。 讓我們將其添加到我們之前處理過的路由旁邊的route方法中:

def route: Route = pathPrefix("tutorials") {  pathEnd {    get {      complete("all tutorials")    }  } ~ pathPrefix(Segment) { id =>    pathEnd {      get {        complete(s"tutorial $id")      }    } ~ path("comments") {      get {        complete(s"comments for the $id tutorial")      } ~ post {        entity(as[String]) { comment =>          complete(s"added the comment '$comment' to the $id tutorial")        }      }    }  }}

If you’d like to learn how to parse Scala classes to and from JSON we’ve got tutorials for that as well.

如果您想學習如何在JSON中解析Scala類以及從JSON解析出Scala類, 我們也有相應的教程 。

Run the tests, and they should all pass.

運行測試,它們都應該通過。

結論 (Conclusion)

Akka HTTP’s routing DSL might seem confusing at first, but after overcoming some bumps it just clicks. After a while it’ll come naturally and it can be very powerful.

Akka HTTP的路由DSL乍一看似乎令人困惑,但是在克服了一些麻煩之后,只需單擊一下。 一段時間后,它會自然而然地變得強大。

We learned how to structure our routes, but more importantly, we learned how to create that structure guided by tests which will make sure we don’t break them at some point in the future.

我們學會了如何構造路線,但更重要的是,我們學會了如何在測試的指導下建立這種結構,以確保我們在將來的某個時候不會破壞它們。

Even though we only worked on four endpoints, we ended up with a somewhat complicated and deep structure. Stay tuned and we’ll explore different ways to simplify our routes and make them more manageable!

即使我們僅在四個端點上工作,但最終還是有一個復雜而深入的結構。 請繼續關注,我們將探索各種方法來簡化路線并使其更易于管理!

Learn how to build REST APIs with Scala and Akka HTTP with this step-by-step free course!

通過此分步免費課程,了解如何使用Scala和Akka HTTP構建REST API!

Originally published at www.codemunity.io.

最初在www.codemunity.io上發布。

翻譯自: https://www.freecodecamp.org/news/an-introduction-to-akka-http-routing-697b00399cad/

akka 簡介

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

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

相關文章

leetcode 1046. 最后一塊石頭的重量(堆)

有一堆石頭&#xff0c;每塊石頭的重量都是正整數。 每一回合&#xff0c;從中選出兩塊 最重的 石頭&#xff0c;然后將它們一起粉碎。假設石頭的重量分別為 x 和 y&#xff0c;且 x < y。那么粉碎的可能結果如下&#xff1a; 如果 x y&#xff0c;那么兩塊石頭都會被完全…

java2d方法_Java SunGraphics2D.fillRect方法代碼示例

import sun.java2d.SunGraphics2D; //導入方法依賴的package包/類/*** Return a non-accelerated BufferedImage of the requested type with the* indicated subimage of the original image located at 0,0 in the new image.* If a bgColor is supplied, composite the orig…

js建立excel表格_建立Excel足球聯賽表格-傳統vs動態數組方法

js建立excel表格介紹 (Introduction) I am going to show you the different ways you can build a football league table in Excel. Some of the methods are old school but others utilise Excel’s new capabilities.我將向您展示在Excel中建立足球聯賽表格的不同方法。 其…

postman+newman生成html報告

作為測試菜鳥,在學習postmannewman的使用過程中真的是頗費周折......沒辦法技術太菜,只能多學習. postman的下載安裝不多言說,下載地址:https://www.getpostman.com/downloads/ newman的安裝過程: 1.首先需要安裝node.js,可以去官網下載,地址:https://nodejs.org/en/#download …

java jdk1.9新特性_JDK1.9-新特性

1. Java平臺級模塊系統該特性使Java9最大的一個特性&#xff0c;Java提供該功能的主要的動機在于&#xff0c;減少內存的開銷&#xff0c;JVM啟動的時候&#xff0c;至少會有30~60MB的內存加載&#xff0c;主要原因是JVM需要加載rt.jar&#xff0c;不管其中的類是否被classload…

如何在10分鐘內讓Redux發揮作用

Hi everyone ??大家好?? For a while now I’ve been hearing my friends and colleagues complaining about how hard it was to get into Redux.一段時間以來&#xff0c;我一直在聽我的朋友和同事抱怨進入Redux有多困難。 I run a freeCodeCamp Study Group in the So…

兩個鏈接合并_如何找到兩個鏈接列表的合并點

兩個鏈接合并了解問題 (Understand the Problem) We are given two singly linked lists and we have to find the point at which they merge.我們給了兩個單鏈表&#xff0c;我們必須找到它們合并的點。 [SLL 1] 1--->3--->5 \ …

安裝veket到移動硬盤NTFS分區

如果你已經看過《手動安裝veket到硬盤》和《簡單的將veket安裝到U盤的方法》兩篇文章并且安裝成功的話&#xff0c;說明不適用本文的安裝環境&#xff0c;就不用往下看了。 《手動安裝veket到硬盤》一文采用grub4dos來引導硬盤上的veket&#xff0c;主要是用來在本機已安裝Wind…

簡書使用小技巧

1、不同字體  在 設置->基礎設置->富文本 模式下可以實現 2、添加圖片&#xff0c;讓文章更生動 3、添加代碼框 &#xff01;注意&#xff1a;設置為Markdown模式后&#xff0c;只對新創建的文章起作用。轉載于:https://www.cnblogs.com/HMJ-29/p/7049540.html

掩碼 項目編碼_每天進行20天的編碼項目

掩碼 項目編碼by Angela He通過何安佳 每天進行20天的編碼項目 (A coding project a day for 20 days) 我如何在20天內自學Web開發 (How I taught myself web development in 20 days) It was the first day of winter break for Stanford students. Back at home, I opened a…

java循環一年月份天數和_javawhile循環編寫輸入某年某月某日,判斷這一天是這一年的第幾…...

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓public class ZuoYe9 {public static void main(String[] args) {int days0; //存儲變量這一年的第幾天//1.輸入年&#xff0c;月&#xff0c;日Scanner inputnew Scanner(System.in);System.out.println("請輸入年份&#xf…

leetcode 605. 種花問題(貪心算法)

假設你有一個很長的花壇&#xff0c;一部分地塊種植了花&#xff0c;另一部分卻沒有。可是&#xff0c;花卉不能種植在相鄰的地塊上&#xff0c;它們會爭奪水源&#xff0c;兩者都會死去。 給定一個花壇&#xff08;表示為一個數組包含0和1&#xff0c;其中0表示沒種植花&…

工程師的成熟模型_數據工程師的成熟度

工程師的成熟模型數據科學與機器學習 (DATA SCIENCE AND MACHINE LEARNING) What does a data engineer do?數據工程師做什么&#xff1f; Let’s start with three big wars that we need to understand before understanding what a data engineer does.讓我們從理解數據工…

杭電2064

此題是一道簡單的遞歸 此題是一道遞歸運算題&#xff0c;這題又是一道漢諾塔問題&#xff01;&#xff01;&#xff01;只要了解其規律&#xff0c;呵呵&#xff0c;你就可以很快AC了&#xff01;&#xff01; 這是一般的漢諾塔問題的解題方法照片&#xff01;&#xff01;&…

/ ./ ../ 的區別

/ 根目錄 &#xff08;絕對路徑&#xff09; ./ 當前目錄 ../父級目錄 &#xff08;相對路徑&#xff09; ./home是當前目錄下的一個叫home的目錄/home是絕對路徑的/home就是根下的home目錄轉載于:https://www.cnblogs.com/sjd1118/p/7055475.html

java設置表格列不可修改_Java DefaultTableModel使單元格不可編輯JTable

參見英文答案 >How to make a JTable non-editable 7個我有一個JAVA項目,并希望使用DefaultTableModel使我的JTable不可編輯.我知道一個解決方法,稱為&#xff1a;JTable table new JTable(...){public boolean isCellEditable(int row…

阻塞隊列實現

? 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主頁&#xff1a;小胡_不糊涂的個人主頁 &#x1f4c0; 收錄專欄&#xff1a;JavaEE &#x1f496; 持續更文&#xff0c;關注博主少走彎路&#xff0c;謝謝大家支持 &#x1f496; 阻塞隊列 1. 什么是阻塞隊列2. 標準庫中的…

graphql入門_GraphQL入門指南

graphql入門by Leonardo Maldonado萊昂納多馬爾多納多(Leonardo Maldonado) GraphQL入門指南 (A Beginner’s Guide to GraphQL) One of the most commonly discussed terms today is the API. A lot of people don’t know exactly what an API is. Basically, API stands fo…

leetcode 239. 滑動窗口最大值(單調隊列)

給你一個整數數組 nums&#xff0c;有一個大小為 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k 個數字。滑動窗口每次只向右移動一位。 返回滑動窗口中的最大值。 示例 1&#xff1a; 輸入&#xff1a;nums [1,3,-1,-3,5,3,6,7], k 3 輸出…

scrape創建_確實在2分鐘內對Scrape公司進行了評論和評分

scrape創建網頁搜羅&#xff0c;數據科學 (Web Scraping, Data Science) In this tutorial, I will show you how to perform web scraping using Anaconda Jupyter notebook and the BeautifulSoup library.在本教程中&#xff0c;我將向您展示如何使用Anaconda Jupyter筆記本…