Most applications have the ability to upload something. Handling uploaded files should not be hard. We need to check if user uploaded the file, if it’s the right type and store it. Mather of fact, this is really easy with Play Framework.
An example
We have a form to upload a file.
1 2 3 |
<form action="/upload" method="POST" enctype="multipart/form-data"> <input type="file" name="file" /> </form> |
This form will take one file and post it to /upload path. To be able to upload a file, we need to define enctype to multipart/form-data. This just means how the POST will be constructed and how the file will be send.
Next this is to create a controller and a method. We will only enable uploading of PDF files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package controllers; import play.mvc.Result; import static play.mvc.Results.badRequest; import static play.mvc.Results.ok; import play.mvc.Controller; import play.mvc.Http; public class Uploads extends Controller { public static Result upload() { Http.MultipartFormData body = request().body().asMultipartFormData(); if(body == null) { return badRequest("Invalid request, required is POST with enctype=multipart/form-data."); } Http.MultipartFormData.FilePart filePart = body.getFile("file"); if(filePart == null) { return badRequest("Invalid request, no file has been sent."); } // getContentType can return null, so we check the other way around to prevent null exception if(!"application/pdf".equalsIgnoreCase(filePart.getContentType()) { return badRequest("Invalid request, only PDFs are allowed."); } File file = filePart.getFile(); // handle file return ok(); } } |
Very simple, right? I highly recommend you move this code to somewhere else (for example to some service). Good practice is to keep controllers slim.
First we need to check type of the request and check if it’s multipart/form-data. If body is null, then something is wrong. Same thing is for a file. If there is no file present, we need to report an error. Beware, it’s easy to modify the content type. Checking if the file is really PDF can sometimes be more difficult. Best ways are to use some additional libraries – one of the is Apache Tika.
Handling multiple files
We can also handle multiple file at once. All we have to do is loop through all posted files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package controllers; import play.mvc.Result; import static play.mvc.Results.badRequest; import static play.mvc.Results.ok; import play.mvc.Controller; import play.mvc.Http; import java.util.List; public class Uploads extends Controller { public static Result upload() { Http.MultipartFormData body = request().body().asMultipartFormData(); if(body == null) { return badRequest("Invalid request, required is POST with enctype=multipart/form-data."); } List<Http.MultipartFormData.FilePart> fileParts = body.getFiles(); if(fileParts.isEmpty()) { return badRequest("Invalid request, no files have been included in the request."); } for(Http.MultipartFormData.FilePart filePart: fileParts) { if(!"application/pdf".equalsIgnoreCase(filePart.getContentType()) { return badRequest("Invalid request, only PDFs are allowed."); } File file = filePart.getFile(); // handle file } return ok(); } } |
Extra tip
When we upload the file, it will be stored into /tmp folder (of course if we use Linux server). Then we just need to move or copy the file to the right folder.
Recommended way is to use highly tested library Apache Commons IO and methods FileUtils.copyFile(source, destination) or FileUtils.moveFile(source, destination).
1 2 3 4 5 6 7 8 9 10 |
try { File file = filePart.getFile(); File destination = new File("/home/app/uploads/", file.getName()); FileUtils.moveFile(file, destination); } catch(IOException ex) { // something went wrong, handle it } |