Backend Development 21 min read

Unified User Login Permission Validation, Exception Handling, and Response Formatting in Spring Boot

This article demonstrates how to consolidate user login permission checks, exception handling, and unified JSON response structures in a Spring Boot application by using AOP, custom HandlerInterceptor, @ControllerAdvice, and ResponseBodyAdvice, providing complete code examples and implementation details.

Top Architect
Top Architect
Top Architect
Unified User Login Permission Validation, Exception Handling, and Response Formatting in Spring Boot

In modern Spring Boot projects, scattered login checks, inconsistent response formats, and duplicated exception handling increase maintenance costs. This guide presents a systematic solution that unifies three core concerns: user login permission validation, exception handling, and data response formatting.

1. Unified User Login Permission Validation

Initially, each controller method performed its own session check, leading to repetitive code and higher coupling. The original implementation looks like this:

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/m1")
    public Object method(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute("userinfo") != null) {
            return true; // logged in
        } else {
            return false; // not logged in
        }
    }
    // other methods ...
}

To eliminate this redundancy, two approaches are explored: Spring AOP and Spring MVC interceptors.

1.1 Spring AOP Attempt

@Aspect
@Component
public class UserAspect {
    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void pointcut() {}

    @Before("pointcut()")
    public void doBefore() {}

    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // custom logic
        return joinPoint.proceed();
    }
}

The AOP solution faces two problems: inability to obtain HttpSession and difficulty excluding specific endpoints (e.g., login and register).

1.2 Spring HandlerInterceptor Solution

Spring provides HandlerInterceptor which can intercept requests before controller execution.

package com.example.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Login interceptor
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute("userinfo") != null) {
            return true; // allow
        }
        log.error("Current user has no access permission");
        response.setStatus(401);
        return false; // block
    }
}

Register the interceptor in a configuration class:

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login", "/user/reg");
    }
}

The interceptor runs before the controller, invoking preHandle for each request, and can be fine‑tuned with include/exclude patterns.

1.3 Interceptor Execution Principle

All controller invocations go through DispatcherServlet . During applyPreHandle , Spring iterates over the registered HandlerInterceptor instances and calls their preHandle methods. If any interceptor returns false , the request processing stops.

2. Unified Exception Handling

Spring’s @ControllerAdvice combined with @ExceptionHandler allows centralised exception processing.

package com.example.demo.config;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;

@ControllerAdvice
public class ErrorAdvice {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public HashMap
handleException(Exception e) {
        HashMap
result = new HashMap<>();
        result.put("code", "-1");
        result.put("msg", e.getMessage());
        return result;
    }

    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public HashMap
handleArithmetic(ArithmeticException e) {
        HashMap
result = new HashMap<>();
        result.put("code", "-2");
        result.put("msg", e.getMessage());
        return result;
    }
}

Multiple handlers are matched from specific to generic, ensuring the most appropriate response is returned.

3. Unified JSON Response Format

To guarantee a consistent response structure, @ControllerAdvice can also implement ResponseBodyAdvice :

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice
{
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true; // apply to all responses
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                 Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof HashMap) {
            return body; // already wrapped
        }
        if (body instanceof String) {
            // special handling for raw strings
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(AjaxResult.success(body));
        }
        return AjaxResult.success(body);
    }
}

public class AjaxResult {
    public static HashMap
success(Object data) {
        HashMap
r = new HashMap<>();
        r.put("code", 200);
        r.put("msg", "");
        r.put("data", data);
        return r;
    }
    public static HashMap
fail(int code, String msg) {
        HashMap
r = new HashMap<>();
        r.put("code", code);
        r.put("msg", msg);
        r.put("data", "");
        return r;
    }
}

With this advice, every controller method automatically returns a JSON object containing code , msg , and data , reducing boilerplate and improving front‑end consistency.

4. Summary

By combining a custom HandlerInterceptor for login checks, a global @ControllerAdvice for exception handling, and a ResponseBodyAdvice for unified response formatting, the Spring Boot application achieves clean separation of concerns, easier maintenance, and a consistent API contract for clients.

JavaAOPException HandlingSpring BootInterceptorUnified Response
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.