字段校验
在前端提交表单到后端的时候,不仅仅前端需要对表单进行验证,后端同样需要对表单进行验证。这个非常重要!
在springboot可以使用注解完成这一个工作
在pom.xml中我们需要加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
验证规则
加入之后刷新下maven,我们定义一个实体类比如叫Rule
public class Rule {
@Min(value = 0,message = "ID最小值为1")
private Integer id;
@NotBlank
@Length(min = 1,max = 30,message = "路由字段应该在{min}~{max}之间")
private String name;
@NotBlank
@Length(min = 2,max = 10,message = "名称字段应该在{min}~{max}之间")
private String title;
private Byte type;
@NotNull
@Min(value = 0,message = "状态值最小值为0")
@Max(value = 1,message = "状态值最小值为1")
private Byte status;
@NotNull
@Min(value = 0,message = "上级的ID最小值为0")
private Integer pid;
@Length(min = 1,max = 100)
private String icon;
@Min(value = 0,message = "排序最小值为0")
private Integer sort;
public Rule(Integer id, String name, String title, Byte type, Byte status, Integer pid, String icon, Integer sort) {
this.id = id;
this.name = name;
this.title = title;
this.type = type;
this.status = status;
this.pid = pid;
this.icon = icon;
this.sort = sort;
}
public Rule() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title == null ? null : title.trim();
}
public Byte getType() {
return type;
}
public void setType(Byte type) {
this.type = type;
}
public Byte getStatus() {
return status;
}
public void setStatus(Byte status) {
this.status = status;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon == null ? null : icon.trim();
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
}
校验的规则
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator 附加的 constraint
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@URL(protocol=,host=, port=, regexp=, flags=) 被注释的字符串必须是一个有效的url
@CreditCardNumber 被注释的字符串必须通过Luhn校验算法,银行卡,信用卡等号码一般都用Luhn计算合法性
对于@NotNull,@NotBlank,@NotEmpty这三个注解,我很多时候分不清楚,我网上查了下资料总结下:
解释:
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串.
@NotBlank 检查约束 (字符串) 是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查(集合)约束元素是否为NULL或者是EMPTY.
总结:
@NotEmpty 用在集合类上面更适合
@NotBlank 用在String上面
@NotNull 用在基本类型上
同时需要在控制器的方法中加上@Valid注解
@PostMapping("addrule_save")
@ResponseBody
public ResponseJson<String> addruleSave(
@Valid Rule rule
){
return iRuleService.addRule(rule);
}
如果是控制器上面参数需要在类上加入@Validated注解
@PostMapping("test")
@ResponseBody
public String test(@NotNull(message = "test不能为空啊啊啊") String test,
@Length(min = 1,max = 2,message = "name最小1,最大2") String name){
return "123456";
}
异常处理
如果参数校验没有通过的话,会直接抛异常的,这样不利于用户体验。所以需要对异常进行一个处理!
在项目包下新建一个目录叫exception用于存放我们的异常处理类。GlobalExceptionHandler.class
这里我们要用到两个关于异常的注解
@RestControllerAdvice == @ControllerAdvice + @ResponseBody
@ExceptionHandler
package com.haihao.exception;
import com.haihao.common.ExceptionUtils;
import com.haihao.common.ResponseJson;
import org.apache.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Created with IntelliJ IDEA.
*
* @Author: haihao 846548324@qq.com
* @Date: 2021/06/24/15:26
* @Description:
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = Logger.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = WebException.class)
public ResponseJson<String> webException(HttpServletRequest req,WebException e){
log.error("业务发生了异常:"+e.getMessage());
return ResponseJson.codeErrorMessage(e.getMessage());
}
@ExceptionHandler(value = NullPointerException.class)
public ResponseJson<String> exceptionHandler(HttpServletRequest req,NullPointerException e){
log.error("发生了空指针异常:"+e.getMessage());
return ResponseJson.codeErrorNull(e.getMessage());
}
//如果是在实体类校验会进入到这个异常当中
@ExceptionHandler(value = BindException.class)
public ResponseJson<String> getBindException(HttpServletRequest req, BindException e){
System.out.println("我执行到了这里1111111");
String errorMessage = ExceptionUtils.getBindErrorMessage(e.getBindingResult());
return ResponseJson.codeErrorMessage(errorMessage);
}
//如果是在控制器校验单独的参数会进入到这个异常当中
@ExceptionHandler(value = ConstraintViolationException.class)
public ResponseJson<String> getConstraintViolationException(ConstraintViolationException e){
Set<ConstraintViolation<?>> cv = e.getConstraintViolations();
StringBuffer errorMsg = new StringBuffer();
cv.forEach(ex -> errorMsg.append(ex.getMessage()));
String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
return ResponseJson.codeErrorMessage(errorMsg.toString());
}
/**
* 网上看到很多人是在这个里面处理校验异常的,但是不知道为什么我的程序没有进入到这个里面来,
* 有知道的大佬麻烦讲解下,百度也没得到解释。
* @param ex
* @return
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseJson<String> handleBindGetException(MethodArgumentNotValidException ex){
System.out.println("我执行到了这里222222");
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(x -> x.getDefaultMessage())
.collect(Collectors.toList());
System.out.println(errors);
String errMsg = ex.getBindingResult().getFieldError().getDefaultMessage().toString();
System.out.println(errMsg);
log.error("校验失败:"+ errMsg);
// List<String> list = new ArrayList<>();
// if(ex.getBindingResult().getAllErrors().isEmpty()){
// for (ObjectError error : ex.getBindingResult().getAllErrors()){
// list.add(error.getDefaultMessage().toString());
// }
// }
return ResponseJson.codeErrorMessage(errMsg);
}
}
本人也是java的小白,有可能有些地方写的不正确,或者说可以写的更好。还麻烦各位大佬指点下。万分感激!