Пишем первый проект на Play Framework 2.0

в 6:39, , рубрики: java, play framework, scala, web-framework, Веб-разработка, метки: , , ,

13 марта состоялся релиз второй версии scala/java-фреймворка Play. На хабре уже был обзор новых фич Play 2.0. В этой же статье я хочу восполнить пробел в отсутствии мануалов на русском языке по этому интересному фреймворку на примере создания простого приложения на Java, состоящего из списка категорий и привязанных к ним вакансий.

Статья рассчитана на тех, кто совсем не знаком с Play и хотел бы его «пощупать», не тратя много времени.

Для работы с Play 2.0 вам понадобиться JDK 6 и выше. Для своей ubuntu 11.10 я поставил JDK 7.

Создаем проект

1. Скачиваем Play 2.0 и распаковываем туда, где у нас есть права и на запись и на чтение, у меня это /var/www/play20.

2. Переходим в директорию, где вы держите сайты и выполняем скрипт:

/var/www/play20/play new jobs

Ответ на первый вопрос оставляем по умолчанию, на второй выбираем «2 — Create a simple Java application». Для Windows все аналогично, только вы выполняете не shell-скрипт, а .bat.

3. Переходим в созданный проект, входим в консоль play и запускаем проект:

cd jobs
/var/www/play20/play
run

4. Проверяем, что у нас получилось: http://localhost:9000.

5. Теперь для начала разработки на Play 2.0 осталось настроить IDE. Останавливаем сервер и возвращаемся в консоль командой CTRL+D и выполняем eclipsify или idea в зависимости от вашей среды разработки. Для netbeans автоматического создания проекта пока нет.

6. Открываем проект, я использую Eclipse: File > Import > General > Existing Projects into Workspace.

Список категорий

Создаем модель категории app/models/Category.java:

package models;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.Id;

import play.data.validation.*;
import play.db.ebean.Model;

@Entity
public class Category extends Model {
  
  @Id
  public Long id;
  
  @Constraints.Required
  public String title;
  
  public static Finder<Long,Category> find = new Finder (
    Long.class, Category.class
  );
  
  public static List<Category> all() {
    return find.all();
  }
}

В шаблоне главной страницы views/index.scala.html выводим все категории:

@(categories: List
Он «объявит войну несовершенству» и откроет любое авто BYD без ключа. Ещё одна уникальная функция Nubia Z70 Ultra

Nubia официально объявила, что функция NFC смартфона Z70 Ultra теперь поддерживает все автомобили BYD, то есть телефон может полностью заменить ключ от машины и поддерживает разблокировку касанием.

Функция, предоставляемая BYD Auto, позволяет пользователям зарегистрировать мобильный телефон или другое носимое устройство в качестве ключа от машины и использовать его для разблокировки/запирания двери автомобиля и запуска двигателя.

) @main("Jobs") { <ul> @for(category <- categories) { <li>@category.title</li> } </ul> }

Шаблоны в play 2.0 представляют собой html + блоки кода на Scala, которые начинаются с символа '@'. Также стоит обратить внимание, что шаблоны похожи на функции и имеют параметры, которые описываются в начале файла.

Передаем из контроллера приложения app/controllers/Application.java в отредактированный нами выше шаблон список категорий:

import models.Category;

...

public class Application extends Controller {

  public static Result index() {
    return ok(index.render(	Category.all()));
  }
}

Данные для начала будем хранить для простоты просто в памяти, для этого расскоментируем строчки в conf/application.conf:

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"

...

ebean.default="models.*"

Жмем F5 в браузере, нам предложат выполнить SQL-запрос. Кликаем на «Apply this script now!» и мы должны увидеть пустой список ul: у нас пока нет ни одной категории.

Добавление категорий

Добавляем в шаблон app/views/index.scala.html форму добавления категории:

@(categories: List
Он «объявит войну несовершенству» и откроет любое авто BYD без ключа. Ещё одна уникальная функция Nubia Z70 Ultra

Nubia официально объявила, что функция NFC смартфона Z70 Ultra теперь поддерживает все автомобили BYD, то есть телефон может полностью заменить ключ от машины и поддерживает разблокировку касанием.

Функция, предоставляемая BYD Auto, позволяет пользователям зарегистрировать мобильный телефон или другое носимое устройство в качестве ключа от машины и использовать его для разблокировки/запирания двери автомобиля и запуска двигателя.

, categoryForm: Form
Он «объявит войну несовершенству» и откроет любое авто BYD без ключа. Ещё одна уникальная функция Nubia Z70 Ultra

Nubia официально объявила, что функция NFC смартфона Z70 Ultra теперь поддерживает все автомобили BYD, то есть телефон может полностью заменить ключ от машины и поддерживает разблокировку касанием.

Функция, предоставляемая BYD Auto, позволяет пользователям зарегистрировать мобильный телефон или другое носимое устройство в качестве ключа от машины и использовать его для разблокировки/запирания двери автомобиля и запуска двигателя.

) @import helper._ @main("Jobs") { <ul> @for(category <- categories) { <li>@category.title</li> } </ul> @form(routes.Application.add()) { @inputText(categoryForm("title")) <input type="submit" value="Создать"> } }

В шаблоне мы импользуем функции из helper._: функция form создает HTML-форму с заполненными полями action и method, функция inputText генерит текстовый input

Прописываем маршрут в conf/routes:

POST    /add                        controllers.Application.add()

Добавляем в app/controllers/Application.java экшн, который будет создавать новую категорию используя данные, полученные из формы и обновим вызов рендеринга шаблона в экшене index, добавив второй параметр (форму):

