背景: 服务器端对客户端提交的请求参数的值应该保持"不信任"的态度。个人认为这点可内化设计原则了,哪怕客户端软件(网页、手机APP等)有严格的检查机制,主要原因在于:
- 客户端软件存在客户端软件被篡改的可能
- 某些项目可能有多种不同的客户端(既有网页端,又有手机端,甚至还有其它客户端),开发人员各异意识不到位,检查规则可能并不统一
所以,必须在服务器端进行检查!来保证各请求参数的有效性。
注意: 一为提高用户体验,二为缓解服务器压力!即使服务器端存在检查请求参数的机制,客户端仍有必要对即将提交的请求参数进行检查
一、 Spring Validation框架
Spring Validation框架是用于检查请求参数的基本格式 的框架。
例如,@NotNull检查某个请求参数是否为null、@Length检查某个字符串的长度、@NotEmpty检查某个字符串是否为空字符串、@Range检查数字值的区间等等。
在Spring Boot项目,在pom.xml添加spring-boot-starter-validation依赖项即可使用它:
            
            
              xml
              
              
            
          
          <!-- Spring Boot Validation依赖项,用于检查请求参数的基本格式 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>二、检查实体类的请求参数
当需要对POJO类型的请求参数进行检查时:
1.在处理请求的方法的被检查参数上添加@Valid注解,表示需要对此参数进行检查,例如:
            
            
              java
              
              
            
          
              //在线文档注解
    @ApiOperation("添加相册") //接口名注解
    @ApiOperationSupport(order = 2)//接口展示排序
    //直接网络请求添加
    //http://localhost:8080/album/add?name=TestAlbum001&description=TestDescription001&sort=88
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public JsonResult addNewAlbum(@Valid AlbumAddNewDTO albumAddNewDTO) {
        albumService.addNew(albumAddNewDTO);
        return JsonResult.ok();
    }2.在POJO类的属性上,添加你需要的检查注解(根据不同的检查规则,使用不同的检查注解)
例如,当某个请求参数是必须提交的,可以添加@NotNull注解,例如,在AlbumAddNewDTO类中:
            
            
              java
              
              
            
          
          @Data
public class AlbumAddNewDTO implements Serializable {
    @ApiModelProperty(value = "相册名称", required = true, example = "小米手机的相册")
    @NotNull(message = "添加相册失败,必须提交相册名称!")
    private String name;
    @ApiModelProperty(value = "描述", example = "简单相册")
    private String description;
    @ApiModelProperty(value = "排序权重", example = "100")
    private Integer sort;
}以上实现对name属性进行"不允许为null"的检查,如果客户端提交的请求参数中不包含name属性,服务器端将响应400错误。


3.如果相对该错误进行捕捉,和响应,如下:

效果

正常上线项目,会对异常进行特殊处理,此处仅打印异常日志
三、检查未封装的请求参数
如果某些请求的参数数量较少,或各参数并不相关,通常不会将参数封装到POJO类型中。
1.在当前类上添加@Validated注解,例如:
            
            
              java
              
              
            
          
          @RestController
@Validated // 新增
public class AlbumController {
    // 暂不关心类内部的代码
}2.在需要检查的参数上添加检查注解,
例如:检查是否相册id是否为空@NotNull 检查相册id是否在一定范围内@Range(min = 1, max = 20)
            
            
              java
              
              
            
          
              //在线文档注解
    @ApiOperation("根据相册id删除相册")//接口名注解
    @ApiImplicitParam(name = "id", value = "相册序号", required = true,
            example = "11", dataType = "Long")//参数名注解
    @ApiOperationSupport(order = 1)//接口展示排序
    //直接网络请求删除
    //http://localhost:8080/album/delete/byId?id=2
    @RequestMapping(value = "/delete/byId", method = RequestMethod.GET)
    public JsonResult deleteAlbumById( @NotNull @Range(min = 1, max = 20) Long id) {
        // "deleteAlbumById.id: 需要在1和20之间
        log.debug("开始处理【根据相册id删除】的请求,参数123:{}", id);
        try {
            albumService.deleteAlbumById(id);
            return JsonResult.ok();
        } catch (Exception e) {
            String message = e.getMessage();
            log.error("deleteAlbumById Exception {}", message);
            return JsonResult.fail(ServiceCode.ERR_CUSTOM, message);
        }实际效果:服务器端将响应500错误,

我这边笼统捕获一下就是



四、常用的检查注解
1.使用Validation框架检查数据的基本格式时,常用的检查注解有:
- @NotNull:不允许为- null值,即客户端必须提交此参数- 可用于任何类型的参数
 
- @NotEmpty:不允许为空字符串,即不允许是长度为0的字符串- 仅用于字符串类型的参数
 
- @NotBlank:不允许为空白的字符串,即不允许仅由空格、TAB制表位、换行等空白组成的字符串- 仅用于字符串类型的参数
 
- @Length:限制字符串的长度,也可以用于检查集合等数据的长度,但不常见- 通常仅用于字符串类型的参数
 
- @Pattern:通过正则表达式检查字符串的格式,此注解的- regexp属性是定义正则表达式的属性- 仅用于字符串类型的参数
 
- @Min:限制最小值- 仅用于整型数值类型的参数
 
- @Max:限制最大值- 仅用于整型数值类型的参数
 
- @Range:限制取值区间,默认最小值为- 0,最大值是- long类型的上限值- 仅用于整型数值类型的参数
 
**提示:**在源代码中,有2套检查注解的包,例如@NotNull和@Range这2个注解就在不同的包下。
2.关于检查注解的使用:
- @NotNull注解可以添加在任何类型的请求参数上,
- 所有检查注解都有message属性,用于配置检查失败时的提示文本
- 每个被检查的请求参数都可以同时添加多个检查注解 ,如同时使用@NotNull与另1个或多个检查注解。
创造价值,乐哉分享!