Mastering Java Web Development: An In-Depth Journey into Filter, Dispatcher Servlet, Interceptor, and Controller

Naveen Metta
5 min readFeb 12, 2024

--

credit goes to the owner : https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter
source : baeldung.com

Introduction:

Java web development, a dynamic and expansive field, demands a deep understanding of various components for creating robust, scalable, and maintainable applications. This article is a comprehensive guide, delving even further into Filter, Dispatcher Servlet, Interceptor, and Controller in the context of web applications. With an extended exploration, we aim to equip developers with not just an understanding but a mastery of these crucial elements. Accompanied by extensive code examples, this knowledge empowers developers to navigate the intricate landscape of Java web development with confidence and expertise.

Filter:

Filters, positioned as the initial defense in Java web applications, are instrumental in intercepting and processing requests and responses before they reach the servlet or any other component. Their versatility enables developers to implement a myriad of tasks, including authentication, logging, input validation, and more. Operating at a low level in the request-processing chain, filters offer an ideal space for pre-processing tasks.

To illustrate the flexibility of filters, let’s explore a scenario where a custom filter is employed to enhance security by blocking requests from blacklisted IP addresses:

public class IpBlacklistFilter implements Filter {
private Set<String> blacklist = new HashSet<>();

@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Load blacklist from a configuration file or database
blacklist.add("192.168.1.1");
blacklist.add("10.0.0.2");
// Add more blacklisted IP addresses as needed
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String ipAddress = httpRequest.getRemoteAddr();

if (!blacklist.contains(ipAddress)) {
// Proceed with the request if the IP address is not blacklisted
chain.doFilter(request, response);
} else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Forbidden");
}
}

@Override
public void destroy() {
// Cleanup resources, if any
}
}

In this example, the IpBlacklistFilter checks the incoming request’s IP address against a predefined blacklist. If the IP address is blacklisted, the filter returns a forbidden response; otherwise, it allows the request to proceed. This demonstrates how filters can be tailored for diverse security measures.

Dispatcher Servlet:

The Dispatcher Servlet, a central component in the Spring MVC framework, manages the flow of requests within an application, dispatching them to the appropriate controllers. Its structured approach to request handling significantly contributes to the organization and maintainability of the codebase.

Taking the Dispatcher Servlet’s capabilities a step further, let’s explore a scenario where it’s utilized with Spring WebFlux to handle server-sent events (SSE) for real-time updates:

@Configuration
@EnableWebFlux
public class WebFluxSseConfig implements WebFluxConfigurer {

@Bean
public HandlerMapping handlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/sse-updates", new SseUpdatesHandler());

SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
mapping.setUrlMap(map);
return mapping;
}
}

In this example, the WebFluxSseConfig class configures Spring WebFlux to handle server-sent events. It defines a WebSocket handler and maps it to the “/sse-updates” URL, showcasing how the Dispatcher Servlet can be adapted for real-time communication.

Interceptor:

Interceptors in Spring MVC offer a flexible mechanism for pre-handling and post-handling requests and responses, injecting additional functionality into the request processing life cycle. Tightly integrated with the Dispatcher Servlet, interceptors enable developers to implement features such as logging, modifying request attributes, and more.

Extending the functionality of interceptors, let’s explore an example where an interceptor is employed for handling caching by checking if a response can be retrieved from the cache:

public class CachingInterceptor extends HandlerInterceptorAdapter {
private Cache<String, String> responseCache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String cachedResponse = responseCache.getIfPresent(request.getRequestURI());
if (cachedResponse != null) {
try {
// Respond with the cached content
response.getWriter().write(cachedResponse);
response.flushBuffer();
return false; // Stop further processing
} catch (IOException e) {
e.printStackTrace();
}
}
return true; // Continue with the request processing
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) {
// Cache the response content for subsequent requests
try {
String responseBody = response.getContentAsString();
responseCache.put(request.getRequestURI(), responseBody);
} catch (IOException e) {
e.printStackTrace();
}
}
}

In this example, the CachingInterceptor intercepts requests, checks if the response is cached, and if so, serves the cached content. It also caches the response content for subsequent requests, illustrating how interceptors can be employed for efficient caching strategies.

Controller:

Controllers, serving as the core of a Spring MVC application, encapsulate business logic, facilitating the interaction between users and the application. They process user requests, execute necessary logic, and return the appropriate view or data, adhering to the principles of the MVC architecture.

Let’s delve into an advanced scenario involving the integration of Spring Security with a controller for handling user authentication and authorization:

@RestController
@RequestMapping("/api")
public class AuthenticatedController {

@GetMapping("/public")
public ResponseEntity<String> publicEndpoint() {
return ResponseEntity.ok("Public endpoint accessible to all");
}

@GetMapping("/user")
public ResponseEntity<String> userEndpoint() {
return ResponseEntity.ok("User endpoint accessible to authenticated users");
}

@GetMapping("/admin")
@Secured("ROLE_ADMIN")
public ResponseEntity<String> adminEndpoint() {
return ResponseEntity.ok("Admin endpoint accessible only to users with the ROLE_ADMIN role");
}
}

In this example, the AuthenticatedController defines three endpoints with different access levels. The “/public” endpoint is accessible to all, the “/user” endpoint is accessible to authenticated users, and the “/admin” endpoint requires users to have the “ROLE_ADMIN” role. This showcases how controllers can integrate seamlessly with Spring Security for robust authentication and authorization mechanisms.

Conclusion:

In the intricate landscape of Java web development, a profound understanding of Filters, Dispatcher Servlets, Interceptors, and Controllers is indispensable for crafting resilient, scalable, and maintainable applications. This in-depth exploration has delved even further into the essence of each component, providing clarity through extensive code examples. By mastering these foundational elements, developers can architect web applications that deliver seamless user experiences while adhering to best practices in design and development.

Whether it’s implementing dynamic security checks with filters, handling real-time communication with the Dispatcher Servlet, optimizing performance with interceptors, or integrating robust authentication and authorization mechanisms in controllers, the knowledge gained here serves as a robust foundation for Java web developers striving to excel in their craft. As the realm of web development continues to evolve, the ability to leverage these components effectively becomes increasingly crucial, enabling developers to navigate the complexities of modern web applications with confidence and expertise.

--

--

Naveen Metta

I'm a Full Stack Developer with 2.5 years of experience. feel free to reach out for any help : mettanaveen701@gmail.com