Laluan Dalam Aplikasi Play di Java

1. Gambaran keseluruhan

Routing adalah konsep umum yang muncul di kebanyakan kerangka kerja pembangunan web termasuk Spring MVC.

Laluan adalah corak URL yang dipetakan ke pengendali. Pengendali dapat berupa fail fizikal, seperti aset yang dapat diunduh dalam aplikasi web atau kelas yang memproses permintaan, seperti pengawal dalam aplikasi MVC.

Dalam tutorial ini, kita akan meneroka aspek routing dalam mengembangkan aplikasi web dengan Play Framework.

2. Persediaan

Pertama, kita perlu membuat aplikasi Java Play. Perincian mengenai cara menyiapkan Play Framework pada mesin terdapat di artikel pengantar kami.

Pada akhir penyediaan, kita seharusnya mempunyai aplikasi Play yang dapat kita akses dari penyemak imbas.

3. Penghalaan HTTP

Oleh itu, bagaimana Play mengetahui pengawal mana yang harus dikonsultasikan setiap kali kami menghantar permintaan HTTP? Jawapan untuk soalan ini terletak pada fail konfigurasi aplikasi / conf / rute .

Penghala Play menerjemahkan permintaan HTTP menjadi panggilan tindakan. Permintaan HTTP dianggap sebagai peristiwa dalam seni bina MVC dan penghala bertindak balas terhadapnya dengan melihat file rute untuk pengawal mana dan tindakan mana yang harus dilaksanakan oleh pengawal tersebut.

Setiap peristiwa ini membekalkan router dengan dua parameter: jalur permintaan dengan rentetan pertanyaannya dan kaedah HTTP permintaan.

4. Laluan Asas Dengan Main

Untuk penghala melakukan tugasnya, fail conf / route mesti menentukan pemetaan kaedah HTTP dan corak URI untuk tindakan pengawal yang sesuai:

