Spring Validation validation framework @Validated annotations for regular validation, use of group validation, and use with global exception handlers.

Note: The Sring Validation validation framework provides @Validated (Spring JSR-303 specification, which is a variant of the standard JSR-303) for the parameter validation mechanism, and javax provides @Valid (standard JSR-303 specification), which can be used directly with BindingResult Provide parameter verification results.

    The use of @Validated with BindingResult personally feels rather rigid. If you do not do the processing test, the verification result can only verify that there is data that does not meet the established rules, and cannot verify which data is abnormal. The front end needs to get the exception information you return, so you can't directly give it to him without processing, or the front end will cut you off. So the use of the global exception handler will be mentioned later.

Annotation

空校验	针对类型	说明
@Null	任何类型	校验对象必须为空
@NotNull	任何类型	校验对象不为空,不能校验字符串长度为0的对象
@NotBlank	字符串	只对字符串有效,校验字符串去掉前后空格后长度不为0
@NotEmpty	字符串、集合、数组	校验对象不能为空 (字符串长度不为0、集合大小不为0)


boolean校验	针对类型	说明
@AssertTrue	布尔	校验boolean类型必须为true
@AssertFalse	布尔	校验boolean类型必须为false


数值校验	针对类型	说明
@Min	数字类型	校验必须是一个数字,其值必须大于或等于指定的最小值
@Max	数字类型	校验必须是一个数字,其值必须小于或等于指定的最大值
@DecimalMin	数字类型	校验必须是一个数字,其值必须大于或等于指定的最小值
@DecimalMax	数字类型	校验必须是一个数字,其值必须小于或等于指定的最大值
@Digits(integer=,fraction=)	数字类型	校验必须是一个数字,interger指定整数精度,fraction指定小数精度
@Range(min =,max = )	数字类型、字符串	校验对象的值在min和max区间内
@Length(min =,max = )	字符串	校验对象的值的长度在min和max区间内
@Size(min =,max = )	字符串、集合、数组	校验对象的值在min和max区间内,如字符长度、集合大小


其他校验	针对类型	说明
@Email	字符串	校验对象的值必须是Email类型,也可以通过regexp和flag指定自定义的email格式
@Pattern	字符串	校验对象的值必须符合指定的正则表达式
@CreditCardNumber	数字类型、字符串	校验对象的值必须是信用卡类型
@URL	字符串	校验对象的值必须是URL地址

The springboot project has imported the basic package by default, so there is no need to guide the package separately, just use it directly.

1. First arrange an entity class, the following is for writing functional tests at work, use it today.

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.hibernate.validator.constraints.Length;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

/**
 * 文件压缩记录表
 * 
 * @author XRJ
 * @email [email protected]
 * @date 2020-04-06 20:46:31
 */
@Data
@Valid
@TableName("hostconfiguration")
public class HostconfigurationEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 主键id
	 */
	@TableId
	@NotNull(groups = {Update.class})
	private int id;

	/**
	 * 服务器ip
	 */
	@NotNull(groups = {Insert.class})
	@Pattern(groups = {Insert.class, Update.class, Select.class}, regexp = "((2[0-4]\\d|25[0-5]|1?[1-9]?\\d)\\.){3}(2[0-4]\\d|25[0-5]|1?[1-9]?\\d)", message = "请输入合法的IP地址")
	private String localhostIp;

	/**
	 * 服务器账号
	 */
	@NotBlank(groups = {Insert.class})
	@Pattern(groups = {Insert.class, Update.class}, regexp = "\\w{1,32}", message = "用户名只能[a-zA-Z0-9_]中字符,长度不能超过32位")
	private String localhostUsername;

	/**
	 * 服务器密码
	 */
	@NotBlank(groups = {Insert.class})
	@Length(groups = {Insert.class, Update.class}, min = 1, max = 32)
	private String localhostPassword;

	/**
	 * 端口号
	 */
	@NotNull(groups = {Insert.class})
	private Integer localhostPort;

	/**
	 * 需压缩文件路径
	 */
	@NotBlank(groups = {Insert.class})
	private String localhostDirectory;

	/**
	 * 天数,压缩几天前的日志文件
	 */
	@NotNull(groups = {Insert.class})
	private Integer numTime;

	/**
	 * 创建时间
	 */
	private Date createTime;
	/**
	 * 是否成功,0失败,1成功
	 */
	private Integer isSuccess;

}

