著者:朝野有也
こんにちは、香川大学工学部の朝野です。普段からパソコンを使っている方ならJava というプログラミング言語の名前を一度は聞いたことがあると思います。プラットフォームに依存しないため、クライアント側、サーバ側問わず様々なシステムで使用されている言語です。さらに、Java のプログラムを実行するにあたって必要となるJava 仮想マシン(JVM) を利用したJVM 言語というものがあります。JVM 言語は、Java の資源を利用できるのに加えて、Java より後発であるため便利なライブラリや仕組みが揃っていることが多いです。
今回は、簡単な名簿アプリケーションの開発をとおして、JVM 言語の1つであるScala と、Java とScala のWeb アプリケーションフレームワークであるPlay Framework をご紹介します。
記事本文掲載のシェルスクリプトマガジンvol.53は以下リンク先でご購入できます。
sbt のインストール:
https://www.scala-sbt.org/1.x/docs/ja/Setup.html
1 2 3 4 5 6 |
libraryDependencies ++= Seq( ehcache, ws, specs2 % Test, "com.typesafe.play" %% "play-slick" % "3.0.3", "com.typesafe.play" %% "play-slick-evolutions" % "3.0.3", "com.h2database" % "h2" % "1.4.196" ) |
1 2 3 4 5 6 7 8 |
# --- !Ups CREATE TABLE users ( id BIGINT(20) NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, age INTEGER NOT NULL, ); # --- !Downs DROP TABLE "user"; |
1 2 3 4 5 6 7 |
slick.dbs.default { profile = "slick.jdbc.H2Profile$" db.driver = org.h2.Driver db.url = "jdbc:h2:./db/play" db.user = sa db.password = "" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
package models import javax.inject.Inject import models.User import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider} import slick.jdbc.H2Profile import slick.jdbc.H2Profile.api._ import scala.concurrent.Future /** * Userモデル * * @param id 識別ID * @param name ユーザ名 * @param age 年齢 */ case class User(id: Long, name: String, age: Int) /** 以下DAO関連の定義 **/ object UserDAO { val users = TableQuery[UsersTable] } class UserDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[H2Profile] { import scala.concurrent.ExecutionContext.Implicits.global //=== 操作 //== 読み込み def all(): Future[Seq[User]] = db.run(UserDAO.users.result) //== 検索 def findOfId(id: Long): Future[Seq[User]] = { db.run(UserDAO.users.filter(_.id === id).result) } //== 削除 def delete(id: Long): Future[Unit] = { db.run(UserDAO.users.filter(_.id === id).delete).map(_ => ()) } //== 登録 def insert(user: User): Future[Unit] = db.run(UserDAO.users += user).map { _ => () } } //=== テーブル定義 class UsersTable(tag: Tag) extends Table[User](tag, "USERS") { def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) def name = column[String]("NAME") def age = column[Int]("AGE") def * = (id, name, age) <> (User.tupled, User.unapply _) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# トップページ GET / controllers.HomeController.index # 登録 + nocsrf POST /insert/user controllers.HomeController.insertUser # 表示 GET /show/user controllers.HomeController.showUser # 削除 GET /remove/:id controllers.HomeController.deleteUser(id: Long) # リソース GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package controllers import javax.inject._ import models.{User, UserDAO} import play.api.data.Form import play.api.data.Forms.{mapping, nonEmptyText, number} import play.api.i18n.{I18nSupport, MessagesApi} import play.api.mvc._ import scala.concurrent.ExecutionContext //=== 入力フォームクラス case class UserForm(name: String, age: Int) //=== コントローラクラス @Singleton class HomeController @Inject()(cc: ControllerComponents, val userDao: UserDAO, val messages: MessagesApi)(implicit ec: ExecutionContext) extends AbstractController(cc) with I18nSupport { //== 入力フォーム値受け取り用 val form = Form( mapping( "name" -> nonEmptyText(minLength = 2, maxLength = 20), "age" -> number )(UserForm.apply)(UserForm.unapply) ) //== トップページ def index = Action { implicit request => Ok(views.html.index(form)) } //== 表示 def showUser = Action.async { implicit request => userDao.all().map { users => Ok(views.html.show(users)) } } //== 登録 def insertUser = Action.async { implicit request => form.bindFromRequest.fold( formWithErrors => { userDao.all().map(users => Ok(views.html.index(formWithErrors))) }, userForm => { userDao.insert(User(0, userForm.name, userForm.age)).map(_ => Redirect(routes.HomeController.showUser)) } ) } //== 削除 def deleteUser(id: Long) = Action.async { implicit request => userDao.delete(id).map(_ => Redirect(routes.HomeController.showUser)) } } |
1 2 3 4 |
@(userForm: Form[UserForm])(implicit messages: Messages) @import helper._ @main("トップページ") { |
@form(routes.HomeController.insertUser) { @inputText(userForm(“name”), ‘_label -> “名前”) @inputText(userForm(“age”), ‘_label -> “年齢”) }
@form(routes.HomeCon troller.showUser) { }
}
1 2 3 4 |
@(users: Seq[User])(implicit messages: Messages) @import helper._ @main("ユーザ一覧") { |
@for(user <- users ) { }
名前 | 年齢 | ||
---|---|---|---|
@user.name | @user.age | @form(routes.HomeController.deleteUser(user.id)) { } |
@form(routes.HomeController.index) { }
}