@Validated参数校验
- 导入依赖,如果SpringBoot版本的小于2.3.x,不需要导入,否则需要手动, 项目
nal-common
<!--如果spring-boot版本大于2.3.x,则需要手动引入依赖-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>
@Validated注解和@Valid注解区别
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
- @Validated是spring旗下的注解,@Valid注解时javax包下的注解,是jdk给提供的。
- @Validated:是spring提供的对@Valid的封装,常见用在方法上进行校验,@Validated要比@Valid更加强大,@Validated在@Valid之上提供了分组功能和验证排序功能
@Valid:没有分组的功能。可以用在方法、构造函数、方法参数和成员属性(字段)上。可以提供嵌套校验的功能
@Validated:提供了一个分组功能
,可以在入参验证时,根据不同的分组采用不同的验证机制。可以用在类型、方法和方法参数上。但是不能用在成员属性(字段
)上。没有嵌套校验的功能
定义全局的异常处理
CustomExceptionHandler中增加异常处理器,项目nal-common
/**
* 忽略参数异常处理器
*
* @param e 忽略参数异常
*/
//@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseBody
public JsonData parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
log.error("参数异常", e);
return JsonData.buildError("请求参数[" + e.getParameterName() + "]不能为空");
}
/**
* 缺少请求体异常处理器
*
* @param e 缺少请求体异常
*/
//@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseBody
public JsonData parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
log.error("缺少请求体异常", e);
return JsonData.buildError("参数体不能为空");
}
/**
* 参数效验异常处理器
*
* @param e 参数验证异常
*/
//@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public JsonData parameterExceptionHandler(MethodArgumentNotValidException e) {
log.error("参数效验异常", e);
BindingResult bindingResult = e.getBindingResult();
StringBuilder sb = new StringBuilder("校验失败: ");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
// sb.append(fieldError.getDefaultMessage()).append(", ");
sb.append("[").append(fieldError.getField()).append("]").append(fieldError.getDefaultMessage()).append(", ");
}
return JsonData.buildError(sb.toString());
}
/**
* 自定义校验
*
* @param e 参数验证异常
*/
@ExceptionHandler({ConstraintViolationException.class})
@ResponseBody
public JsonData handleConstraintViolationException(ConstraintViolationException e) {
log.error("自定义校验异常", e);
return JsonData.buildError(e.getMessage());
}
自定义方法校验
自定义校验注解: cn.nla.common.annotation.EncryptId
/**
* 自定义加密校验
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EncryptIdValidator.class})
public @interface EncryptId {
// 默认错误消息
String message() default "加密id格式错误";
// 分组
Class<?>[] groups() default {};
// 负载
Class<? extends Payload>[] payload() default {};
}
自定义校验逻辑:cn.nla.common.config.EncryptIdValidator
import cn.nla.common.annotation.EncryptId;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 自定义加密校验的方法
*/
public class EncryptIdValidator implements ConstraintValidator<EncryptId, String> {
// 字符串的长度: 32~256,以字母a到f或数字0到9开头。
private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 不为null才进行校验
if (value != null) {
Matcher matcher = PATTERN.matcher(value);
return matcher.find();
}
return true;
}
}
创建分组的接口
package cn.nla.user.goup;
/**
* 保存
*/
public interface Save {
}
/**
* 更新
*/
public interface Update {
}
请求参数校验配置
import cn.nla.common.annotation.EncryptId;
import cn.nla.user.goup.Save;
import cn.nla.user.goup.Update;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.List;
@Data
public class StudentBean implements Serializable {
@NotBlank(message = "用户名不能为空")
private String name;
@NotNull(groups = {Save.class, Update.class})
@Length(min = 6, max = 20, groups = {Save.class, Update.class})
private String account;
@Min(value = 18, message = "年龄不能小于18岁")
@NotNull(message = "年龄不能为空")
private Integer age;
@Pattern(regexp = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误")
private String phoneNum;
@Email(message = "邮箱格式错误")
private String email;
@Valid //嵌套只能使用Valid
@NotNull(message = "任课老师不能为空")
@Size(min = 1, message = "至少有一个老师")
private List<TeacherBean> teacherBeans;
@EncryptId(message = "密码格式错误")
private String password;
}
子对象TeacherBean
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
@Data
public class TeacherBean {
@NotEmpty(message = "老师姓名不能为空")
private String teacherName;
@Min(value = 1, message = "学科类型从1开始计算")
private int type;
}
控制器使用
Post请求
@PostMapping("query")
public String query(@Validated @RequestBody StudentBean params) {
log.info("请求参数:{}", params);
return "成功";
}
Get请求时,也是封装为对象进行校验
jackson注解:
请求参数与SpringBoot接收参数映射
使用注解@JsonProperty
@JsonProperty("product_id") //外部请求参数 &接收参数
private long productId; // springboot内部接收参数
时间格式化JsonFormat
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@RestController处理GET&POST请求
GET - @RequestParam
@GetMapping("query")
public Object query(@RequestParam(value = "params",required = false,defaultValue = "参数") {}
// get请求方式: /query?parmas=请求参数, 该请求参数是非必传参数,默认参数是:参数
GET - @PathVariable
没有required或defaultValue属性可以通过方法的逻辑来处理缺失的路径变量
@GetMapping("query/{parmas}")
public Object query(@PathVariable("parmas") String params) {}
// get请求方式: /query/请求参数
GET - @ModelAttribute
ModelAttribute主要用于将请求参数(包括查询字符串参数、表单数据、路径变量等)绑定到Java对象上,并将这些对象添加到模型中,以便在视图渲染时使用。
@GetMapping("query")
public Object query(@ModelAttribute StudentBean bean) {}
POST- Form请求@RequestParam
表单提交
@PostMapping("query")
public Object query(@RequestParam("params") {}
POST-JSON请求
@PostMapping("query")
public Object query(@RequestBody StudentBean bean) {}
图片上传
@PostMapping(value = "/uploadFile", name = "上传文件")
public String uploadImage(MultipartFile file){}
请求头@RequestHeader
@Post/GetMapping("query")
public Object query(@RequestHeader("token") String token) {}
// 此时如何请求头中没有token,会报错,不推荐使用
@PostMapping("query")
public Object query(@RequestHeader Map<String, String> headers){}
// 推荐使用Map来接收请求头数据