You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot:返回非指定响应类型时抛出自定义异常

Spring Boot API强制返回指定响应类型的实现

需求说明

所有API接口必须返回ResponseEntity<MyResponseType>类型的响应,若接口返回其他类型,则抛出自定义异常InvalidResponseTypeException,向用户返回统一格式的错误信息。

核心代码定义

1. 统一响应实体类

public class MyResponseType {
    private String message;
    private int statusCode;

    // 带参构造方法
    public MyResponseType(String message, int statusCode) {
        this.message = message;
        this.statusCode = statusCode;
    }

    // Getter & Setter
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public int getStatusCode() { return statusCode; }
    public void setStatusCode(int statusCode) { this.statusCode = statusCode; }
}

2. 自定义异常类

public class InvalidResponseTypeException extends RuntimeException {
    public InvalidResponseTypeException(String message) {
        super(message);
    }
}

3. 控制器示例

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

    // 合法接口:返回指定类型响应
    @GetMapping("/example-success")
    public ResponseEntity<MyResponseType> getExampleSuccess() {
        MyResponseType response = new MyResponseType("这是一个合法响应", 200);
        return ResponseEntity.ok(response);
    }

    // 非法接口:返回String类型响应,调用时会触发异常
    @GetMapping("/example-failure")
    public ResponseEntity<String> getExampleFailure() {
        String response = "这是一个非法响应";
        return ResponseEntity.ok(response);
    }
}

实现自动校验的两种方案

方案一:使用ResponseBodyAdvice全局拦截

通过ResponseBodyAdvice可以在响应写出前校验返回类型,拦截所有@RestController的接口:

@ControllerAdvice
public class ResponseTypeValidator implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 仅处理标注了@RestController的类中的方法
        return returnType.getDeclaringClass().isAnnotationPresent(RestController.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        validateReturnType(returnType.getGenericParameterType());
        return body;
    }

    private void validateReturnType(Type returnType) {
        // 校验返回类型是否为ResponseEntity<MyResponseType>
        if (!(returnType instanceof ParameterizedType)) {
            throw new InvalidResponseTypeException("API返回类型必须为ResponseEntity<MyResponseType>");
        }
        ParameterizedType paramType = (ParameterizedType) returnType;
        if (!paramType.getRawType().equals(ResponseEntity.class)) {
            throw new InvalidResponseTypeException("API返回类型必须为ResponseEntity<MyResponseType>");
        }
        Type[] actualTypes = paramType.getActualTypeArguments();
        if (actualTypes.length != 1 || !actualTypes[0].equals(MyResponseType.class)) {
            throw new InvalidResponseTypeException("API返回类型必须为ResponseEntity<MyResponseType>");
        }
    }
}

方案二:使用AOP切面拦截

通过AOP切面拦截控制器方法的执行,在方法调用前校验返回类型:

@Aspect
@Component
public class ResponseTypeValidationAspect {

    // 拦截控制器包下的所有公共方法,替换为实际包路径
    @Around("execution(public * com.your.package.controller.*.*(..))")
    public Object validateResponseType(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        validateReturnType(signature.getMethod().getGenericReturnType());
        return joinPoint.proceed();
    }

    private void validateReturnType(Type returnType) {
        if (!(returnType instanceof ParameterizedType)) {
            throw new InvalidResponseTypeException("API返回类型必须为ResponseEntity<MyResponseType>");
        }
        ParameterizedType paramType = (ParameterizedType) returnType;
        if (!paramType.getRawType().equals(ResponseEntity.class)) {
            throw new InvalidResponseTypeException("API返回类型必须为ResponseEntity<MyResponseType>");
        }
        Type[] actualTypes = paramType.getActualTypeArguments();
        if (actualTypes.length != 1 || !actualTypes[0].equals(MyResponseType.class)) {
            throw new InvalidResponseTypeException("API返回类型必须为ResponseEntity<MyResponseType>");
        }
    }
}

全局异常处理

添加全局异常处理器,将自定义异常转换为统一格式的响应:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(InvalidResponseTypeException.class)
    public ResponseEntity<MyResponseType> handleInvalidResponseType(InvalidResponseTypeException ex) {
        MyResponseType errorResp = new MyResponseType(ex.getMessage(), 400);
        return ResponseEntity.badRequest().body(errorResp);
    }
}

内容的提问来源于stack exchange,提问作者Derda Karaaslan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:53:11