The above groups = {Insert.class,Update.class,Select.class,Delete.class} belong to group verification, corresponding to add, delete, modify and check. Use @Validated(Insert.class,Update.class,Select.class,Delete.class) in the controller layer to enable the corresponding verification.

2. The controller layer code is as follows

package cn.cm.filecompress.controller;

import cn.cm.filecompress.entity.HostconfigurationEntity;
import cn.cm.filecompress.service.HostconfigurationService;
import cn.cm.filecompress.tool.FileCompressTool;
import cn.cm.filecompress.tool.Result;
import com.jcraft.jsch.JSchException;
import org.apache.ibatis.annotations.Insert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 文件压缩记录表
 *
 * @author XRJ
 * @email [email protected]
 * @date 2020-04-06 20:46:31
 */
@RestController
@RequestMapping("/hostconfiguration")
public class HostconfigurationController {
    @Autowired
    private HostconfigurationService hostconfigurationService;

    @PostMapping(value = "/add",produces = "application/json;charset=UTF-8")
    public Result<Integer> insert(@RequestBody @Validated(Insert.class) HostconfigurationEntity hostconf){
        return hostconfigurationService.insert(hostconf);
    }
}

At present, it has not cooperated with the global exception catcher, first test it with postman, the following is my simulated data

{
	"localhostPort":22,
	"localhostPassword":"",
	"localhostUsername":"",
	"localhostDirectory":"",
	"localhostIp":"192.156.124.90",
	"numTime":3
}

This is the returned result. Obviously, the entire exception information is brought back. I don't know which attribute is abnormal. At this time, the global exception handler comes:

{"timestamp":1587890386937,"status":400,"error":"Bad Request","errors":[{"codes":["Length.hostconfigurationEntity.localhostPassword","Length.localhostPassword","Length.java.lang.String","Length"],"arguments":[{"codes":["hostconfigurationEntity.localhostPassword","localhostPassword"],"arguments":null,"defaultMessage":"localhostPassword","code":"localhostPassword"},32,1],"defaultMessage":"长度需要在1和32之间","objectName":"hostconfigurationEntity","field":"localhostPassword","rejectedValue":"","bindingFailure":false,"code":"Length"},{"codes":["NotBlank.hostconfigurationEntity.localhostPassword","NotBlank.localhostPassword","NotBlank.java.lang.String","NotBlank"],"arguments":[{"codes":["hostconfigurationEntity.localhostPassword","localhostPassword"],"arguments":null,"defaultMessage":"localhostPassword","code":"localhostPassword"}],"defaultMessage":"不能为空","objectName":"hostconfigurationEntity","field":"localhostPassword","rejectedValue":"","bindingFailure":false,"code":"NotBlank"},{"codes":["Pattern.hostconfigurationEntity.localhostUsername","Pattern.localhostUsername","Pattern.java.lang.String","Pattern"],"arguments":[{"codes":["hostconfigurationEntity.localhostUsername","localhostUsername"],"arguments":null,"defaultMessage":"localhostUsername","code":"localhostUsername"},[],{"defaultMessage":"\\w{1,32}","arguments":null,"codes":["\\w{1,32}"]}],"defaultMessage":"用户名只能[a-zA-Z0-9_]中字符,长度不能超过32位","objectName":"hostconfigurationEntity","field":"localhostUsername","rejectedValue":"","bindingFailure":false,"code":"Pattern"},{"codes":["NotBlank.hostconfigurationEntity.localhostUsername","NotBlank.localhostUsername","NotBlank.java.lang.String","NotBlank"],"arguments":[{"codes":["hostconfigurationEntity.localhostUsername","localhostUsername"],"arguments":null,"defaultMessage":"localhostUsername","code":"localhostUsername"}],"defaultMessage":"不能为空","objectName":"hostconfigurationEntity","field":"localhostUsername","rejectedValue":"","bindingFailure":false,"code":"NotBlank"},{"codes":["NotBlank.hostconfigurationEntity.localhostDirectory","NotBlank.localhostDirectory","NotBlank.java.lang.String","NotBlank"],"arguments":[{"codes":["hostconfigurationEntity.localhostDirectory","localhostDirectory"],"arguments":null,"defaultMessage":"localhostDirectory","code":"localhostDirectory"}],"defaultMessage":"不能为空","objectName":"hostconfigurationEntity","field":"localhostDirectory","rejectedValue":"","bindingFailure":false,"code":"NotBlank"}],"message":"Validation failed for object='hostconfigurationEntity'. Error count: 5","path":"/compress/hostconfiguration/add"}

