# Filters & Interceptors in Spring

In 
Published 2023-03-04

This tutorial explains what the filters & interceptors are and how they are used in Spring.

Please take a look at the following examples and read carefully the comments. The code is self-explanatory.

Starting from the base application downloaded from Spring Initializr, I updated the main class and added the more classes as below:

Employee.java
package com.example.demo;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Employee {
  private String id;
  private String name;
  private String department;
  private int age;

  public Employee(String id, String name, String department, int age) {
    this.id = id;
    this.name = name;
    this.department = department;
    this.age = age;
  }
}
EmployeeController.java
package com.example.demo;

import com.example.demo.filters.SecurityFilter;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;

@RestController
// Define a REST controller for testing our cases
public class EmployeeController {

  Logger Logger = LoggerFactory.getLogger(SecurityFilter.class);

  @Autowired
  EmployeeService employeeService;

  @GetMapping("/employee/all")
  String getAllEmployees() {
    ArrayList<Employee> allEmployees = employeeService.getEmployees();
    String json = new Gson().toJson(allEmployees);
    return json;
  }

  @PutMapping(value="/employee/add", consumes = "application/json")
  int addEmployee(@RequestBody Employee newEmployee) {

    Logger.info("Employee Controller - IN");
    employeeService.addEmployee(newEmployee);
    int newCount = employeeService.countEmployees();
    Logger.info("Employee Controller - OUT");
    return newCount;
  }

  @DeleteMapping(value="/employee/delete", consumes = "application/json")
  int deleteEmployee(@RequestBody String empId) {

    employeeService.removeEmployee(empId);
    int newCount = employeeService.countEmployees();
    return newCount;
  }
}
EmployeeService.java
package com.example.demo;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;

@Service
public class EmployeeService {

    private HashMap<String, Employee> employees = new HashMap<>();

    public void addEmployee(Employee Emp) {
        this.employees.put(Emp.getId(), Emp);
    }

    public void removeEmployee(String empId) {
        this.employees.remove(empId);
    }

    public int countEmployees() {
        return this.employees.size();
    }

    public ArrayList<Employee> getEmployees() {

        ArrayList<Employee> empList = new ArrayList<>();
        // go through the values of the map
        for (Employee emp : employees.values()) {
            empList.add(emp);
        }

        return empList;
    }
}
LoggingFilter.java
package com.example.demo.filters;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

@WebFilter()
// Define a filter for logging
public class LoggingFilter implements Filter {

    Logger Logger = LoggerFactory.getLogger(LoggingFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest r1 = (HttpServletRequest) request;
        Logger.info("LoggingFilter// before doFilter() for URL req. = " + r1.getRequestURI());
        chain.doFilter(request, response);
        Logger.info("LoggingFilter// AFTER doFilter() for URL req. = " + r1.getRequestURI());
    }
}
SecurityFilter.java
package com.example.demo.filters;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

@WebFilter()
// Define another filter for testing the chaining of the filters
public class SecurityFilter implements Filter {

    Logger Logger = LoggerFactory.getLogger(SecurityFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest r1 = (HttpServletRequest) request;
        Logger.info("SecurityFilter// before doFilter() for URL req. = " + r1.getRequestURI());
        chain.doFilter(request, response);
        Logger.info("SecurityFilter// AFTER doFilter() for URL req. = " + r1.getRequestURI());
    }
}
LoggingInterceptor.java
package com.example.demo.interceptors;

import com.example.demo.filters.SecurityFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.util.UUID;

// Implements preHandle(), postHandle() and afterCompletion() methods of HandlerInterceptor interface
public class LoggingInterceptor implements HandlerInterceptor {

    Logger log = LoggerFactory.getLogger(SecurityFilter.class);

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        UUID uuid = UUID.randomUUID();
        request.setAttribute("request-id", uuid );
        log.info(">>>>  preHandle() for "+request.getRequestURI());

