1.在前后端的传输参数的过程中数据在何处校验?
在前后端都需要进行校验,只是分工不同.
2.各个层的校验内容:
1.Controller层主要负责校验残水的合法性,包括: 必填的参数字段,数据格式的校验
2.Service层的业务校验是审核业务中的规则的相关内容,比如:课程已经审核通过所以提交失败这种错误,通常来书, 比较复杂,难以直接写成通用校验代码.
3.spring提供的支持:
spring提供了是spring-boot-starter-validation来实现校验工作.依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
3.1定义校验规则
代码中实现的方法(举例):
1.@NotEmpty,@NotEmpty表示属性不能为空。
2.@Size, 表示限制属性内容的长短
package com.xuecheng.content.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
/**
* @description 添加课程dto
* @author Mr.M
* @date 2022/9/7 17:40
* @version 1.0
*/
@Data
@ApiModel(value="AddCourseDto", description="新增课程基本信息")
public class AddCourseDto {
@NotEmpty(message = "课程名称不能为空")
@ApiModelProperty(value = "课程名称", required = true)
private String name;
@NotEmpty(message = "适用人群不能为空")
@Size(message = "适用人群内容过少",min = 10)
@ApiModelProperty(value = "适用人群", required = true)
private String users;
@ApiModelProperty(value = "课程标签")
private String tags;
@NotEmpty(message = "课程分类不能为空")
@ApiModelProperty(value = "大分类", required = true)
private String mt;
@NotEmpty(message = "课程分类不能为空")
@ApiModelProperty(value = "小分类", required = true)
private String st;
@NotEmpty(message = "课程等级不能为空")
@ApiModelProperty(value = "课程等级", required = true)
private String grade;
@ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true)
private String teachmode;
@ApiModelProperty(value = "课程介绍")
private String description;
@ApiModelProperty(value = "课程图片", required = true)
private String pic;
@NotEmpty(message = "收费规则不能为空")
@ApiModelProperty(value = "收费规则,对应数据字典", required = true)
private String charge;
@ApiModelProperty(value = "价格")
private Float price;
@ApiModelProperty(value = "原价")
private Float originalPrice;
@ApiModelProperty(value = "qq")
private String qq;
@ApiModelProperty(value = "微信")
private String wechat;
@ApiModelProperty(value = "电话")
private String phone;
@ApiModelProperty(value = "有效期")
private Integer validDays;
}
更多的校验规则如下所示:
3.2. 定义好之后需要在controller中添加开启的注解,
注解添加的位置是接受dto类的函数的入口参数出处,添加@Validated 举例如下:
@ApiOperation("新增课程基础信息")
@PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody @Validated AddCourseDto
addCourseDto){
//机构id,由于认证系统没有上线暂时硬编码
Long companyId = 1L;
return courseBaseInfoService.createCourseBase(companyId,addCourseDto);
}
3.3在全局异常处理器中添加处理方法
如果校验出错就会报错MethodArgumentNotValidException,所以需要在同一异常处理中添加如下的捕获信息,解析出异常信息
@ResponseBody
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse doValidException(MethodArgumentNotValidException e){
BindingResult result = e.getBindingResult();
StringBuffer errMsg = new StringBuffer();
List<FieldError> fieldErrors = result.getFieldErrors();
fieldErrors.forEach(item->
{
errMsg.append(item.getDefaultMessage()).append(",");
});
log.error(errMsg.toString());
return new RestErrorResponse(errMsg.toString());
}
4.分组异常处理规则
有时候在同一个属性上设置的校验规则不能满足属性的要求,比如订单号的生成,在插入订单的时候要求订单编号为空,而在更新订单的时候要求订单的编号不为空,此时就用到了分组校验,同一个属性定义多个校验规则属于不同的分组,比如添加订单的@Null规则属于insert分组,更新订单名字的@NotEmpty属于update分组,而controller在调用validate的时候就去指定分组从而实现想要的效果.
package com.xuecheng.base.exception;
/**
* @author YCL
* @version 1.0
* @description 定义校验粉组,因为对于同一属性,不同的情况要求的属性值不同
* @date 2023-02-01 16:31
*/
public class ValidationGroups {
public interface Insert{};
public interface Update{};
public interface Delete{};
}
dto类中添加校验规则时指定分组:
@NotEmpty(groups = {ValidationGroups.Insert.class},message = "添加课程名称不能为空")
@NotEmpty(groups = {ValidationGroups.Update.class},message = "修改课程名称不能为空")
@ApiModelProperty(value = "课程名称", required = true)
private String name;
controller中的指定校验分组:
@ApiOperation("新增课程")
@PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody @Validated({ValidationGroups.Insert.class}) AddCourseDto addCourseDto){
//获取当前用户所属培训机构的id
Long companyId = 22L;
//调用service
CourseBaseInfoDto courseBase = courseBaseInfoService.createCourseBase(companyId, addCourseDto);
return courseBase;
}