控制器层面针对请求体的自定义异常处理器实现疑问
同一请求体适配多端点的自定义校验与异常处理方案
需要复用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
相关产品推荐
相关产品推荐

