在后台对前端提交的参数验证是必须的。Spring Boot 内置了相关参数校验。
1、添加依赖
使用的是Spring Boot 2.7版本,经过测试需要安装 spring-boot-starter-validation 依赖。如果 pom 没有从 parent 继承,需要添加版本号。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
2、 @RequestParam注解参数校验
前后端参数提交的方式很多,一般使用 @RequestParam ,@RequestBody注解自动获取参数,有关这两者的区别参考:SpringBoot中使用注解@RequestParam与 @RequestBody区别
对@RequestParam的参数校验如下:
controller上添加 @Validated 注解,参数前添加对应注解。
@Validated @RestController @RequestMapping("/load") public class PayloadController { @PostMapping("manage") public ResponseWrapper postEarthStation( @RequestParam("id") @Min(0) @Max(127) int id, ...... ) { ......return reply.equals("success") ? ResponseWrapper.success : ResponseWrapper.fail; } }
3、@RequestBody注解参数校验
@RequestBody 一般对 content-type: application/json 类型的参数进行校验,需要定义一个实体类,字段和前端参数需要一一对应。
定义实体类,并对实体类字段进行校验。
public class TmParamEntity { @NotNull(message = "satId字段不能为空") private int satId; ...... }
需要添加两个注解: controller加上@Validated注解,参数前添加@Valid注解。
@Validated @RestController @RequestMapping("tele") public class TelemetryController { @PostMapping("postData") public ResponseWrapper postTmData(@RequestBody @Valid List<TmParamEntity> tmParamEntity, HttpServletRequest httpServletRequest) { ...... return ResponseWrapper.success; } }
需要注意的是,如果前端传递参数是一个对象,那么参数类型就是实体类型,如果前端传递的是一个数组Array,这里需要使用 List<TmParamEntity> 类型。添加 @Valid注解,即可使参数校验生效。参数的反序列化工作,Spring 内置了Jackson 自动处理。如果字段没对上,会报错。
4、直接读取InputStream
有时我们需要无需借助 Jackson反序列化,直接从 httpServletRequest 拿到参数,有两种方法:
InputStreamReader inputStreamReader = new InputStreamReader(httpServletRequest.getInputStream()); char[] chars = new char[1024]; StringBuilder stringBuilder = new StringBuilder(); while ((inputStreamReader.read(chars)) != -1) { stringBuilder.append(new String(chars).trim()); }
StringBuilder stringBuilder = new StringBuilder(); try (BufferedReader bufferedReader = httpServletRequest.getReader()) { String lineString = bufferedReader.readLine(); while (lineString != null) { stringBuilder.append(lineString); lineString = bufferedReader.readLine(); } }
前者从 InputStreamReader 中读,后者直接从 BufferedReader 中读数据。需要注意的是,无论是哪种读取方式,stream数据只能读一次。例如使用了Jackson,再用 bufferedReader 去读,返回的是个null。注意到使用了try(resource) 对网络资源进行释放。