Первый взгляд на веб-фреймворк без JavaScript

Scala — сильный статически типизированный язык программирования общего назначения, поддерживающий объектно-ориентированное и функциональное программирование. Play — это веб-фреймворк, который создает веб-приложения на Scala и Java. Play поставляется с Twirl, механизмом шаблонов на основе Scala, который имеет следующие преимущества:

  • Компактный, выразительный и плавный: он сводит к минимуму количество символов и нажатий клавиш, необходимых в файле, и обеспечивает быстрый и плавный рабочий процесс кодирования.
  • Простота в освоении: в нем есть минимум концепций для изучения, помимо конструкций Scala и знаний HTML.
  • Не новый язык: это просто Scala + HTML.
  • Редактируется в любом текстовом редакторе: простого редактора должно быть достаточно для продуктивной работы с кодом.

Play — это веб-фреймворк, не использующий JavaScript, и он рендерится на стороне сервера. Мы собираемся изучить, как работает веб-приложение Play.

Настройка игровой среды

Lightbend Tech Hub предлагает загружаемые примеры Play для Java и Scala. Обучение на примере — это эффективный способ мгновенно подготовить среду.

Это ссылка для загрузки примера, Play Scala Hello World. Разархивируйте загруженный файл play-samples-play-scala-hello-world-tutorial.zip в локальный каталог.

Play требует Java и sbt с некоторыми требованиями к версии:

  • Java Software Developer’s Kit (SE) 1.8 или выше, который можно скачать здесь.
  • sbt 1.3.4 или более поздней версии, которая включена в zip-файл. Как вариант, его можно скачать здесь.

sbt — это интерактивный инструмент сборки для Scala, Java и т. д. Он работает на JVM.

Проверьте версии, чтобы убедиться, что Java и sbt соответствуют требованиям.

% pwd
/Users/jenniferfu/play-samples-play-scala-hello-world-tutorial
% java --version 
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode)
% sbt --version
sbt version in this project: 1.7.2
sbt script version: 1.6.2

Выполнить sbt run:

