A File Upload Form in Thymeleaf8:55 with Chris Ramacciotti
In order to allow users the ability to upload a an animated GIF file, we'll need to make sure the HTML form renders with all necessary tags and attributes. In this video we add the enctype attribute to the form tag, and visit the controller to add to the Model all data required by the Thymeleaf template, such as the list of categories to fill the category drop down.
Git Command to Sync Your Code to the Start of this Video
git checkout -f s5v1
Using Github With This Course
You can complete this course entirely using code created by you on your local machine. However, if you choose to use the code I've made available to you, you have two options:
- Use the project files linked at the bottom of this page, or
- Use the Github repository I've made available (recommended)
If you choose the recommended option of using the Github repository, it can be found at
To utilize Github with this course, you can download the Github desktop client for your system or use the command line interface provided with Git.
Clone this repository to your machine using the Github desktop client, or using the following command:
git clone email@example.com:treehouse/giflib-hibernate.git
To update your local repository to match a video's starting point, you can use the
git checkout command in combination with the stage and video number. For example, to update your local repository to match the starting point of Stage 5, Video 4, you'd use the following:
git checkout -f s5v4
Notice the use of the -f option. This forces Git to override all local changes, so be aware: this will cause any changes you made to be lost.
Using a Custom Validator on the Uploaded GIF
Adding validation to the GIF can be a bit tricky, with one reason being that the
MultipartFile is not part of the entity, but should definitely be validated. Currently our
Gif entity uses a
byte field for the GIF's binary image data. We're capturing a
MultipartFile object in the controller method with a
@RequestParam parameter. A nice alternative would be to include the
MultipartFile object as a field in the entity, but we don't want this object to be persisted to the database, so we can mark it as
@Transient (which means it'll exist in our application, but won't be saved to or read from the database).
The advantage of including it as a field is that we can then validate the entire
Gif entity (with the file), and not have to worry about that logic in the controller methods for uploading a new GIF and updating an existing GIF. In order to do this, though, we'll need to write a custom validator.
Check out my Gist on Github to see everything you'll need to make this happen.
[MUSIC] 0:00 Probably the most important feature for 0:04 us to incorporate into Giflib is the ability to upload, well, GIFs. 0:07 And we haven't even touched it yet. 0:11 It's time to change that. 0:13 In order to incorporate a file upload feature, we'll need to make a new addition 0:16 to a standard HTML form, include a parameter in the GIF controller method to 0:19 accept file data, and of course update our service and DAO layer to save it all. 0:24 First, in order to give our users an opportunity to upload a file they've 0:30 saved on their device, we'll need to alter the HTML form element. 0:34 We will need a new attribute called enctype which stands for encryption type. 0:39 Let's open the .gifs form and do that now. 0:43 So that template is located in the templates/gif directory, and 0:47 there is the form template. 0:51 And that attribute that I was just referring to goes inside this form tag, 0:54 ENC type. 0:59 And we will use this multi part/form data value. 1:00 This allows the form submission to include not only simple parameter value pairs but 1:06 also file data. 1:11 And while we're in here let's use object binding on the form just like we did on 1:13 the category form. 1:16 So in this form element, I will bind the gif object. 1:18 Remember that's the dollar sign curly brace notation to 1:23 reference some model attribute named gif. 1:27 And then I'll bind both the description and the category IDs. 1:31 So I'll scroll down here to the description. 1:35 And I will bind the description field. 1:39 Remember when you're binding a field, 1:42 you use the asterisk instead of the dollar sign. 1:43 Description, and down here, we'll use TH field. 1:47 And that will be a category.id. 1:54 Now, notice I use a dot notation here. 1:58 But that's simply because the category property 2:00 is one that is a part of our bound object which is GIF. 2:04 So essentially, it's gif.category.id. 2:08 And this whole select element represents the ID 2:11 of the category that we want to be associated with the GIF that's uploaded. 2:15 Now you'll also notice that I'm not binding this file field here. 2:20 This is because the file property isn't a property of the GIF entity at all. 2:25 And we can certainly make this change and there might be good reason to do so 2:30 to add a file field to the GIF entity. 2:33 Check the teachers notes for more info on this, for now though, 2:37 I'll leave it as is so that the file data is submitted as a parameter named file. 2:40 And so that is indeed passed along with the post request. 2:45 I won't forget the name attribute. 2:50 And let's take care of a couple more items while we're here. 2:53 First let's add those necessary form element attributes the action and 2:56 method attributes. 3:00 So up in the form element I'll say th action equals and 3:01 all have thymeleaf process this URL we will post to the /gifs URI. 3:05 Speaking of post we want to set the method of this form submission as post. 3:12 Next, we should iterate over the actual categories in our app 3:20 instead of displaying a single static category. 3:23 So I will add a th:each attribute here, th:each. 3:27 And here I'll say for every category that all named Cat in this 3:34 model attribute categories, we'll be generating an option for 3:39 each one of the elements that's in the categories model attribute. 3:44 Now for this we'll want to add a value to be sent along with the select element, 3:50 whose name will be the category ID, to the value here will be 3:57 whatever ID this particular category on this iteration of the loop happens to be. 4:03 And the text that will display in this option will be cat.name again. 4:09 That comes from the category entity, there is a name field there. 4:16 And finally let's take care of this static style attribute. 4:21 Let's make Tymelive processes. 4:25 And instead of making it a single static color, let's use time leave concatenation. 4:27 And let's replace this with the value from the cat object, cat.colorcode.. 4:34 Whatever category that we're on during this iteration, 4:41 let's use that Color code as the color value for 4:46 the style attribute and that should do it for now. 4:50 One thing you wanna always take note of while coding your templates. 4:55 If you ever reference an object with this 4:57 dollar sign curly brace notation like this dollar sign GIF. 5:00 Or down here this $ categories then you will need to have 5:05 added those attributes to the model from your controller. 5:10 Either directly or via redirect attributes. 5:13 I see here that those two objects on need to address. 5:17 Again that's the GIF object up here that we'll need to add 5:21 as well as this collection of categories down here. 5:25 Let's switch to the GIF controller now and add those so 5:29 that we don't forget them later. 5:32 So we'll open the GIF controller to do that. 5:34 Let's scroll down to the method that renders a form for adding a new GIF and. 5:38 It is called form new GIF right here. 5:44 Let's start by adding that GIF attribute. 5:48 So we'll do model dot addAttribute we called it GIF the template so 5:51 we'll call it GIF here. 5:57 And we'll create a GIF object using its default contractor. 5:58 Next, we'll add the current list of categories. 6:04 But for this, we need to auto-wire the category service. 6:06 And I'll do that up top. 6:09 So I'll scroll up top. 6:10 And I will auto wire the category service. 6:12 I'll call it category service. 6:19 So now I can scroll back down to where it says. 6:22 Form new gift and I can add that list of categories. 6:24 So we'll say model.addAttribute, we called it categories in the template, so 6:31 let's call it categories here. 6:35 categoryService.findAll. 6:37 At this point our form should render nicely in the browser so 6:42 let's pause to test it all save all my changes here and 6:45 let me stop what I have going here as far as my application instance. 6:49 I all ready had a database server running but 6:56 if you didn't you could certainly execute this command once again. 6:59 So let me rerun that bootRun task, and make sure everything 7:05 compiles correctly and that the application starts successfully as well. 7:10 Cool, started the application. 7:20 Let's switch to Chrome, and 7:22 let's make sure everything comes up nicely in the browser. 7:25 I will click the. 7:28 Upload link to check it out. 7:29 Let's check out this categories dropdown to see if we got all of our 7:31 categories in there. 7:34 And there they are. 7:36 Looks like we're rocking and rolling. 7:38 Hey, one quick note. 7:40 If your Browse button right here isn't working such that when you click it file 7:41 explorer or a file chooser doesn't come up then here's what you want to do. 7:46 It could be because the label on the form can't find an input element whose id 7:52 is file. 7:56 In browsers the four attribute connects labels to input elements using the input 7:57 elements id attribute let me show you what I mean if you go to the form. 8:02 You'll see that the input element has an ID attribute named file and 8:07 I added a name attribute with the value file as well. 8:13 This label element is what renders the button there. 8:18 But when you use this for attribute in a label, whatever value you place here, 8:21 the browser will connect that with its associated input element. 8:27 Using that input elements id attribute not name attribute so 8:31 this is for a file that means this label will be associated with 8:36 this input since this input has an id of file. 8:40 So be sure to check that out if by chance you come up with a browse button 8:45 that doesn't work. 8:50 And next we'll tackle the service for gifs. 8:52
You need to sign up for Treehouse in order to download course files.Sign up