import play.data.Form;

...

public static Result index() {
  return ok(index.render(Category.all(), form(Category.class)));
}

public static Result add() {
  Form<Category> filledForm = form(Category.class).bindFromRequest();
  if (filledForm.hasErrors()) {
    return badRequest(index.render(Category.find.all(), filledForm));
  }
  Category category = filledForm.get();
  category.save();
  return redirect(routes.Application.index());
}

Обновляем http://localhost:9000 и пробуем добавлять категории.

На этом месте у меня проект сломался. Чтобы все пересобрать выходим из консоли, вызываем /var/www/play20/play clean-all и заново запускаем.

Вакансии

Модель вакансий app/models/Job.java, связанная один-ко-многим с категориями:

package models;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import play.data.validation.*;
import play.db.ebean.Model;
import play.db.ebean.Model.Finder;

@Entity
public class Job extends Model {
  
  @Id
  public Long id;
  
  @Constraints.Required
  public String title;
  
  @ManyToOne
  public Category category;
  
  public static Finder<Long,Job> find = new Finder(Long.class, Job.class);
}

Добавляем обратную связь в модель категорий app/models/Category.java:

import javax.persistence.OneToMany;

...

@OneToMany(mappedBy="category")
public List<Job> jobs;

Жмем F5, применяем новый SQL.

Теперь мы можем создать шаблон вывода категории views/show.scala.html со всеми ее вакансиями:

@(category: Category, jobForm: Form[Job])

@import helper._

@main("Jobs") {
  
  <h1>@category.title</h1>

  <h2>Вакансии:</h2>
  <ul>
    @for(job <- category.jobs) {
      <li>@job.title</li>
    }
  </ul>
  
  <h2>Добавить вакансию</h2>
  @form(routes.Jobs.аdd(category.id)) {
    @inputText(jobForm("title")) 
    <input type="submit" value="Создать">
  }
}

Добавляем контроллер вакансий app/controllers/Jobs.java, позволяющий добавить новую вакансию, вывод вакансии оставим на потом:

package controllers;

import java.util.List;

import play.*;
import play.data.Form;
import play.mvc.*;

import views.html.*;

import models.*;

public class Jobs extends Controller {

  public static Result add(Long categoryId) {
    Form<Job> filledForm = form(Job.class).bindFromRequest();
    if (filledForm.hasErrors()) {
      Category category = Category.find.byId(categoryId);
      return badRequest(show.render(category, filledForm));
    }
    Job job = filledForm.get();
    job.category = Category.find.ref(categoryId);
    job.save();
    return redirect(routes.Categories.show(categoryId));
  }
  
  public static Result show(Long id) {
    return TODO;
  }
}

Рефакторим категории

Осталось реализовать страницу вывода категории и всех ее вакансий, заодно вынесем из Application-контроллера добавление категорий.

Создаем отдельный контроллер для категорий app/controllers/Categories.java:

package controllers;

import java.util.List;

import play.*;
import play.data.Form;
import play.mvc.*;

import views.html.*;

import models.*;

public class Categories extends Controller {

  public static Result add() {
    Form<Category> filledForm = form(Category.class).bindFromRequest();
    if (filledForm.hasErrors()) {
      return badRequest(index.render(Category.find.all(), filledForm));
    }
    Category category = filledForm.get();
    category.save();
    return redirect(routes.Application.index());
  }
  
  public static Result show(Long id) {
    Category category = Category.find.byId(id);

    return ok(show.render(category, form(Job.class)));
  }
}

Не забываем добавить роуты добавления вакансии, вывода категории и меняем маршрут добавления новых категорий в conf/routes:

GET     /category/:id               controllers.Categories.show(id: Long)
POST    /category/add               controllers.Categories.add()
POST    /job/add                    controllers.Jobs.add(categoryId: Long)

В шаблоне главной страницы views/index.scala.html меняем параметр функции форм, добавленяем ссылки на категории:

@(categories: List
Он «объявит войну несовершенству» и откроет любое авто BYD без ключа. Ещё одна уникальная функция Nubia Z70 Ultra

Nubia официально объявила, что функция NFC смартфона Z70 Ultra теперь поддерживает все автомобили BYD, то есть телефон может полностью заменить ключ от машины и поддерживает разблокировку касанием.

Функция, предоставляемая BYD Auto, позволяет пользователям зарегистрировать мобильный телефон или другое носимое устройство в качестве ключа от машины и использовать его для разблокировки/запирания двери автомобиля и запуска двигателя.

, categoryForm: Form
Он «объявит войну несовершенству» и откроет любое авто BYD без ключа. Ещё одна уникальная функция Nubia Z70 Ultra

Nubia официально объявила, что функция NFC смартфона Z70 Ultra теперь поддерживает все автомобили BYD, то есть телефон может полностью заменить ключ от машины и поддерживает разблокировку касанием.

Функция, предоставляемая BYD Auto, позволяет пользователям зарегистрировать мобильный телефон или другое носимое устройство в качестве ключа от машины и использовать его для разблокировки/запирания двери автомобиля и запуска двигателя.

) @import helper._ @main("Jobs") { <ul> @for(category <- categories) { <li><a href="@routes.Categories.show(category.id)">@category.title</a></li> } </ul> @form(routes.Categories.add()) { @inputText(categoryForm("title")) <input type="submit" value="Создать"> } }

На этом шаге я еще раз пересобрал проект командой play clean-all.

Ресурсы для дальнейшего изучения Play 2.0:

Автор: faost

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js