A File Upload Form in Thymeleaf

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.

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 git@github.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.

0:00

[MUSIC]

0:04

Probably the most important feature for

0:07

us to incorporate into Giflib is
the ability to upload, well, GIFs.

0:11

And we haven't even touched it yet.

0:13

It's time to change that.

0:16

In order to incorporate a file upload
feature, we'll need to make a new addition

0:19

to a standard HTML form, include a
parameter in the GIF controller method to

0:24

accept file data, and of course update
our service and DAO layer to save it all.

0:30

First, in order to give our users
an opportunity to upload a file they've

0:34

saved on their device,
we'll need to alter the HTML form element.

0:39

We will need a new attribute called
enctype which stands for encryption type.

0:43

Let's open the .gifs form and do that now.

0:47

So that template is located in
the templates/gif directory, and

0:51

there is the form template.

0:54

And that attribute that I was just
referring to goes inside this form tag,

0:59

ENC type.

1:00

And we will use this multi
part/form data value.

1:06

This allows the form submission to include
not only simple parameter value pairs but

1:11

also file data.

1:13

And while we're in here let's use object
binding on the form just like we did on

1:16

the category form.

1:18

So in this form element,
I will bind the gif object.

1:23

Remember that's the dollar
sign curly brace notation to

1:27

reference some model attribute named gif.

1:31

And then I'll bind both
the description and the category IDs.

1:35

So I'll scroll down here
to the description.

1:39

And I will bind the description field.

1:42

Remember when you're binding a field,

1:43

you use the asterisk
instead of the dollar sign.

1:47

Description, and down here,
we'll use TH field.

1:54

And that will be a category.id.

1:58

Now, notice I use a dot notation here.

2:00

But that's simply because
the category property

2:04

is one that is a part of our
bound object which is GIF.

2:08

So essentially, it's gif.category.id.

2:11

And this whole select
element represents the ID

2:15

of the category that we want to be
associated with the GIF that's uploaded.

2:20

Now you'll also notice that I'm
not binding this file field here.

2:25

This is because the file property isn't
a property of the GIF entity at all.

2:30

And we can certainly make this change and
there might be good reason to do so

2:33

to add a file field to the GIF entity.

2:37

Check the teachers notes for
more info on this, for now though,

2:40

I'll leave it as is so that the file data
is submitted as a parameter named file.

2:45

And so that is indeed passed
along with the post request.

2:50

I won't forget the name attribute.

2:53

And let's take care of a couple
more items while we're here.

2:56

First let's add those necessary form
element attributes the action and

3:00

method attributes.

3:01

So up in the form element
I'll say th action equals and

3:05

all have thymeleaf process this
URL we will post to the /gifs URI.

3:12

Speaking of post we want to set the method
of this form submission as post.

3:20

Next, we should iterate over
the actual categories in our app

3:23

instead of displaying
a single static category.

3:27

So I will add a th:each attribute here,
th:each.

3:34

And here I'll say for
every category that all named Cat in this

3:39

model attribute categories,
we'll be generating an option for

3:44

each one of the elements that's in
the categories model attribute.

3:50

Now for this we'll want to add a value to
be sent along with the select element,

3:57

whose name will be the category ID,
to the value here will be

4:03

whatever ID this particular category on
this iteration of the loop happens to be.

4:09

And the text that will display in
this option will be cat.name again.

4:16

That comes from the category entity,
there is a name field there.

4:21

And finally let's take care of
this static style attribute.

4:25

Let's make Tymelive processes.

4:27

And instead of making it a single static
color, let's use time leave concatenation.

4:34

And let's replace this with the value
from the cat object, cat.colorcode..

4:41

Whatever category that we're
on during this iteration,

4:46

let's use that Color code
as the color value for

4:50

the style attribute and
that should do it for now.

4:55

One thing you wanna always take note
of while coding your templates.

4:57

If you ever reference an object with this

5:00

dollar sign curly brace notation
like this dollar sign GIF.

5:05

Or down here this $ categories
then you will need to have

5:10

added those attributes to
the model from your controller.

5:13

Either directly or
via redirect attributes.

5:17

I see here that those two
objects on need to address.

5:21

Again that's the GIF object up
here that we'll need to add

5:25

as well as this collection
of categories down here.

5:29

Let's switch to the GIF controller now and
add those so

5:32

that we don't forget them later.

5:34

So we'll open the GIF
controller to do that.

5:38

Let's scroll down to the method that
renders a form for adding a new GIF and.

5:44

It is called form new GIF right here.

5:48

Let's start by adding that GIF attribute.

5:51

So we'll do model dot addAttribute
we called it GIF the template so

5:57

we'll call it GIF here.

5:58

And we'll create a GIF object
using its default contractor.

6:04

Next, we'll add the current
list of categories.

6:06

But for this,
we need to auto-wire the category service.

6:09

And I'll do that up top.

6:10

So I'll scroll up top.

6:12

And I will auto wire the category service.

6:19

I'll call it category service.

6:22

So now I can scroll back
down to where it says.

6:24

Form new gift and
I can add that list of categories.

6:31

So we'll say model.addAttribute, we
called it categories in the template, so

6:35

let's call it categories here.

6:37

categoryService.findAll.

6:42

At this point our form should
render nicely in the browser so

6:45

let's pause to test it all
save all my changes here and

6:49

let me stop what I have going here
as far as my application instance.

6:56

I all ready had a database
server running but

6:59

if you didn't you could certainly
execute this command once again.

7:05

So let me rerun that bootRun task,
and make sure everything

7:10

compiles correctly and that the
application starts successfully as well.

7:20

Cool, started the application.

7:22

Let's switch to Chrome, and

7:25

let's make sure everything
comes up nicely in the browser.

7:28

I will click the.

7:29

Upload link to check it out.

7:31

Let's check out this categories
dropdown to see if we got all of our

7:34

categories in there.

7:36

And there they are.

7:38

Looks like we're rocking and rolling.

7:40

Hey, one quick note.

7:41

If your Browse button right here isn't
working such that when you click it file

7:46

explorer or a file chooser doesn't come
up then here's what you want to do.

7:52

It could be because the label on the form
can't find an input element whose id

7:56

is file.

7:57

In browsers the four attribute connects
labels to input elements using the input

8:02

elements id attribute let me show you
what I mean if you go to the form.

8:07

You'll see that the input element
has an ID attribute named file and

8:13

I added a name attribute
with the value file as well.

8:18

This label element is what
renders the button there.

8:21

But when you use this for attribute in
a label, whatever value you place here,

8:27

the browser will connect that with
its associated input element.

8:31

Using that input elements id
attribute not name attribute so

8:36

this is for a file that means this
label will be associated with

8:40

this input since this
input has an id of file.

8:45

So be sure to check that out if by
chance you come up with a browse button