背景: 服务器端对客户端提交的请求参数的值应该保持"不信任"的态度。个人认为这点可内化设计原则了,哪怕客户端软件(网页、手机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个或多个检查注解。
创造价值,乐哉分享!