В этой заметке я расскажу про то, какие изменения нужны в одном из шаблонных проектов Play framework 2.5 для принятия мультипарт данных (ключевой элемент — файл с картинкой) в POST запросе и сохранения их в MySQL. В форме будет выпадающий список для перечисления. Потом сделаем вывод загруженных сущностей с картинками в табличке.
Исходники живут тут: github
Файл build.sbt:
name := """play-form""" version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayJava) scalaVersion := "2.11.7" libraryDependencies ++= Seq( // If you enable PlayEbean plugin you must remove these // JPA dependencies to avoid conflicts. javaJpa, "org.hibernate" % "hibernate-entitymanager" % "4.3.7.Final", "mysql" % "mysql-connector-java" % "5.1.38" ) fork in run := true |
Необходимая вставка в application.conf:
db { default.url="jdbc:mysql://localhost:3306/exp" default.driver=com.mysql.jdbc.Driver default.username=root default.password="mypass" default.host=localhost default.jndiName=DefaultDS } |
Файл /app/views/form.scala.html наряду с самой формой содержит пару javascript функций:
loadFile() — показывает уменьшенное изображение выбранной для загрузки картинки, convertToKopeykas() преобразует введенное дробное число рублей в копейки. Это целое число копеек затем хранится в БД. Сама форма:
@helper.form(action = routes.FormController.uploadFile, 'enctype -> "multipart/form-data") { Payment function: <select name="paymentFunction"> @for(pfType < - PaymentFunction.values()){ <option value="@pfType.name()">@pfType.getValue() } </select> <br /> <input type="hidden" name="moneyAmount" id="moneyAmount"/><br /> Sum(roubles): <input type="text" name="roubles" id="roubles"/><br /> Comment: <br /> <textarea rows="4" cols="50" name="comment"></textarea> <br /> Image to be uploaded: <input id="imgInput" type="file" name="scan" accept="image/*" onchange="loadFile(event)" /><br /> <br /> <img id="output" alt="your image" width="80" /> <p> <input type="submit" onclick="convertToKopeykas()"/> </p> } |
Дробное число рублей вводится в поле roubles, но его название не совпадает с именем поля в классе UploadedScan, поэтому туда это дробное число не попадет. А вот значение moneyAmount из скрытого поля — попадет. При этом при возврате в браузере на страницу формы в поле roubles по-прежнему будет число рублей, а не в сто раз большее число копеек.
В файл /conf/routes добавлены маршруты:
GET /form controllers.FormController.renderForm POST /upload controllers.FormController.uploadFile GET /view_all controllers.FormController.getUploadedScans GET /image/:id controllers.FormController.getImage(id:Long) |
В пакет models добавлены 2 файла: PaymentFunction.java с перечислением типов платежей и, собственно UploadedScan.java с описанием сущности для БД. Обратите внимание, что у поля формы с картинкой имя imgInput, а в БД пишется массив байтов с именем:
private byte[] scanFile; |
Это сделано намеренно — чтобы Play при задействовании класса FormFactory не трогал это поле, массив байтов мы заполним вызвав для него сеттер сами. Для хранения в БД поля paymentFunction со значением перечисления выбрана стратегия @Enumerated(EnumType.STRING).
Это может оказаться полезным при изменении порядка элементов в перечислении.
Данные из формы принимает FormController.uploadFile(). На всякий случай для обеспечения уникальности имени файла к нему после символа подчеркивания дописывается эпоха в виде числа миллисекунд. Расширение файла остается прежним. На всякий случай сохраняем значение заголовка Content-type.
Раз уж начали разбирать файл FormController.java, то продолжим. Функция getImage() отправляет по GET запросу вида /image/3 картинку из БД для соответствующей сущности. В обработанном scala шаблоне это выглядит так:
<img src="/image/3"/> |
Метод getUploadedScans() выводит список сохраненных в БД сущностей:
Из видов незатронутым в заметке остался view_all.scala.html. В нем, как явствует из названия, выводится табличка со всему сущностями из БД. Для получения картинки в отдельном GET зпросе используется конструкция вида:
<img src=@{routes.FormController.getImage(scan.getId())}/> |