Matrix variables and path variables are a great way to bind variables in the URL request path. However, there is one more way to bind variables in the HTTP request, not only as a part of the URL but also in the body of the HTTP web request; these are the so-called HTTP parameters. You might have heard about GET or POST parameters; GET parameters have been used for years as a standard way to bind variables in URLs, and POST is used to bind variables in the body of an HTTP request. You will learn about POST parameters in the next chapter during form submission.
Okay, now let's see how to read GET request parameters in the Spring MVC style. To demonstrate the usage of a request parameter, let's add a product details page to our application.
So far in our product listing page, we have only shown product information such as the product's name, description, price, and available units in stock. But we haven't shown information such as the manufacturer, category, product ID, and more. Let's add a product detail page to show them:
ProductRepository
interface from the com.packt.webstore.domain.repository
package in the src/main/java
source folder and add one more method declaration on it as follows:Product getProductById(String productID);
InMemoryProductRepository
implementation class and add an implementation for the previously declared method as follows:@Override public Product getProductById(String productID) { String SQL = "SELECT * FROM PRODUCTS WHERE ID = :id"; Map<String, Object> params = new HashMap<String, Object>(); params.put("id", productID); return jdbcTemplate.queryForObject(SQL, params, new ProductMapper()); }
ProductService
interface and add one more method declaration to it as follows:Product getProductById(String productID);
ProductServiceImpl
service implementation class and add the following method implementation for getProductById
:@Override public Product getProductById(String productID) { return productRepository.getProductById(productID); }
ProductController
class and add one more request mapping method as follows:@RequestMapping("/product") public String getProductById(@RequestParam("id") String productId, Model model) { model.addAttribute("product", productService.getProductById(productId)); return "product"; }
product.jsp
under the src/main/webapp/WEB-INF/views/
directory, add the following code snippets into it, and save it:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/ bootstrap.min.css"> <title>Products</title> </head> <body> <section> <div class="jumbotron"> <div class="container"> <h1>Products</h1> </div> </div> </section> <section class="container"> <div class="row"> <div class="col-md-5"> <h3>${product.name}</h3> <p>${product.description}</p> <p> <strong>Item Code : </strong><span class="label label warning">${product.productId} </span> </p> <p> <strong>manufacturer</strong> : ${product.manufacturer} </p> <p> <strong>category</strong> : ${product.category} </p> <p> <strong>Availble units in stock </strong> : ${product.unitsInStock} </p> <h4>${product.unitPrice} USD</h4> <p> <a href="#" class="btn btn-warning btn-large"> <span class="glyphicon-shopping-cart glyphicon"> </span> Order Now </a> </p> </div> </div> </section> </body> </html>
http://localhost:8080/webstore/market/product?id=P1234
. You will be able to see the product detail page as shown in the following screenshot:In steps 1 and 2, we just created a repository method declaration/implementation to get products for the given product ID (getProductById
). Similarly in steps 3 and 4, we created a corresponding Service layer method declaration and implementation to access the getProductById
method. What we did in step 5 is very similar to what we did in the getProductsByCategory
method of ProductController
. We just added a product object to the model
that is returned by the service object:
model.addAttribute("product", productService.getProductById(productId));
But here, the important question is, who is providing the value for the productId
parameter? The answer is simple, as you guessed; since we annotated the parameter productId
with @RequestParam("id")
annotation (org.springframework.web.bind.annotation.RequestParam
), Spring MVC will try to read a GET request parameter with the name id
from the URL and will assign that to the getProductById
method's parameter productId
.
The @RequestParam
annotation also follows the same convention as other binding annotations; that is, if the name of the GET request parameter and the name of the variable it is annotating are the same, then there is no need to specify the value attribute in the @RequestParam
annotation.
And finally in step 6, we added one more View file called product.jsp
, because we want a detailed view of the product where we can show all the information about the product. Nothing fancy in this product.jsp
file; as usual we are getting the value from the model
and showing it within HTML tags using the usual JSTL expression notation ${}
:
<h3>${product.name}</h3> <p>${product.description}</p> ... ...
Okay, you saw how to retrieve a GET request parameter from an URL, but how do you pass more than one GET request parameter in the URL? The answer is simple: the standard HTTP protocol defines a way for it; we simply need to delimit each parameter value pair with an &
symbol; for example, if you want to pass category
and price
as GET request parameters in a URL, you have to form the URL as follows:
http://localhost:8080/webstore/product?category=laptop&price=700
Similarly, to map this URL in a request mapping method, your request mapping method should have at least two parameters with the @RequestParam
annotation annotated:
public String getProducts(@RequestParam String category, @RequestParam String price) {
For the following request mapping method signature, which is the appropriate request URL?
@RequestMapping(value = "/products", method = RequestMethod.GET) public String productDetails(@RequestParam String rate, Model model)
http://localhost:8080/webstore/products/rate=400
http://localhost:8080/webstore/products?rate=400
http://localhost:8080/webstore/products?rate/400
http://localhost:8080/webstore/products/rate=400
A master detail View is nothing but a display of very important information in a master page; once we select an item in the master View, a detailed page of the selected item will be shown in the detailed View page. Let's build a master detail View for our product listing page, so that, when we click on any product, we can see the detailed View of that product.
We have already implemented the product listing page (http://localhost:8080/webstore/market/products
) and product detail page (http://localhost:8080/webstore/market/product?id=P1234
), so the only thing we need to do is connect those two Views to make it a master detail View. Let's see how to do that:
products.jsp
. You can find products.jsp
under src/main/webapp/WEB-INF/views/
. Add the following spring
tag lib reference on top of the file:<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
Available units in stock
paragraph tag in products.jsp
: <p>
<a href=" <spring:url value="/market/product?
id=${product.productId}" /> " class="btn btn-primary">
<span class="glyphicon-info-sign glyphicon"/></span> Details
</a>
</p>
product.jsp
. You can find product.jsp
under src/main/webapp/WEB-INF/views/
. Add the following spring tag lib reference on top of the file:<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
Order Now
link in product.jsp
:<a href="<spring:url value="/market/products" />" class="btn btn-default"> <span class="glyphicon-hand-left glyphicon"></span> back </a>
http://localhost:8080/webstore/market/products
. You will be able to see the product list page, and every product will have a Details button as shown in the following screenshot:What we did is simple; in step 2 we just added a hyperlink using the following tag in products.jsp
:
<a href=" <spring:url value="/market/product?id=${product.productId}" /> " htmlEscape="true" />" class="btn btn-primary">
<span class="glyphicon-info-sign glyphicon"/></span> Details
</a>
Notice the href
attribute of a <a>
tag, which has a <spring:url>
tag as its value:
<spring:url value="/market/product?id=${product.productId}" />
This <spring:url>
tag is used to construct a valid Spring URL. We need this <spring:url>
to be used in step 2; that's why we added reference to the Spring tag library in step 1. Observe the value attribute of the <spring:url>
tag, and you can see that, for the id
URL parameter, we assigned the expression ${product.productId}
. So during the rendering of this link, Spring MVC will assign the corresponding product ID in that expression.
For example, while rendering the link for the first product, Spring MVC will assign the value P1234
for the product ID. So the final URL value with <spring:url>
in it will become /market/product?id=P1234
, which is nothing but the request mapping path for the product's details page. So when you click this link, you will land on the details page for that particular product.
Similarly, we need a link back to the product listing page from product detail page; that's why we added another link in the product.jsp
tag as follows in step 4:
<a href="<spring:url value="/market/products" />" class="btn btn-default"> <span class="glyphicon-hand-left glyphicon"></span> back </a>
Note the <span>
tag is just to style the button with an icon, so you do not need to pay attention to it too much; the only interesting thing for us is the href
attribute of the <a>
tag, which has the <spring:url>
tag with the value attribute /market/products
in it.
It is good that you learned various techniques to bind parameters with URLs such as using path variables, matrix variables, and GET parameters. We saw how to get the products of a particular category using path variables, how to get products within a particular brand and category using the matrix variable, and finally how to get a particular product by the product ID using a request parameter.
Now imagine you want to apply multiple criteria to view a desired product; for example, what if you want to view a product that falls under the Tablet
category, and within the price range of $200 to $400, and from the manufacturer Google
?
To retrieve a product that can satisfy all this criteria, we can form a URL something like this:
http://localhost:8080/webstore/products/Tablet/price;low=200;high=400?brand="Google"
Why don't you write a corresponding controller method to serve this request URL? Here are some hints to accomplish this requirement:
filterProducts
in the productController
class to map the following URL:http://localhost:8080/webstore/products/Tablet/price;low=200;high=400?brand="Google"
Remember this URL contains matrix variables low
and high
to represent the price range, a GET parameter called brand
to identify the manufacturer, and finally a URI template path variable called Tablet
to represent the category.
products.jsp
to list the filtered products.Good luck!