Обрабатываем multipart POST запрос в framework Play 2.5

В этой заметке я расскажу про то, какие изменения нужны в одном из шаблонных проектов 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() выводит список сохраненных в БД сущностей:


play_fr

Из видов незатронутым в заметке остался view_all.scala.html. В нем, как явствует из названия, выводится табличка со всему сущностями из БД. Для получения картинки в отдельном GET зпросе используется конструкция вида:

<img src=@{routes.FormController.getImage(scan.getId())}/>
You can leave a response, or trackback from your own site.

Leave a Reply