GET / controllers.HomeController.index GET / assets/*file controllers.Assets.versioned(path="/public", file: Asset)

Semua fail laluan juga mesti memetakan sumber statik dalam folder play-routing / awam yang tersedia untuk klien di / aset akhir.

Perhatikan sintaks menentukan laluan HTTP, dan kaedah HTTP ruang corak URI ruang tindakan pengawal.

5. Corak URI

Pada bahagian ini, kita akan menjelaskan sedikit mengenai corak URI.

5.1. Corak URI Statik

Tiga corak URI pertama di atas adalah statik. Ini bermaksud pemetaan URL ke sumber berlaku tanpa proses selanjutnya dalam tindakan pengawal.

Selagi kaedah pengawal dipanggil, ia mengembalikan sumber statik yang kandungannya ditentukan sebelum permintaan.

5.2. Corak URI Dinamik

Corak URI terakhir di atas adalah dinamik. Ini bermaksud bahawa tindakan pengawal yang melayani permintaan pada URI ini memerlukan beberapa maklumat dari permintaan untuk menentukan tindak balas. Dalam kes di atas, ia mengharapkan nama fail.

Urutan peristiwa yang biasa adalah bahawa penghala menerima peristiwa, memilih jalan dari URL, menyahkod segmennya, dan meneruskannya ke pengawal.

Parameter jalan dan pertanyaan kemudian disuntikkan ke dalam tindakan pengawal sebagai parameter. Kami akan menunjukkan ini dengan contoh di bahagian seterusnya.

6. Laluan Lanjutan Dengan Main

Di bahagian ini, kita akan membincangkan pilihan lanjutan dalam perutean menggunakan Corak URI Dinamik secara terperinci.

6.1. Parameter Laluan Mudah

Parameter jalan sederhana adalah parameter yang tidak disebutkan namanya dalam URL permintaan yang muncul setelah host dan port dan diuraikan mengikut urutan penampilan.

Di dalam play-routing / app / HomeController.java , mari buat tindakan baru:

public Result greet(String name) { return ok("Hello " + name); }

Kami ingin dapat memilih parameter jalur dari URL permintaan dan memetakannya ke nama pemboleh ubah.

Penghala akan mendapatkan nilai-nilai tersebut dari konfigurasi laluan.

Oleh itu, mari buka play-routing / conf / route dan buat pemetaan untuk tindakan baru ini:

GET /greet/:name controllers.HomeController.greet(name: String)

Perhatikan bagaimana kita memberitahu penghala bahawa nama itu adalah segmen jalan dinamik dengan sintaks kolon dan kemudian teruskan untuk meneruskannya sebagai parameter untuk panggilan tindakan salam.

Sekarang, mari muatkan // locahost: 9000 / salam / john di penyemak imbas, dan kami akan disambut dengan nama:

Hello john

Kebetulan jika parameter tindakan kita adalah jenis rentetan, kita dapat meneruskannya semasa panggilan tindakan tanpa menentukan jenis parameter , walaupun ini tidak sama untuk jenis lain.

Mari raikan titik akhir / salam kami dengan maklumat usia.

Kembali ke HomeController tindakan Greet 's, kami akan mengubahnya kepada:

public Result greet(String name, int age) { return ok("Hello " + name + ", you are " + age + " years old"); }

Dan laluan ke:

GET /greet/:name/:age controllers.HomeController.greet(name: String, age: Integer)

Perhatikan juga sintaks Scala untuk menyatakan pemboleh ubah, umur: Integer . Di Jawa, kita akan menggunakan sintaks usia Integer . Play Framework dibina di Scala. Akibatnya, terdapat banyak sintaksis scala.

Mari memuatkan // localhost: 9000 / salam / john / 26 :

Hello john, you are 26 years old

6.2. Kad Liar dalam Parameter Laluan

Dalam fail konfigurasi laluan kami, pemetaan terakhir adalah:

GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)

We use a wildcard in the dynamic part of the path. What we are telling Play is that whatever value replaces *file in the actual request should be parsed as a whole and not decoded like in other cases of path parameters.

In this example, the controller is a built-in one, Assets, which allows the client to download files from the play-routing/public folder. When we load //localhost:9000/assets/images/favicon.png, we should see the image of the Play favicon in the browser since it's present in the /public/images folder.

Let's create our own example action in HomeController.java:

public Result introduceMe(String data) { String[] clientData = data.split(","); return ok("Your name is " + clientData[0] + ", you are " + clientData[1] + " years old"); }

Notice that in this action, we receive one String parameter and apply our logic to decode it. In this case, the logic is to split a comma-delimited String into an array. Previously, we depended on a router to decode this data for us.

With wildcards, we are on our own. We're hoping that the client gets our syntax correct while passing this data in. Ideally, we should validate the incoming String before using it.

Let's create a route to this action:

GET /*data controllers.HomeController.introduceMe(data)

Now load the URL //localhost:9000/john,26. This will print:

Your name is john, you are 26 years old

6.3. Regex in Path Parameters

Just like wildcards, we can use regular expressions for the dynamic part. Let's add an action that receives a number and returns its square:

public Result squareMe(Long num) { return ok(num + " Squared is " + (num * num)); }

Now we'll add its route:

GET /square/$num controllers.HomeController.squareMe(num:Long)

Let's place this route below the introduceMe route to introduce a new concept. We can only handle routes where the regex part is a positive integer with this routing configuration.

Now if we have placed the route as instructed in the previous paragraph, and we load //localhost:9000/square/2, we should be greeted with an ArrayIndexOutOfBoundsException:

If we check the error logs in the server console, we will realize that the action call was actually performed on introduceMe action rather than squareMe action. As said earlier about wildcards, we are on our own and we did not validate incoming data.

Instead of a comma-delimited string, the introduceMe method was called with the string “square/2“. Consequently, after splitting it, we got an array of size one. Trying to reach index 1 then threw the exception.

Naturally, we would expect the call to be routed to the squareMe method. Why was it routed to introduceMe? The reason is a Play feature we'll cover next called Routing Priority.

7. Routing Priority

If there is a conflict between routes as there is between squareMe and introduceMe, then Play picks the first route in declaration order.

Why is there a conflict? Because of the wildcard context path /*data matches any request URL apart from the base path /. So every route whose URI pattern uses wildcards should appear last in order.

Now let's change the declaration order of the routes such that the introduceMe route comes after squareMe and reload:

2 Squared is 4

To test the power of regular expressions in a route, try loading //locahost:9000/square/-1, a router will fail to match the squareMe route. Instead, it will match introduceMe, and we'll get the ArrayIndexOutOfBoundsException again.

This is because -1 does not match by the provided regular expression, neither does any alphabetic character.

8. Parameters

Up until this point, we've covered the syntax for declaring parameter types in the routes file.

In this section, we'll look at more options available to us when dealing with parameters in routes.

8.1. Parameters With Fixed Values

Sometimes we'll want to use a fixed value for a parameter. This is our way of telling Play to use the path parameter provided or if the request context is the path /, then use a certain fixed value.

Another way of looking at it is having two endpoints or context paths leading to the same controller action — with one endpoint requiring a parameter from the request URL and defaulting to the other in case the said parameter is absent.

To demonstrate this, let's add a writer() action to the HomeController:

public Result writer() { return ok("Routing in Play by Baeldung"); }

Assuming we don't always want our API to return a String:

Routing in Play by Baeldung

We want to control it by sending the name of an author of the article along with the request, defaulting to the fixed value Baeldung only if the request does not have the author parameter.

So let's further change the writer action by adding a parameter:

public Result writer(String author) { return ok("REST API with Play by " + author); }

Let's also see how to add a fixed value parameter to the route:

GET /writer controllers.HomeController.writer(author = "Baeldung") GET /writer/:author controllers.HomeController.writer(author: String)

Notice how we now have two separate routes all leading to the HomeController.index action instead of one.

When we now load //localhost:9000/writer from the browser we get:

Routing in Play by Baeldung

And when we load //localhost:9000/writer/john, we get:

Routing in Play by john

8.2. Parameters With Default Values

Apart from having fixed values, parameters can also have default values. Both provide fallback values to the controller action parameters in case the request does not provide the required values.

The difference between the two is that fixed values are used as a fallback for path parameters while default values are used as a fallback for query parameters.

Path parameters are of the form //localhost:9000/param1/param2 and query parameters are of the form //localhost:9000/?param1=value1¶m2=value2.

The second difference is in the syntax of declaring the two in a route. Fixed value parameters use the assignment operator as in:

author = "Baeldung"

While default values use a different type of assignment:

author ?= "Baeldung"

We use the ?= operator which conditionally assigns Baeldung to author in case author is found to contain no value.

To have a complete demonstration, let's create the HomeController.writer action. Let's say, apart from the author's name which is a path parameter, we also want to pass author id as a query parameter which should default to 1 if not passed in the request.

We'll change writer action to:

public Result writer(String author, int id) { return ok("Routing in Play by: " + author + " ID: " + id); }

dan penulis menghala ke:

GET /writer controllers.HomeController.writer(author="Baeldung", id: Int ?= 1) GET /writer/:author controllers.HomeController.writer(author: String, id: Int ?= 1)

Sekarang memuatkan // localhost: 9000 / penulis yang kita lihat:

Routing in Play by: Baeldung ID: 1

Memukul // localhost: 9000 / penulis? Id = 10 memberi kita:

Routing in Play by: Baeldung ID: 10

Bagaimana dengan // localhost: 9000 / penulis / john ?

Routing in Play by: john ID: 1

Dan akhirnya, // localhost: 9000 / writer / john? Id = 5 mengembalikan:

Routing in Play by: john ID: 5

9. Kesimpulannya

Dalam artikel ini, kami meneroka konsep aplikasi Routing in Play. Kami juga mempunyai artikel tentang membangun RESTful API dengan Play Framework di mana konsep perutean dalam tutorial ini diterapkan dalam contoh praktikal.

Seperti biasa, kod sumber untuk tutorial ini boleh didapati di GitHub.