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.
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.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.