        // when "true" we allow user to access rest controller api
        return true;
    }

    @Override
    public void postHandle( HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler,
                            ModelAndView modelAndView) throws Exception {

        log.info(">>>>  postHandle() for "+request.getRequestURI()+" ATTR(request-id)= "+request.getAttribute("request-id"));
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception exception) throws Exception {

        log.info(">>>>  afterCompletion() for " + request.getRequestURI() + " ATTR(request-id)= " + request.getAttribute("request-id"));
    }
}
RegisterInterceptors.java
package com.example.demo.components;

import com.example.demo.interceptors.LoggingInterceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Component
public class RegisterInterceptors implements WebMvcConfigurer {

    @Override
    // Register the LoggingInterceptor
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor( new LoggingInterceptor() );
    }
}
DemoApplication.java
package com.example.demo;

import com.example.demo.filters.LoggingFilter;
import com.example.demo.filters.SecurityFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.concurrent.ExecutionException;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		ApplicationContext appContext = SpringApplication.run(DemoApplication.class, args);

	}

	@Bean
	// Setting the proprieties of SecurityFilter
	public FilterRegistrationBean<SecurityFilter> filterSecurityBean() {
		FilterRegistrationBean<SecurityFilter> filterPropertiesBean = new FilterRegistrationBean();

		filterPropertiesBean.setFilter(new SecurityFilter());
		filterPropertiesBean.addUrlPatterns("/employee/*");
		filterPropertiesBean.setOrder(2);
		return filterPropertiesBean;
	}

	@Bean
	// Setting the proprieties of LoggingFilter
	public FilterRegistrationBean<LoggingFilter> filterLoggingBean() {
		FilterRegistrationBean<LoggingFilter> filterPropertiesBean = new FilterRegistrationBean();

		filterPropertiesBean.setFilter(new LoggingFilter());
		filterPropertiesBean.addUrlPatterns("/employee/all");
		filterPropertiesBean.setOrder(1);
		return filterPropertiesBean;
	}
}

When we send the "/employee/add" request we will see something like that in the logs :

c.example.demo.filters.SecurityFilter    : SecurityFilter// before doFilter() for URL req. = /employee/add
c.example.demo.filters.SecurityFilter    : >>>>  preHandle() for /employee/add
c.example.demo.filters.SecurityFilter    : Employee Controller - IN
c.example.demo.filters.SecurityFilter    : Employee Controller - OUT
c.example.demo.filters.SecurityFilter    : >>>>  postHandle() for /employee/add ATTR(request-id)= d296eafe-71ec-4a0a-8a5a-84b5c593a91b
c.example.demo.filters.SecurityFilter    : >>>>  afterCompletion() for /employee/add ATTR(request-id)= d296eafe-71ec-4a0a-8a5a-84b5c593a91b
c.example.demo.filters.SecurityFilter    : SecurityFilter// AFTER doFilter() for URL req. = /employee/add

When we send the "/employee/all" request we will see something like that in the logs :

com.example.demo.filters.LoggingFilter   : LoggingFilter// before doFilter() for URL req. = /employee/all
c.example.demo.filters.SecurityFilter    : SecurityFilter// before doFilter() for URL req. = /employee/all
c.example.demo.filters.SecurityFilter    : >>>>  preHandle() for /employee/all
c.example.demo.filters.SecurityFilter    : >>>>  postHandle() for /employee/all ATTR(request-id)= d113f7cd-3ef1-46eb-98ee-b01a4b53a0f8
c.example.demo.filters.SecurityFilter    : >>>>  afterCompletion() for /employee/all ATTR(request-id)= d113f7cd-3ef1-46eb-98ee-b01a4b53a0f8
c.example.demo.filters.SecurityFilter    : SecurityFilter// AFTER doFilter() for URL req. = /employee/all
com.example.demo.filters.LoggingFilter   : LoggingFilter// AFTER doFilter() for URL req. = /employee/all

To understand better the difference from Filters & Interceptors in Spring take a look at the following picture: