Spring-boot搭建基础的开发环境(三)

字段校验

在前端提交表单到后端的时候,不仅仅前端需要对表单进行验证,后端同样需要对表单进行验证。这个非常重要!
在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的小白,有可能有些地方写的不正确,或者说可以写的更好。还麻烦各位大佬指点下。万分感激!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Richai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值