注:Sring Validation验证框架对参数的校验机制提供了@Validated(Spring JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。
@Validated配合BindingResult使用个人觉得比较死板,如果不做处理测试校验结果只能校验出有数据不符合制定的规则,并不能校验哪个数据出现了异常。而前端需要拿到你返回的异常信息,所以不能在不作处理的情况下直接给他,不然前端会砍你的。所以后面会提到搭配全局异常处理器使用。
空校验 针对类型 说明
@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地址
springboot项目已经默认导入了基础包,所以无需另行导包,直接使用即可。
1.首先安排一个实体类,下面是在工作时写功能测试用的,今天就用它。
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;
}
上边groups = {Insert.class,Update.class,Select.class,Delete.class}属于分组校验,分别对应增删改查。在controller层使用@Validated(Insert.class,Update.class,Select.class,Delete.class),则会启用相应校验。
2.controller层代码如下
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 insert(@RequestBody @Validated(Insert.class) HostconfigurationEntity hostconf){
return hostconfigurationService.insert(hostconf);
}
}
目前还没有配合全局异常捕获器,先用postman测试一下,下面是我模拟的数据
{
"localhostPort":22,
"localhostPassword":"",
"localhostUsername":"",
"localhostDirectory":"",
"localhostIp":"192.156.124.90",
"numTime":3
}
这是返回的结果,很明显,把整个异常信息带回来了,不知道是哪个属性异常了,这时候全局异常处理器来了:
{"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.Validation校验框架配合全局异常处理器,全局异常处理器代码如下:
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 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 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);
}
}
使用之前的数据再一次请求接口,返回数据如下:
{
"code": 412,
"data": {
"localhostPassword": "长度需要在1和32之间",
"localhostUsername": "用户名只能[a-zA-Z0-9_]中字符,长度不能超过32位",
"localhostDirectory": "不能为空"
},
"message": "客户端请求信息的先决条件错误"
}
如此一来,可以很清楚的看到,请求体中是哪个属性出现了异常,这就是全局异常处理器,可以好好研究一下,由于公司的编码要求严格,数据返回格式做了统一,大家可以自定义。
Sring Validation验证框架就到此结束,后面会逐个更新springcloud核心组件的配置与使用当做个人的云笔记本,觉得不错的小伙伴点个关注哈哈。。。