Kategória: Scala.
Table of Contents
|
Számos külső könyvtár áll a Scala programozók rendelkezésére. Ne feledjük, hogy a Scala is JVM-re fordít, így lényegében használható a teljes Java könyvtárrendszer. A övetkező oldalak áttekintést nyújtanak a lehetőségekről.
Mindet megnézni képtelenség lenne; lássunk azért párat!
A külső könyvtárak használata
Akár parancssorban használjuk a Scala-t, akár fordítjuk, ahhoz, hogy használni tudjuk a külős könyvtárakat, a legegyszerűbb létrehozni egy build.sbt fájlt.
libraryDependencies += "[groupId]" %% "[artifactId]" % "[version]"
Parancssorból indítva most ne a scala-t indítsuk, hanem ezt:
sbt console
Ha mindent jól csináltunk, akkor automatikusan letölti a könyvtárakat, és azonnal használhatjuk. Fordításkor a már ismertetett build.sbt-be írjuk bele a függőségeket.
JSON
A JSON kezeléséhez a json4s-jackson könyvtárat használjuk. Hozzuk létre az alábbi build.sbt fájlt:
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.0"
Indítsuk el a Scala parancssori értelmezőt: sbt console. Lássuk, hogyan tudjuk visszafejteni a JSON struktúrát Scala osztályokká:
import org.json4s._
import org.json4s.jackson.JsonMethods._
case class Person(name: String, age: Int)
implicit val formats = DefaultFormats
val jsValue = parse("""{"name":"John", "age": 28}""")
jsValue.extract[Person]
Ugyanezt ha fordítani szeretnénk, a következőképpen néz ki:
build.sbt:
name := "jsonexample"
version := "1.0"
scalaVersion := "2.12.7"
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.0"
src/main/scala/JsonExample.scala:
import org.json4s._
import org.json4s.jackson.JsonMethods._
case class Person(name: String, age: Int)
object JsonExample {
def main(args: Array[String]) = {
implicit val formats = DefaultFormats
val jsValue = parse("""{"name":"John", "age": 28}""")
println(jsValue.extract[Person])
}
}
Ez csak egy egyszerű példa a számos lehetőségből; ha használnunk kell, akkor részletesebben el kell benne mélyednünk, célszerűen ezen az oldalon: https://github.com/json4s/json4s.
Egységtesztelés
Ahogy a Java-nak sem része az egységtesztelés, a Scala esetén is külső könyvtárat kell ehhez használnunk. Adjuk a következő sort a build.sbt fájlhoz:
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test"
A forrást, amit tesztelni szeretnénk (src/main/scala/MyAdder.scala):
class MyAdder {
def add(a: Int, b: Int) = a + b
}
Erre készítünk egységtesztet (src/test/scala/MyAdderTest.scala):
import org.scalatest.FlatSpec
class MyAdderTest extends FlatSpec {
"My adder" should "return 5 when adding 2 and 3" in {
val myAdder = new MyAdder
val result = myAdder.add(2, 3)
assert(result == 5)
}
it should "return 0 when adding -2 and 2" in {
val myAdder = new MyAdder
val result = myAdder.add(-2, 2)
assert(result == 0)
}
}
Futtatás:
sbt test
A futtatás lényeges eredménye:
[info] MyAdderTest:
[info] My adder
[info] - should return 5 when adding 2 and 3
[info] - should return 0 when adding -2 and 2
...
[info] All tests passed.
Némi magyarázat a fenti példához: a Scalatest egy rendkívül szerteágazó teszt keretrendszer. Első körben el kell döntenünk, hogy milyen stílust használunk. Ez lehet a Java-ban megszokott Junit4 is (org.scalatest.junit.AssertionsForJUnit), de a Scalaban inkább javasolt más megközelítés. Kezdetnek a Scalatest maga a FlatSpec-et javasolja, amelyben a fenti módon, szinte "emberi nyelven" tudjuk megadni az egységteszteket. Bővebb információt ezen az oldalon olvashatunk: http://www.scalatest.org/user_guide.
Adatbázis kapcsolat
A Scala-nak nincs saját adatbázis kapcsolat kezelője, a Java-s JDBC-t tudjuk használni erre a célra. Példaként a MySQL-t fogjuk használni, ehhez hozzuk létre a teszt adatbázist az adatbázisok oldalon leírtak alapján. Lássuk, hogyan tudunk ebből kiolvasni Scala-ban! Mindenekelőtt adjuk hozzá a megfelelő függőséget a build.sbt fájlhoz (ügyeljünk a megfelelő verzióra):
libraryDependencies += "mysql" % "mysql-connector-java" % "8.0.15"
Ügyeljünk a megfelelő verzióra; én belefutottam abba, hogy rossz verziót használtam, és furcsa hibaüzenettel állt le a program. Pl. itt tudjuk megnézni a pontos legfrissebb verziókat: https://mvnrepository.com/artifact/mysql/mysql-connector-java. Majd hozzuk létre meg a következő programot:
object JdbcExample {
def main(args: Array[String]) = {
Class.forName("com.mysql.cj.jdbc.Driver")
val connection = java.sql.DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "csaba", "farago")
val statement = connection.createStatement
val rs = statement.executeQuery("SELECT name, age FROM person")
while (rs.next()) {
val name = rs.getString("name")
val age = rs.getInt("age")
println(name + " (" + age + ")")
}
connection.close()
}
}
Ez egy rendkívül leegyszerűsített program, hibakezelés sincs benne. Ha mindent jól csináltunk lés lefuttatjuk a programot, akkor az eredmények az alábbinak kell lennie:
Sanyi (34)
Kata (32)
Pista (46)
Web kliens
Láthattunk hogy egyszerű HTTP GET lekérést standard Scala eszközzel is el tudjuk érni (scala.io.Source.fromURL()). A tapasztalatom szerint viszont már a legegyszerűbb esetben is hibába futhatunk, ill. ennél bonyolultabb esetekre (pl. HTTP POST) már nem igazán alkalmas. Célszerű a HTTP-hez külső könyvtárat használni.
Számos HTTP könyvtár létezik Scala-hoz, mi most a scalaj könyvtárat nézzük meg. Adjuk a build.sbt-hez az alábbi függőséget:
libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2"
Ekkor a legegyszerűbb HTTP GET kérés a következőképpen néz ki:
scalaj.http.Http("http://faragocsaba.hu").asString
Számos egyéb HTTP műveletet végre lehet hajtani. A részletekért javaslom a dokumentáció átolvasását (https://github.com/scalaj/scalaj-http) és a példaprogramokat (pl. https://github.com/scalaj/scalaj-http/blob/master/src/test/scala/scalaj/http/HttpBinTest.scala).
Web szerver
Web szerverként az Akka keretrendszert használhatjuk. Lássunk egy példát! A build.sbt fájlhoz adjuk hozzá a következő függőségeket:
libraryDependencies += "com.typesafe.akka" %% "akka-http" % "10.1.10"
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % "2.5.23"
Majd készítsük el a következő kódot:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn
object WebServer {
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
val route = path("greetings") {
get {
parameter("name") {name => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "Hello, " + name + "!"))}
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println("Server online. Open a page like http://localhost:8080/greetings?name=Csaba for testing.\nPress RETURN to stop...")
StdIn.readLine()
bindingFuture
.flatMap(_.unbind())
.onComplete(_ => system.terminate())
}
}
Indítsuk el. Ahogy a kódban is látható, nyissuk meg a http://localhost:8080/greetings?name=Csaba oldalt (a saját nevünket írjuk az URL-be). Ha mindent jól csináltunk, akkor megjelenik a Hello, Csaba! szöveg.
Ezzel is épp hogy csak a felszínt karcoltuk. A további részletekért használjuk a dokumentációt.