% sbt run
[info] welcome to sbt 1.7.2 (AdoptOpenJDK Java 11.0.11)
[info] loading project definition from /Users/jenniferfu/play-samples-play-scala-hello-world-tutorial/project/project
[info] loading settings for project play-samples-play-scala-hello-world-tutorial-build from plugins.sbt,scaffold.sbt ...
[info] loading project definition from /Users/jenniferfu/play-samples-play-scala-hello-world-tutorial/project
[info] loading settings for project root from build.sbt ...
[info]   __              __
[info]   \ \     ____   / /____ _ __  __
[info]    \ \   / __ \ / // __ `// / / /
[info]    / /  / /_/ // // /_/ // /_/ /
[info]   /_/  / .___//_/ \__,_/ \__, /
[info]       /_/               /____/
[info] 
[info] Version 2.8.18 running Java 11.0.11
[info] 
[info] Play is run entirely by the community. Please consider contributing and/or donating:
[info] https://www.playframework.com/sponsors
[info] 
--- (Running the application, auto-reloading is enabled) ---
[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
(Server started, use Enter to stop and go back to the console...)

Пример доступен из браузера по адресу http://localhost:9000.

Вот рабочий процесс:

  1. Браузер запрашивает корневой URI / с HTTP-сервера, используя метод GET.
  2. Внутренний HTTP-сервер Play получает запрос.
  3. Play разрешает запрос, используя файл routes, который сопоставляет URI с методами действия контроллера.
  4. Метод действия отображает страницу index, которая является шаблоном Twirl.
  5. HTTP-сервер возвращает ответ в виде HTML-страницы.

Архитектура модель-представление-контроллер

Приложение Play использует Model-View-Controller (MVC), широко используемый архитектурный шаблон программного обеспечения для разработки пользовательских интерфейсов (UI).

  • Модель является центральным компонентом выкройки. Это хранилище динамических данных приложения, независимое от пользовательского интерфейса.
  • Представление — это любое представление информации, состоящее из заголовка, нижнего колонтитула, боковой панели, представления содержимого и/или других компонентов.
  • Контроллер принимает ввод и преобразует его в команды для модели или представления.

Дерево исходного кода приложения Play

Разархивированный play-samples-play-scala-hello-world-tutorial выглядит так:

play-samples-play-scala-hello-world-tutorial
├── README.md
├── .g8
├── app
│   ├── controllers
│   └── views
├── conf
├── logs
│   └── application.log
├── project
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
├── sbt-dist
├── scripts
│   └── test-sbt
├── target
├── build.sbt
├── sbt
└── sbt.bat
  • play-samples-play-scala-hello-world-tutorial: это каталог проекта для приложения Play.
  • README.md: Это файл README, в котором описаны требования к проекту и этапы выполнения.
  • .g8: это каталог, сгенерированный play-scala-seed.g8, шаблоном для создания сида проекта Play в Scala. Этот шаблон был использован для создания этого проекта.
  • app: это каталог, содержащий код MVC, где находятся все исполняемые артефакты, включая исходный код Java и Scala, шаблоны и исходники скомпилированных ресурсов. В этом примере он содержит два пакета, controllers и views. При наличии внешнего хранилища данных можно добавить пакет models. Кроме того, можно добавить пакет service и utils.
  • conf: это каталог, содержащий конфигурацию приложения, включая routes.
  • logs: это каталог, содержащий журналы, где application.log — файл журнала по умолчанию.
  • project: это каталог, содержащий sbt файлов конфигурации.
  • public: это каталог для статических ресурсов, обслуживаемых непосредственно веб-сервером. Есть три подкаталога: images, javascripts и stylesheets.
  • sbt-dist: это каталог, содержащий распространяемый файл sbt.
  • scripts: это каталог, содержащий sbt скриптов, где скрипт test-sbt выполняет тесты с использованием sbt.
  • target: это каталог, содержащий сгенерированный код и документы API.
  • build.sbt: это скрипт сборки, который выполняет проект в текущем каталоге (строка 1 ниже) с указанным плагином (строка 2) и настройками (строки 3–17). Обычной практикой является объявление отложенной загрузки проекта (строка 1).
  • sbt: это исполняемый файл, который вызывает распределенный скрипт sbt с более чем 600 строками кода.
#!/usr/bin/env bash
./sbt-dist/bin/sbt "$@"

Ниже приводится использование sbt:

Usage: `basename "$0"` [options]
  -h | --help         print this message
  -v | --verbose      this runner is chattier
  -V | --version      print sbt version information
  --numeric-version   print the numeric sbt version (sbt sbtVersion)
  --script-version    print the version of sbt script
  -d | --debug        set sbt log level to debug
  -debug-inc | --debug-inc
                      enable extra debugging for the incremental debugger
  --no-colors         disable ANSI color codes
  --color=auto|always|true|false|never
                      enable or disable ANSI color codes      (sbt 1.3 and above)
  --supershell=auto|always|true|false|never
                      enable or disable supershell            (sbt 1.3 and above)
  --traces            generate Trace Event report on shutdown (sbt 1.3 and above)
  --timings           display task timings report on shutdown
  --sbt-create        start sbt even if current directory contains no sbt project
  --sbt-dir   <path>  path to global settings/plugins directory (default: ~/.sbt)
  --sbt-boot  <path>  path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
  --ivy       <path>  path to local Ivy repository (default: ~/.ivy2)
  --mem    <integer>  set memory options (default: $sbt_default_mem)
  --no-share          use all local caches; no sharing
  --no-global         uses global caches, but does not use global ~/.sbt directory.
  --jvm-debug <port>  Turn on JVM debugging, open at the given port.
  --batch             disable interactive mode
  # sbt version (default: from project/build.properties if present, else latest release)
  --sbt-version  <version>   use the specified version of sbt
  --sbt-jar      <path>      use the specified jar as the sbt launcher
  # java version (default: java from PATH, currently $(java -version 2>&1 | grep version))
  --java-home <path>         alternate JAVA_HOME
  # jvm options and output control
  JAVA_OPTS           environment variable, if unset uses "$default_java_opts"
  .jvmopts            if this file exists in the current directory, its contents
                      are appended to JAVA_OPTS
  SBT_OPTS            environment variable, if unset uses "$default_sbt_opts"
  .sbtopts            if this file exists in the current directory, its contents
                      are prepended to the runner args
  /etc/sbt/sbtopts    if this file exists, it is prepended to the runner args
  -Dkey=val           pass -Dkey=val directly to the java runtime
  -J-X                pass option -X directly to the java runtime
                      (-J is stripped)
  -S-X                add -X to sbt's scalacOptions (-S is stripped)
In the case of duplicated or conflicting options, the order above
shows precedence: JAVA_OPTS lowest, command line options highest.
@JenniferFuBook
 
Add heading textAdd bold text, <Cmd+b>Add italic text, <Cmd+i>
Add a quote, <Cmd+Shift+.>Add code, <Cmd+e>Add a link, <Cmd+k>
Add a bulleted list, <Cmd+Shift+8>Add a numbered list, <Cmd+Shift+7>Add a task list, <Cmd+Shift+l>
Directly mention a user or team
Reference an issue or pull request
Leave a comment
  • sbt.bat: это исполняемый файл, который вызывает скрипт запуска распределенного sbt с более чем 900 строками кода.
@REM SBT launcher script
.\sbt-dist\bin\sbt.bat %*

Контроллеры игрового приложения

Контроллер управляет приложением MVC на основе рабочего процесса. Он принимает ввод и преобразует его в команды для модели или представления. Контроллер в Play — это не что иное, как объект, который генерирует Action значений. Контроллеры воспроизведения обычно определяются как классы, чтобы использовать преимущества внедрения зависимостей.

app/controllers — рекомендуемый каталог для контроллеров. Из коробки есть один контроллер, HomeController.scala.

controllers
└── HomeController.scala

Вот app/controllers/HomeController.scala:

  • В строке 1 пакет controllers создается путем объявления его в верхней части файла Scala. Было бы удобно назвать пакет так же, как каталог, содержащий файл Scala. Однако Scala не зависит от расположения файлов.
  • В строке 3 импортируется все содержимое пакета javax.inject. javax — это соглашение об именах для расширения JRE. Приведенный выше код имеет синтаксис Scala 2: import javax.inject._. В Scala 3 это будет записано как import javax.inject.*.
  • В строке 4 импортируется все содержимое пакета play.api.
  • В строке 5 импортируется все содержимое пакета play.api.mvc.
  • В строках 11–33 создается класс с одноэлементной записью (строка 11). Он вызывает идиоматический API Play для Action, расширяя AbstractController (строка 12). Этот контроллер определяет три действия для трех маршрутов: index(/), explore(/explore) и tutorial (/tutorial).
  • В строках 21–23 он определяет метод index, который представляет собой Action, возвращающий Ok(views.html.index()). Он генерирует HTML-страницу, определенную index.scala.html, шаблоном Twirl в views.
  • В строках 25–27 он определяет метод explore, который представляет собой Action, возвращающий Ok(views.html.explore()). Он генерирует HTML-страницу, определенную explore.scala.html, шаблоном Twirl в views.
  • В строках 29–31 он определяет метод tutorial, который представляет собой Action, возвращающий Ok(views.html.tutorial()). Он создает HTML-страницу, определенную tutorial.scala.html, шаблоном Twirl в views.

Просмотры приложения Play

Представление производит ответ для браузера. Он получает данные от модели и представляет их браузеру для отображения. Это может быть полное представление маршрута или подвид, составляющий целое представление.

app/views — рекомендуемый каталог для представлений. По умолчанию есть несколько файлов представлений, написанных как шаблоны Twirl с расширениями .scala.html.

views
├── main.scala.html
├── commonSidebar.scala.html
├── index.scala.html
├── explore.scala.html
└── tutorial.scala.html

main.scala.html отображает head и body. Он принимает два аргумента: String для заголовка страницы и объект Html для вставки в тело страницы. Другие шаблоны Twirl используют его для создания HTML-страницы.

Вот app/views/main.scala.html:

  • В строке 7 он определяет конструктор с двумя аргументами: title и content.
  • В строках 9–32 это шаблон HTML, где он определяет head (строки 12–20) и body (строки 22–30).
  • В строке 13 @title является динамическим значением, которое вычисляется из аргумента title.
  • В строках 23–28 определяется заголовок страницы.
  • В строке 29 @content является динамическим значением, которое вычисляется из аргумента content.

Включая этот шаблон, на странице будет отображаться следующий заголовок:

commonSidebar.scala.html определяет main.scala.html, который не принимает аргументов.

Вот app/views/commonSidebar.scala.html:

  • В строке 1 он определяет конструктор без аргументов.
  • В строке 2 он устанавливает version в значение play.core.PlayVersion.current.
  • В строках 3–8 он определяет список оглавления, где @routes.HomeController.index() (строка 5), @routes.HomeController.explore() (строка 6) и @routes.HomeController.tutorial() (строка 7) — функции маршрута.
  • В строках 9–16 он определяет список связанных ресурсов, где @version (строка 11) — динамическое значение.

Вот дисплей пользовательского интерфейса:

index.scala.html — это шаблон Twirl, который вызывается маршрутом index (/).

Вот app/views/index.scala.html:

  • В строке 1 он определяет конструктор без аргументов.
  • В строках 3–71 директива main (строка 3) вызывает шаблон main, main.scala.html, с двумя параметрами.
    - заголовок: "Welcome"
    - содержание: строки 4–71, где @commonSidebar() (строка 66) ​​— это общая боковая панель, определенная в commonSidebar.scala.html.

Вот дисплей пользовательского интерфейса:

explore.scala.html — это шаблон Twirl, который вызывается маршрутом explore (/explore).

Вот app/views/explore.scala.html:

  • В строке 1 он определяет конструктор без аргументов.
  • В строках 3–90 директива main (строка 3) вызывает шаблон main, main.scala.html, с двумя параметрами для создания страницы.
    - заголовок: "Hello World"
    - содержание: строки 4–90, где @commonSidebar() (строка 84) — это общая боковая панель, определенная в commonSidebar.scala.html.

Вот дисплей пользовательского интерфейса:

tutorial.scala.html — это шаблон Twirl, который вызывается маршрутом tutorial (/tutorial).

Вот app/views/tutorial.scala.html:

  • В строке 1 он определяет конструктор без аргументов.
  • В строках 3–162 директива main (строка 3) вызывает шаблон main, main.scala.html, с двумя параметрами для создания страницы.
    - заголовок: "Hello World"
    - содержание: строки 4–162, где @commonSidebar() (строка 157) — это общая боковая панель, определенная в commonSidebar.scala.html.

Вот дисплей пользовательского интерфейса:

Поскольку шаблоны отображаются на сервере, нет необходимости использовать REST API для конечных точек. Шаблоны Twirl могут получать доступ к моделям через код Scala.

Конфигурация игрового приложения

conf — это каталог, содержащий конфигурацию приложения (скомпилированную) и другие нескомпилированные ресурсы на classpath. Из коробки есть эти файлы.

conf
├── routes
├── application.conf
├── logback.xml
└── messages

Маршрутизатор — это компонент, отвечающий за преобразование каждого входящего HTTP-запроса в действие контроллера. HTTP-запрос рассматривается платформой MVC как событие. Это событие содержит две основные части информации:

  • Путь запроса, включая строку запроса
  • Метод HTTP (GET, POST, PUT, DELETE и т. д.)

routes — это файл конфигурации, используемый маршрутизатором. Он разрешает входящий HTTP-запрос, находя правильный URI и затем сопоставляя его с методом действия контроллера. Один и тот же запрос может соответствовать многим маршрутам.

Вот app/conf/routes:

  • В строке 7 для метода GET маршрута index вызывается метод /, HomeController index.
  • В строке 8 для метода GET маршрута explore вызывается метод /explore, HomeController explore.
  • В строке 9 для метода GET маршрута tutorial вызывается метод /tutorial, HomeController tutorial.
  • В строке 13 для метода GET маршрута актива, /assets/*file, вызывается метод versioned встроенного контроллера Assets с путем (/public) и именем file. *file — это динамическая часть, соответствующая регулярному выражению .*.

Перейдите по URL-адресу http://localhost:9000/assets/images/play-stack.png, и появится следующее изображение:

Что делать, если есть конфликт в routes?

Будет использоваться первый маршрут в порядке объявления.

Что делать, если в routes есть ошибка?

Ошибка маршрута будет отображаться непосредственно в браузере, поскольку этот файл был скомпилирован.

Вот пример несопоставленного маршрута /xyz:

При необходимости API REST можно настроить в маршрутах. В этой статье объясняется, как реализовать REST API в маршрутах.

Помимо routes, есть и другие файлы конфигурации, application.conf, logback.xml и messages.

Заключение

Play — это веб-фреймворк, который создает веб-приложения с помощью Scala и Java. Веб-страницы отображаются на стороне сервера и пишутся с помощью шаблонов Twirl.

Для разнообразия мы изучили веб-фреймворк без JavaScript. Все они манипулируют HTML, но их синтаксис и терминология различаются.

Все дороги ведут к веб-приложениям.

Спасибо за прочтение.

Спасибо, С. Шрирам, Ноа Джексон и Сиддхартха Чинтхапалли, за работу со мной над веб-приложениями Play.

Want to Connect?

If you are interested, check out my directory of web development articles.