Refactor Spring Controllers for Unified Responses and Robust Validation
This article explains how to redesign Spring MVC controllers by introducing a unified Result wrapper, using ResponseBodyAdvice for automatic response packaging, applying JSR‑303 validation on DTOs and method parameters, and handling custom exceptions globally to produce consistent API outputs.
From the Current Situation
Controller is an indispensable companion in both three‑layer and COLA architectures, responsible for receiving requests, invoking services, handling exceptions and returning responses.
Problems with Traditional Controller Code
Parameter validation couples business logic, violating Single Responsibility Principle.
Repeated exception throwing across services leads to duplicated code.
Inconsistent success and error response formats make client integration unfriendly.
Refactoring the Controller Layer
Unified Return Structure
A generic IResult interface and Result wrapper provide a status code, message and data payload, making success detection explicit.
public interface IResult {
Integer getCode();
String getMessage();
}
public enum ResultEnum implements IResult {
SUCCESS(2001, "接口调用成功"),
VALIDATE_FAILED(2002, "参数校验失败"),
COMMON_FAILED(2003, "接口调用失败"),
FORBIDDEN(2004, "没有权限访问资源");
// fields and constructor omitted
}
public class Result<T> {
private Integer code;
private String message;
private T data;
// static factory methods omitted
}Unified Response Advice
Implement ResponseBodyAdvice to wrap every controller return value into Result. For String returns, convert the wrapper to JSON manually.
@RestControllerAdvice(basePackages = "com.example.demo")
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result) {
return body;
}
if (body instanceof String) {
try {
return objectMapper.writeValueAsString(Result.success(body));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
return Result.success(body);
}
}Adjust the order of MappingJackson2HttpMessageConverter in the MVC configuration to avoid String conversion errors.
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2HttpMessageConverter());
}
}Parameter Validation
Use JSR‑303 annotations ( @Valid, @Validated, @Min, @Email, etc.) on DTOs, @PathVariable and @RequestParam parameters. Spring’s MethodValidationPostProcessor and MethodValidationInterceptor perform AOP‑based validation and throw MethodArgumentNotValidException or ConstraintViolationException on failure.
Custom Exceptions and Global Exception Handling
Define domain‑specific exceptions such as BusinessException and ForbiddenException, then handle them in a @RestControllerAdvice that returns a Result with appropriate error codes.
@RestControllerAdvice(basePackages = "com.example.demo")
public class ExceptionAdvice {
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException ex) {
return Result.failed(ex.getMessage());
}
@ExceptionHandler(ForbiddenException.class)
public Result<?> handleForbiddenException(ForbiddenException ex) {
return Result.failed(ResultEnum.FORBIDDEN);
}
// other handlers omitted for brevity
}After these changes, controller code becomes concise, validation rules are explicit, and all responses share a uniform structure, allowing developers to focus on business logic.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