3. The Validation verification framework cooperates with the global exception handler, the global exception handler code is as follows:

package cn.cm.filecompress.tool;

import com.alibaba.fastjson.JSONObject;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * description : 全局异常处理器
 */
@ControllerAdvice
public class GlobalExceptionHandler {

//    private static final SystemLogger LOGGER = SystemLogger.getLogger(GlobalExceptionHandler.class);

    /**
     * 方法入参支持:Exception、SessionAttribute、@RequestAttribute、HttpServletRequest、HttpServletResponse、HttpSession
     * 方法返回支持: ModelAndView、@ResponseBody、ResponseEntity
     */
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public Result<String> error(HttpServletResponse response, Exception e) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
//        LOGGER.error("全局异常捕获", e);
        try {
            response.getWriter().print(JSONObject.toJSONString(Result.of(Code.SC_INTERNAL_SERVER_ERROR.getState(), Code.SC_INTERNAL_SERVER_ERROR.getDescription(), e.toString())));
        } catch (IOException exc) {
//            LOGGER.error("全局异常捕获响应失败", exc);
        }
        return null;
//        return new Result<>(Code.SC_INTERNAL_SERVER_ERROR, e.toString());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public String handleMethodArgumentNotValid(HttpServletResponse response, Exception e) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
        BindingResult bindingResult = ex.getBindingResult();
        Map<String, Object> map = new HashMap<>();
        for (FieldError error : bindingResult.getFieldErrors()) {
            String field = error.getField();
            String msg = error.getDefaultMessage();
//            Object value = error.getRejectedValue();
//            map.put(field, String.format("{'value':'%s','errorMsg','%s'}", value, msg));
            map.put(field, msg);
        }
        try {
            response.getWriter().print(JSONObject.toJSONString(Result.of(Code.SC_PRECONDITION_FAILED.getState(), Code.SC_PRECONDITION_FAILED.getDescription(), map)));
        } catch (IOException exc) {
//            LOGGER.error("统一参数异常处理响应失败", exc);
        }
        return null;
//        return new Result<>(Code.SC_PRECONDITION_FAILED, map);
    }
}

Use the previous data to request the interface again, and the returned data is as follows:

{
    "code": 412,
    "data": {
        "localhostPassword": "长度需要在1和32之间",
        "localhostUsername": "用户名只能[a-zA-Z0-9_]中字符,长度不能超过32位",
        "localhostDirectory": "不能为空"
    },
    "message": "客户端请求信息的先决条件错误"
}

In this way, you can clearly see which attribute in the request body is abnormal. This is the global exception handler. You can study it carefully. Due to the company’s strict coding requirements, the data return format has been unified. definition.

This is the end of the Sring Validation verification framework. Later, the configuration and use of springcloud core components will be updated one by one as a personal cloud notebook. I think a good friend pays attention to it. Haha. . .

Guess you like

Origin blog.csdn.net/weixin_46792649/article/details/105768359