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

Spring Rest自定义类校验:JSON转换前的参数验证方案

Spring JSON参数预校验方案(处理未知字段/拼写错误)

针对你遇到的JSON字段拼写错误(如select写成seletc)未触发校验的问题,以下是两种实用的实现方案:

方案一:Jackson开启未知字段报错(最简方案)

默认Jackson会忽略JSON中的未知字段,只需修改配置让其遇到未知字段时抛出异常,再通过全局异常处理器返回友好响应。

1. 配置Jackson

通过配置文件或配置类开启未知字段报错:

  • application.properties配置:
spring.jackson.deserialization.fail-on-unknown-properties=true
  • Java配置类:
@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 遇到未知字段时抛出异常
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
        return objectMapper;
    }
}

2. 全局异常捕获

用@RestControllerAdvice捕获Jackson抛出的未知字段异常,返回自定义错误响应:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UnrecognizedPropertyException.class)
    public ResponseEntity<ErrorResponse> handleUnknownField(UnrecognizedPropertyException e) {
        String errorMsg = String.format("请求参数存在未知字段: %s,请检查字段拼写(正确字段为select/filters)", e.getPropertyName());
        return ResponseEntity.badRequest().body(new ErrorResponse(400, errorMsg));
    }

    // 捕获其他JSON反序列化错误
    @ExceptionHandler(JsonMappingException.class)
    public ResponseEntity<ErrorResponse> handleJsonError(JsonMappingException e) {
        return ResponseEntity.badRequest().body(new ErrorResponse(400, "请求JSON格式错误: " + e.getOriginalMessage()));
    }
}

// 自定义错误响应类
class ErrorResponse {
    private int code;
    private String message;

    public ErrorResponse(int code, String message) {
        this.code = code;
        this.message = message;
    }

    // getter/setter 省略
}

注意事项

给Search类添加无参构造器,否则Jackson反序列化会失败:

public Search() {}

方案二:JSON Schema校验(灵活复杂校验)

如果需要更细粒度的参数校验(如字段类型、数组元素格式、必填字段等),可以用JSON Schema在Jackson转换前先校验原始JSON结构。

1. 添加依赖

引入JSON Schema校验库:

<dependency>
    <groupId>org.everit.json</groupId>
    <artifactId>org.everit.json.schema</artifactId>
    <version>1.14.0</version>
</dependency>
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20230618</version>
</dependency>

2. 定义JSON Schema文件

在resources目录下创建search-schema.json,明确约束字段:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "select": {
      "type": "array",
      "items": {"type": "string"}
    },
    "filters": {
      "type": "array",
      "items": {
        "type": "object",
        // 根据Filter类结构定义字段约束
        "properties": {
          "name": {"type": "string"},
          "value": {"type": "string"}
        },
        "required": ["name", "value"]
      }
    }
  },
  "additionalProperties": false, // 禁止未知字段
  "required": [] // 若select/filters为必填则添加对应字段
}

3. Controller中手动校验

先校验原始JSON字符串,通过后再转换为Search类:

@PostMapping("/results")
public ResponseEntity<?> results(@NotNull String id, @RequestBody String searchJson) {
    // 1. 加载并校验JSON Schema
    try (InputStream is = getClass().getResourceAsStream("/search-schema.json")) {
        JSONObject rawSchema = new JSONObject(new String(is.readAllBytes()));
        Schema schema = SchemaLoader.load(rawSchema);
        schema.validate(new JSONObject(searchJson));
    } catch (ValidationException e) {
        return ResponseEntity.badRequest().body(new ErrorResponse(400, "请求参数错误: " + e.getMessage()));
    } catch (IOException e) {
        return ResponseEntity.internalServerError().build();
    }

    // 2. 校验通过后转换为Search类
    Search search;
    try {
        search = new ObjectMapper().readValue(searchJson, Search.class);
    } catch (JsonProcessingException e) {
        return ResponseEntity.badRequest().body(new ErrorResponse(400, "JSON格式解析失败"));
    }

    // 3. 执行业务逻辑
    return ResponseEntity.ok("处理成功");
}

方案对比

  • 方案一:配置简单,无额外依赖,适合仅需拦截未知字段的场景,配合原有的@Valid可实现字段内部校验。
  • 方案二:支持复杂结构校验,扩展性强,但需额外依赖,代码量稍大。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:42:52