Repository
https://github.com/playframework/playframework
What Will I Learn?
In this tutorial you will learn the following
- Defining form actions in views
- setting form multipart/form-data enctype
- setting POST and GET Methods for file upload forms in routes
- Rendering an upload form using controller actions
- File upload using multipart/form-data encoding
Requirements
The following are required in order to properly follow along this tutorial.
- Intellij IDEA
- sbt
- playframework with slick installed
- Web browser
- Basic knowledge of Scala programming language
Resources
- Gimp website:- https://www.gimp.org
- Gimp repository:- https://github.com/GNOME/gimp
- Gimp License:- GNU license
Difficulty
- Intermediate
Tutorial Contents
Welcome to today's tutorial on how to build a file upload system using Multipart/form-data in the play(scala) framework. This tutorial is part of a series of tutorials that I hope to present and each one in the series promises to be exciting.
Before we begin I will like to define a basic concept which we need to know in order to properly understand basic file upload.
Multipart/form-data
The Multipart/form-data is an a file encoding type that allows files to be sent using a post request. Which means that for files to be sent through post they must first be encoded using this enctype or encoding type.
This is a standard way of uploading files in a web application as it allows you to mix standard form data with file attachment.
Defining the upload form
before a form is displayed you might sometimes need to create a case class for that form, then define the form by setting it to the apply and unapply methods of the case class. Please note that the case class can be defined out in a separate file which can be referenced, or outside the main class definition in a separate block. source code below
val form = Form(
mapping(
"name" -> text
)(UploadForm.apply)(UploadForm.unapply)
)
Code Explanation
In defining our form we first declare a variable known which we will call
form
The next thing we do is to call the form function which takes in a
mapping
as a parameterinside the mapping we declare a form data known as name and has a type of text, in other cases it can be
filename
,email
, or whatever you want it to belastly we then set it to the UploadForm apply and unapply methods.
After declaring the upload form, we need to create a form action to render the form render the form, we will the define a function called uploader
that would handle file upload requests.
def uploader = Action(parse.multipartFormData) { implicit request =>
request.body.file("file").map { picture =>
picture.ref.moveTo(Paths.get(s"/Users/Alexis/Downloads/"+picture.filename).toFile, replace = true)
Ok("File upload successful")
}.getOrElse {
Redirect(routes.FileUploadController.index).flashing(
"error" -> "File not found")
}
}
Code Explanation
We use the picture.ref.moveTo function to set the destination of the file, the Paths.get function retrieves the file name which is then appended to the correct storage location in our case the file will be uploaded to Users/Alexis/Downloads
The toFile function converts it from a path to file file for upload, while the replace = true statement overwrites any previous existing file of the same file name
We then display an ok that says file upload successful, when the file has been successfully uploaded
To create an alternate condition that is activated when there is an error uploading the file we call the getOrElse Condition which the redirects to the index page
The Redirect() function redirects to routes.FileUploadController.index which is the default route for our application or our application's home page
After the we display a flashing error message to the user that says file not found
Setting the form multipart/form-data enctype
In the views is where we define the form template, this is where we will set the enctype to multipart/form-data
. for a better understanding of this you are advised to read on upload forms using HTML, that might give you a basic understanding of this concept.
@(form: Form[controllers.UploadForm])
@main("Welcome to Play") {
@helper.form(action = routes.FileUploadController.uploader, 'enctype -> "multipart/form-data") {
@helper.inputFile(form("file"))
<input type="submit" value="upload"/>
}
}
Code Explanation
In displaying our form, we begin by setting the form action to
routes.FileUploadController.uploader
, which is the routes that processes the upload request. Theuploader
function has already been defined in our controller.We define a helper for a form input type, which is giving the name,
file
. The@helper.inputFile
is the same as the form input type selection.Finally our submit button is defined using HTML syntax, and the value of the button is set to
upload
Setting POST and GET methods in our routes
Our application cannot be complete without setting both POST and GET methods for our application. Like I said earlier multipart/form-data sends files using POST requests, so it's very important you set this. To set the POST and GET variables we do the following.
GET /fileupload controllers.FileUploadController.index
POST /uploadpage controllers.FileUploadController.uploader
Code Explanation
We set a GET variable which has a URL called
/fileupload
and it maps tocontrollers.FileUploadController.index
. By defualt the index page displays only the form.we set a POST variable known as
/uploadpage
, this is the action that will be activated when the user clicks the upload button. It activates theuploader
function in theFileUploadController
To test our application, go to localhost:9000/fileupload
. Screenshot below
Proof of Work Done
Proof of work done can be found here
https://github.com/leczy642/leczy642-play-scala-file-upload
Curriculum
- Creating a user registration system in play 2.6.x (Scala) using mysql
- Retrieving a particular user and initiating GET requests in play 2.6.x(Scala)
- Updating a particular user in play 2.6.x using slick
- Deleting a User and sorting elements in play(Scala) 2.6.x
- Carrying out aggregations in Play(Scala) 2.6.x
- Retrieving Data From 2 Tables in play 2.6.x(Scala) Using Slick: Part 1