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
相关产品推荐
相关产品推荐

