So far, we have seen that every request goes through the Controller and returns a corresponding View file for the request, and most of the time these View files contain dynamic content. By dynamic content, I mean that, during the request processing, the model values are dynamically populated in the View file. For example, if the View file is of the type JSP, then we populate the model values in the JSP file using the JSTL notation ${}
.
But what if we have some static content that we want to serve to the client? For example, consider an image that is static content; we don't want to go through Controllers in order to serve (fetch) an image, as there is nothing to process or update in terms of values in the model—we simply need to return the requested image.
Let's say we have a directory (/resources/images/
) that contains some product images and we want to serve those images upon request. For example, if the requested URL is http://localhost:8080/webstore/img/P1234.png
, then we will like to serve the image with the name P1234.png
. Similarly, if the requested URL is http://localhost:8080/webstore/img/P1236.png
, then an image with the name P1236.png
needs to be served.
Let's see how to serve static images with Spring MVC:
src/main/webapp/resources/images/
; I put three product images in: P1234.png
, P1235.png
, and P1236.png
.addResourceHandlers
method from our WebApplicationContextConfig.java
web application context configuration file as follows:@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/img/**") .addResourceLocations("/resources/images/"); }
http://localhost:8080/webstore/img/P1234.png
(change the image name in the URL based on the images you put in the directory in step 1).What just happened was simple. In step 1, we put some image files under the src/main/webapp/resources/images/
directory. And in step 2, we just overrode the addResourceHandlers
method from our web application context configuration file, WebApplicationContextConfig.java
, to tell Spring where those image files are located in our project, so that Spring can serve those files upon request:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/img/**") .addResourceLocations("/resources/images/"); }
The addResourceLocations
method from ResourceHandlerRegistry
defines the base directory location of the static resources that you want to serve. In our case, we want to serve all the images that are available under the src/main/webapp/resources/images/
directory; you may wonder then why we have only given /resources/images
as the location value instead of src/main/webapp/resources/images/
. This is because, during our application build and deployment time, Spring MVC will copy everything available under the src/main/webapp/
directory to the root directory of our web application. So during resource look up, Spring MVC will start looking up from the root directory.
The other method—addResourceHandler
—just indicated the request path that needs to be mapped to this resource directory. In our case, we assigned /img/**
as the mapping
value. So if any web request comes with the request path /img
, then it will be mapped to the resources/images
directory, and the /**
symbol indicates to recursively look for any resource files underneath the base resource directory.
That is why, if you noticed in step 3, we formed the URL as follows: http://localhost:8080/webstore/img/P1234.png
. So while serving this web request, Spring MVC will consider /img/P1234.png
as the request path, so it will try to map /img
to the resource base directory resources/images
. From that directory, it will try to look for the remaining path of the URL, which is /P1234.png
. Since we have the images
directory under the resources
directory, Spring can easily locate the image file from the images
directory.
So in our application, if any request comes with the request path prefix /img
in its URL, then Spring will look into the location
directory that is configured in ResourceHandlerRegistry
and will return the requested file to the browser. Remember Spring allows you to not only host images, but also any type of static files such as PDFs, Word documents, Excel sheets, and so in this fashion.
It is good that we are able to serve product images without adding any extra request mapping methods in our Controller.
Consider the following resource configuration:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/pdf/"); }
Under the pdf
directory, if I have a sub-directory such as product/manuals/
, which contains a PDF file called manual-P1234.pdf
, how can I form the request path to access that PDF file?
/pdf/product/manuals/manual-P1234.pdf
/resources/product/manuals/manual-P1234.pdf
/product/manuals/manual-P1234.pdf
/resource/pdf/product/manuals/manual-P1234.pdf
Let's extend this technique to show the product images in our product listing page and in the product detail page. Perform the following steps:
products.jsp
, which you can find under the /src/main/webapp/WEB-INF/views/
directory in your project, and add the following <img>
tag after the <div class="thumbnail">
tag: <img src="<c:url value="/img/${product.productId}.png">
</c:url>" alt="image" style = "width:100%"/>
product.jsp
and add the following <img>
tag after the <div class="row">
tag: <div class="col-md-5">
<img src="<c:url value="/img/${product.productId}.png">
</c:url>" alt="image" style = "width:100%"/>
</div>
http://localhost:8080/webstore/market/products
. You will be able to see a product list page with every product displaying a product image, as shown in the following screenshot:What we did was simple. You learned how we can serve static resources, and you saw how to host product images. During this exercise, you learned that, in our application, if any request comes with the request path prefix /img
, it will get mapped to the base resource directory and any further remaining URL path will lead to the static file.
We leveraged this fact and formed the image's src
URL accordingly; notice the src
attribute of the <img>
tag we added in step 1:
<img src="<c:url value="/img/${product.productId}.png"></c:url>" alt="image" style = "width:100%"/>
The src
attribute value that we are forming in this <img>
tag has an expression to fetch the product ID. After getting the product ID, we simply concatenate it to the existing value to form a valid request path, as follows:
"/img/${product.productId}.png
For example, if the product ID is P1234
, then we will get an image request URL as /img/P1234.png
, which is nothing but one of the image file names that we already put in the /resources/images
directory. So Spring can easily return that image file, which we showed using the <img>
tag in steps 1 and 2.