Interceptors are a great way to add logic that needs to be executed during every request to our web application. The cool thing about interceptors is that, not only can we have a logic that executes before and/or after the request, we can even bypass or redirect the original web request itself. So far, we have seen a couple of examples of interceptors, such as performance logging and internationalization, but one problem with those examples is that there is no proper way to stop them from being run for specific requests.
For example, we might have a specific web request that does not need to run that additional logic in our interceptor. How can we tell Spring MVC to selectively include or exclude interceptors? Mapped interceptors to the rescue; using mapped interceptors we can selectively include or exclude interceptors, based on a mapped URL. Mapped interceptors use Ant-based path pattern matching to determine whether a web request path matches the given URL path pattern.
Consider a situation where you want to show the special-offer products page only to those users who have a valid promo code, but others who are trying to access the special-offer products page with an invalid promo code should be redirected to an error page.
Let's see how we can achieve this piece of functionality with the help of a mapped interceptor:
PromoCodeInterceptor
under the com.packt.webstore.interceptor
package in the src/main/java
source folder, and add the following code to it:package com.packt.webstore.interceptor; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.handler .HandlerInterceptorAdapter; public class PromoCodeInterceptor extends HandlerInterceptorAdapter { private String promoCode; private String errorRedirect; private String offerRedirect; public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException{ String givenPromoCode = request.getParameter("promo"); if (promoCode.equals(givenPromoCode)) { response.sendRedirect(request.getContextPath() + "/" + offerRedirect); } else { response.sendRedirect(errorRedirect); } return false; } public void setPromoCode(String promoCode) { this.promoCode = promoCode; } public void setErrorRedirect(String errorRedirect) { this.errorRedirect = errorRedirect; } public void setOfferRedirect(String offerRedirect) { this.offerRedirect = offerRedirect; } }
PromoCodeInterceptor
in our web application context (WebApplicationContextConfig.java
) as follows:@Bean public HandlerInterceptor promoCodeInterceptor() { PromoCodeInterceptor promoCodeInterceptor = new PromoCodeInterceptor(); promoCodeInterceptor.setPromoCode("OFF3R"); promoCodeInterceptor.setOfferRedirect("market/products"); promoCodeInterceptor.setErrorRedirect("invalidPromoCode"); return promoCodeInterceptor; }
PromoCodeInterceptor
interceptor bean in our InterceptorRegistry
as follows:@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ProcessingTimeLogInterceptor()); LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); localeChangeInterceptor.setParamName("language"); registry.addInterceptor(localeChangeInterceptor); registry.addInterceptor(promoCodeInterceptor()) .addPathPatterns("/**/market/products/specialOffer"); }
ProductController
class and add one more request mapping method as follows: @RequestMapping("/products/invalidPromoCode")
public String invalidPromoCode() {
return "invalidPromoCode";
}
invalidPromoCode.jsp
under the directory src/main/webapp/WEB-INF/views/
, add the following code snippets to it, and save it: <%@ taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring"
uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<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>Invalid promo code</title>
</head>
<body>
<section>
<div class="jumbotron">
<div class="container">
<h1 class="alert alert-danger"> Invalid promo
code</h1>
</div>
</div>
</section>
<section>
<div class="container">
<p>
<a href="<spring:url value="/market/products" />"
class="btn btn-primary">
<span class="glyphicon-hand-left glyphicon">
</span> products
</a>
</p>
</div>
</section>
</body>
</html>
http://localhost:8080/webstore/market/products/specialOffer?promo=offer
URL; you should be able to see an error message page as follows:http://localhost:8080/webstore/market/products/specialOffer?promo=OFF3R
URL; you will land on a special-offer products page.The PromoCodeInterceptor
class that we created in step 1 is very similar to ProcessingTimeLogInterceptor
; the only difference is that we have extended HandlerInterceptorAdapter
and only overridden the preHandle
method:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException{ String givenPromoCode = request.getParameter("promo"); if (promoCode.equals(givenPromoCode)) { response.sendRedirect(request.getContextPath() + "/" + offerRedirect); } else { response.sendRedirect(errorRedirect); } return false; }
In the preHandle
method, we are simply checking whether the request contains the correct promo code as the HTTP parameter. If so, we redirect the request to the configured special-offer page; otherwise, we redirect it to the configured error page.
The PromoCodeInterceptor
class has three properties, promoCode
, errorRedirect
, and offerRedirect
. The promoCode
property is used to configure the valid promo code; in our case, we have assigned OFF3R
as the valid promo code in step 2, so whoever is accessing the special-offer page should provide OFF3R
as the promo code in their HTTP parameter in order to access the special-offer page.
The next two attributes, errorRedirect
and offerRedirect
, are used for redirection. errorRedirect
indicates the redirect URL mapping in the case of an invalid promo code and offerRedirect
indicates the redirect URL mapping for a successful promo code redirection.
I have not created a special-offer products page; for demonstration purposes I have reused the same regular products page as a special-offer products page, which is why we have assigned market
/products
as the value for offerRedirect
; thus, in the case of a valid promo code we are simply redirecting to the regular products page. But if we create a special-offer products page, we can assign that page URL as the value for offerRedirect
.
Okay, we have created the PromoCodeInterceptor
bean, but we have to configure this interceptor with our Spring MVC runtime, which is what we have done in step 3 by adding the PromoCodeInterceptor
bean to our InterceptorRegistry
within the addInterceptors
method:
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ProcessingTimeLogInterceptor()); LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); localeChangeInterceptor.setParamName("language"); registry.addInterceptor(localeChangeInterceptor); registry.addInterceptor(promoCodeInterceptor()) .addPathPatterns("/**/market/products/specialOffer"); }
If you notice, while adding promoCodeInterceptor
to our InterceptorRegistry
, we can specify URL patterns using the addPathPatterns
method. This way we can specify the URL patterns to which the registered interceptor should apply. So our promoCodeInterceptor
will get executed only for a request that ends with market/specialOffer
.
In step 4, we have added one more request mapping method called invalidPromoCode
to show an error page in the case of an invalid promo code. In step 5, we have added the corresponding error View file, called invalidPromoCode.jsp
.
So in step 6, we purposely entered the http://localhost:8080/webstore/market/products/specialOffer?promo=offer
URL into our running application to demonstrate PromoCodeInterceptor
in action; we saw the error page because the promo code we gave in the URL is offer
(?promo=offer
), which is wrong. In step 7, we gave the correct promo code in the http://localhost:8080/webstore/market/products/specialOffer?promo=OFF3R
URL, so we should be able to see the configured special-offer products page.