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

控制器层面针对请求体的自定义异常处理器实现疑问

同一请求体适配多端点的自定义校验与异常处理方案

需要复用RequestData请求体给不同接口端点,针对同一字段(比如distance),根据不同端点返回不同的错误提示。因为JSR-380的@Valid注解无法绑定特定端点,所以采用全局异常处理器来实现,但当前代码缺少触发自定义校验的逻辑,且异常处理器的写法存在问题,以下是修正后的完整方案:

一、重构自定义异常类

给异常类添加字段标识,方便后续处理器定位错误字段:

public class CustomIllegalArgumentException extends RuntimeException {
    private String fieldName;

    public CustomIllegalArgumentException(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getFieldName() {
        return fieldName;
    }
}

二、创建校验服务类

把校验逻辑抽离出来,根据端点实现差异化校验规则:

import org.springframework.stereotype.Component;

@Component
public class RequestDataValidator {

    public void validate(RequestData requestData, String endpoint) {
        // 针对distance字段,按不同端点做校验
        if ("doSomething".equals(endpoint)) {
            if (requestData.getDistance() > 2) {
                throw new CustomIllegalArgumentException("distance");
            }
        } else if ("getSomething".equals(endpoint)) {
            if (requestData.getDistance() > 2) {
                throw new CustomIllegalArgumentException("distance");
            }
        }
        // 其他字段或端点的校验可在此扩展
    }
}

三、修正Controller类

去掉方法上的@ExceptionHandler(改用全局处理器),在业务逻辑前调用校验服务触发检查:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;

@RestController
public class TestController {

    private final RequestDataValidator validator;

    // 构造注入校验服务
    public TestController(RequestDataValidator validator) {
        this.validator = validator;
    }

    @PostMapping("/getSomething")
    public ResponseEntity getSomething(@RequestBody RequestData requestData) {
        validator.validate(requestData, "getSomething");
        // 校验通过后执行业务逻辑
        return new ResponseEntity<>("response", HttpStatus.OK);
    }

    @PostMapping("/doSomething")
    public ResponseEntity doSomething(@RequestBody RequestData requestData) {
        validator.validate(requestData, "doSomething");
        // 校验通过后执行业务逻辑
        return new ResponseEntity<>("response", HttpStatus.OK);
    }
}

四、修正全局异常处理器

通过HttpServletRequest获取当前请求的端点,结合异常信息生成差异化错误响应:

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class RestExceptionHandler {

    @ExceptionHandler(CustomIllegalArgumentException.class)
    @ResponseBody
    public ResponseEntity<ErrorResponse> handleIllegalRequestBodyException(
            CustomIllegalArgumentException exp,
            HttpServletRequest request) {
        // 从请求路径提取端点标识
        String requestUri = request.getRequestURI();
        String endpoint = requestUri.substring(requestUri.lastIndexOf("/") + 1);

        ErrorResponse response = new ErrorResponse(HttpStatus.BAD_REQUEST);
        // 根据端点和错误字段设置对应提示
        if ("distance".equals(exp.getFieldName())) {
            if ("doSomething".equals(endpoint)) {
                response.setMessage("doSomething端点:distance不能大于2");
            } else if ("getSomething".equals(endpoint)) {
                response.setMessage("getSomething端点:distance超过最大限制");
            }
        }
        return buildResponseEntity(response);
    }

    private ResponseEntity<ErrorResponse> buildResponseEntity(ErrorResponse errorResponse) {
        return new ResponseEntity<>(errorResponse, errorResponse.getStatus());
    }
}

五、保留原有基础类

原有的请求体和错误响应类可直接复用:

// RequestData类
public class RequestData {
    private String type; 
    private int distance;
    // getters、setters 省略
}
// ErrorResponse类
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.http.HttpStatus;
import java.time.LocalDateTime;

@Getter
@Setter
public class ErrorResponse {
    private HttpStatus status;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd hh:mm:ss")
    private LocalDateTime timeStamp;
    private String message;

    public ErrorResponse(HttpStatus status) {
        this();
        this.status = status;
    }

    public ErrorResponse(HttpStatus status, String message) {
        this();
        this.status = status;
        this.message = message;
    }

    public ErrorResponse(){
        timeStamp = LocalDateTime.now();
    }

    public ErrorResponse(HttpStatus status, LocalDateTime timeStamp, String message) {
        this();
        this.status = status;
        this.timeStamp = timeStamp;
        this.message = message;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:35:23