实体字段校验 @NotNull、@NotEmpty、@NotBlank
1.@NotNull
:不能为 null,但可以为 empty,一般用在 Integer 类型的基本数据类型的非空校验上,而且被其标注的字段可以使用
@size、@Max、@Min 对字段数值进行大小的控制
2.@NotEmpty
: 不能为 null,且长度必须大于 0,一般用在集合类上或者数组上
3.@NotBlank
:只能作用在接收的 String 类型上,注意是只能,不能为 null,而且调用 trim() 后,长度必须大于
0即:必须有实际字符
4. GET请求参数校验
4.1 直接在请求方法中对参数实现注解校验
需要在 Controller类上添加 @Validated ,否则会出翔意料外错误;
4.2 使用对象方式进行接收参数,请求对象中添加注解校验
需要再参数前添加 @Valid或者@Validated ,并且对象要实现 implements Serializable 接口
@Valid与@Validated区别:后者是前者的补充,前者能做的后者都能做,并且后者支持分组、级联操作等.所以在请求对象前面加@Valid同样生效.
https://blog.csdn.net/weixin_43401380/article/details/121845901
https://blog.csdn.net/yuanchangliang/article/details/109325867
4.3示例代码:
Controller
package net.cnki.editor.expense.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import net.cnki.editor.common.dto.CurrentUserDTO;
import net.cnki.editor.common.web.BaseController;
import net.cnki.editor.common.web.JsonResult;
import net.cnki.editor.common.web.PageParam;
import net.cnki.editor.common.web.PageResult;
import net.cnki.editor.expense.core.invoice.common.beans.ToInvoiceOrderDetail;
import net.cnki.editor.expense.dao.PayconfigDOMapper;
import net.cnki.editor.expense.pojo.dos.*;
import net.cnki.editor.expense.pojo.dto.IDDTO;
import net.cnki.editor.expense.pojo.dto.PayconfigDTO;
import net.cnki.editor.expense.pojo.dto.UpdatePayconfigDTO;
import net.cnki.editor.expense.pojo.query.ListPayconfigsQuery;
import net.cnki.editor.expense.pojo.vo.PayconfigInfoVO;
import net.cnki.editor.expense.pojo.vo.PayconfigVO;
import net.cnki.editor.expense.service.ExpenseCacheService;
import net.cnki.editor.expense.service.PayconfigDOService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Validated
@RestController
@Api(tags = "PayConfigController", description = "管理接口->客户支付服务配置")
@RequestMapping("/admin/payconfig")
@Slf4j
public class PayConfigController extends BaseController {
//todo
@ApiOperation("查看 客户支付服务配置详情")
@RequestMapping(value = "/payconfig_info_byname", method = RequestMethod.GET)
public JsonResult<PayconfigInfoVO> getPayconfig(
@NotBlank @ApiParam("服务商标识") @RequestParam(name = "name", required = true) String name
, @NotBlank @ApiParam("期刊代码") @RequestParam(name = "journalCode", required = true) String journalCode
, @Valid ToInvoiceOrderDetail t1
, @Validated ToInvoiceOrderDetail t2
) {
PayconfigInfoVO vo = new PayconfigInfoVO();
try {
Optional<PayconfigDO> clientPayConfig = cacheService.getClientPayConfig(journalCode, journalCode, name);
if (clientPayConfig.isPresent()) {
PayconfigDO payconfigDO = clientPayConfig.get();
BeanUtil.copyProperties(payconfigDO, vo);
return JsonResult.success(vo);
}
} catch (Exception e) {
log.error("支付服务配置 获取缓存失败 { }", e);
}
LambdaQueryWrapper<PayconfigDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PayconfigDO::getPayProviderId, name)
.eq(PayconfigDO::getClientAppKey, journalCode)
.eq(PayconfigDO::getEnabled, true);
PayconfigDO payconfigDO = payconfigDOMapper.selectOne(wrapper);
BeanUtil.copyProperties(payconfigDO, vo);
return JsonResult.success(vo);
}
}
实体类
package net.cnki.editor.expense.core.invoice.common.beans;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* Author: xjiaopi
* Date: 2024/4/29
* Description: ToInvoiceOrderDetail
*/
@Data//todo
public class ToInvoiceOrderDetail implements Serializable {
/* 商品名称 */
@NotBlank
String goodsName;
/* 含税金额,单位为元 */
Double price;
/* 数量 */
Integer num;
/* 税率 */
Float taxRate;
/* 商品编码 */
String goodsCode;
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public Float getTaxRate() {
return taxRate;
}
public void setTaxRate(Float taxRate) {
this.taxRate = taxRate;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public String getGoodsCode() {
return goodsCode;
}
public void setGoodsCode(String goodsCode) {
this.goodsCode = goodsCode;
}
}
注意
一个 BigDecimal 的字段使用字段校验标签应该为 @NotNull。
在使用 @Length 一般用在 String 类型上可对字段数值进行最大长度限制的控制。
在使用 @Range 一般用在 Integer 类型上可对字段数值进行大小范围的控制。
如下图示:
测试
1.String name = null;
@NotNull: false
@NotEmpty:false
@NotBlank:false
2.String name = "";
@NotNull:true
@NotEmpty: false
@NotBlank: false
3.String name = " ";
@NotNull: true
@NotEmpty: true
@NotBlank: false
4.String name = "Hello World!";
@NotNull: true
@NotEmpty:true
@NotBlank:true
常见类型校验
import java.util.Date; 时间类型
@NotNull 不能为 null,但可以为 empty,必须传
参考:
解决日期转换异常 https://blog.csdn.net/qq_40269087/article/details/112723364
@DateTimeFormat 和 @JsonFormat 注解详解 https://blog.csdn.net/weixin_43888891/article/details/126846791
public enum TaxMaterial 枚举类型
@NotNull 不能为 null,必须传入PAPRE或ELECTRONIC或ALLELECTRONIC_PAPER或ALLELECTRONIC_PDF 字符串
package net.cnki.editor.expense.core.invoice.common.beans;
public enum TaxMaterial {
PAPRE("纸质发票"),
ELECTRONIC("电子发票"),
ALLELECTRONIC_PAPER("全电票纸质"),
ALLELECTRONIC_PDF("全电票电子");
String name;
TaxMaterial(String name) {this.name = name;}}
实体类
@Valid 校验成员变量类内部属性 @NotNull(message = "不能为 null,但可以为 empty ") 两个注解最好同时使用
类集合
@Valid 校验成员变量类内部属性 @NotNull(message = "不能为 null,但可以为 empty ") @NotEmpty(message = "不能为 null,且长度必须大于 0")
包装类
@NotNull(message = "不能为 null,必须传值 ")
基本数据类型
当入参为null时,会使用基本数据类型的默认值0;
BigDecimal 类型
@NotNull 一个 BigDecimal 的字段使用字段校验标签应该为 @NotNull。
示例代码
dto
package net.cnki.editor.expense.pojo.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import net.cnki.editor.expense.core.invoice.common.beans.TaxMaterial;
import net.cnki.editor.expense.core.invoice.common.beans.ToInvoiceOrderDetail;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
@Data
public class UpdatePayconfigDTO {
@NotNull(message = "时间null ")
@ApiModelProperty(value = "时间 yyyy-MM-dd HH:mm:ss", required = true)
@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
Date orderDate2;
@NotNull(message = "枚举 ")
@ApiModelProperty(value = "枚举 ", required = true)
TaxMaterial taxMaterial;
@NotNull(message = "类3 ")
@ApiModelProperty(value = "类3 ", required = true)
ToInvoiceOrderDetail lei3;
@Valid
@NotNull(message = "集合3 ")
@ApiModelProperty(value = "类集合 ", required = true)
List<ToInvoiceOrderDetail> orderDetails3;
@Valid
@NotEmpty(message = "类4 ")
@ApiModelProperty(value = "类集合 ", required = true)
List<ToInvoiceOrderDetail> orderDetails4;
@NotNull(message = "包装类1 ")
@ApiModelProperty(value = "包装类1 ", required = true)
Integer num1;
@ApiModelProperty(value = "包装类1 ", required = true)
int num3;
}
枚举类 enum
package net.cnki.editor.expense.core.invoice.common.beans;
/**
* Author: xjiaopi
* Date: 2024/5/21
* Description: TaxMaterial
*/
public enum TaxMaterial {
PAPRE("纸质发票"),
ELECTRONIC("电子发票"),
ALLELECTRONIC_PAPER("全电票纸质"),
ALLELECTRONIC_PDF("全电票电子")
;
String name;
TaxMaterial(String name) {
this.name = name;
}
}
对象类
package net.cnki.editor.expense.core.invoice.common.beans;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* Author: xjiaopi
* Date: 2024/4/29
* Description: ToInvoiceOrderDetail
*/
@Data//todo
public class ToInvoiceOrderDetail implements Serializable {
private static final long serialVersionUID = 1L;
/* 商品名称 */
@NotBlank
String goodsName;
/* 含税金额,单位为元 */
Double price;
/* 数量 */
Integer num;
/* 税率 */
Float taxRate;
/* 商品编码 */
String goodsCode;
}
Controller
package net.cnki.editor.expense.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import net.cnki.editor.common.dto.CurrentUserDTO;
import net.cnki.editor.common.web.BaseController;
import net.cnki.editor.common.web.JsonResult;
import net.cnki.editor.common.web.PageParam;
import net.cnki.editor.common.web.PageResult;
import net.cnki.editor.expense.dao.PayconfigDOMapper;
import net.cnki.editor.expense.pojo.dos.*;
import net.cnki.editor.expense.pojo.dto.IDDTO;
import net.cnki.editor.expense.pojo.dto.PayconfigDTO;
import net.cnki.editor.expense.pojo.dto.UpdatePayconfigDTO;
import net.cnki.editor.expense.pojo.query.ListPayconfigsQuery;
import net.cnki.editor.expense.pojo.vo.PayconfigInfoVO;
import net.cnki.editor.expense.pojo.vo.PayconfigVO;
import net.cnki.editor.expense.service.ExpenseCacheService;
import net.cnki.editor.expense.service.PayconfigDOService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Validated
@RestController
@Api(tags = "PayConfigController", description = "管理接口->客户支付服务配置")
@RequestMapping("/admin/payconfig")
@Slf4j
public class PayConfigController extends BaseController {
//todo
@ApiOperation("查看 客户支付服务配置详情")
@RequestMapping(value = "/payconfig_info_byname", method = RequestMethod.GET)
public JsonResult<PayconfigInfoVO> getPayconfig(
@NotBlank @ApiParam("服务商标识") @RequestParam(name = "name", required = true) String name
, @NotBlank @ApiParam("期刊代码") @RequestParam(name = "journalCode", required = true) String journalCode
, @Valid ToInvoiceOrderDetail t1
, @Validated ToInvoiceOrderDetail t2
) {
PayconfigInfoVO vo = new PayconfigInfoVO();
try {
Optional<PayconfigDO> clientPayConfig = cacheService.getClientPayConfig(journalCode, journalCode, name);
if (clientPayConfig.isPresent()) {
PayconfigDO payconfigDO = clientPayConfig.get();
BeanUtil.copyProperties(payconfigDO, vo);
return JsonResult.success(vo);
}
} catch (Exception e) {
log.error("支付服务配置 获取缓存失败 { }", e);
}
LambdaQueryWrapper<PayconfigDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PayconfigDO::getPayProviderId, name)
.eq(PayconfigDO::getClientAppKey, journalCode)
.eq(PayconfigDO::getEnabled, true);
PayconfigDO payconfigDO = payconfigDOMapper.selectOne(wrapper);
BeanUtil.copyProperties(payconfigDO, vo);
return JsonResult.success(vo);
}
//todo
@ApiOperation("修改 客户支付服务配置")
@RequestMapping(value = "/update_payconfig", method = RequestMethod.POST)
public JsonResult<?> update(@Valid @RequestBody UpdatePayconfigDTO dto) {
System.out.println("入参: " + dto.toString());
PayconfigDO tbPayconfigServiceById = tbPayconfigService.getById(dto.getId());
try {
if (tbPayconfigServiceById != null) {
String jc = "";
if (StrUtil.isNotBlank(tbPayconfigServiceById.getClientKey())) {
jc = tbPayconfigServiceById.getClientKey();
} else {
jc = tbPayconfigServiceById.getClientAppKey();
}
cacheService.clearClientPayConfigs(jc);
}
} catch (Exception e) {
log.error("支付服务配置 清除缓存失败 { }", e);
}
PayconfigDO payconfigDO = new PayconfigDO();
BeanUtil.copyProperties(dto, payconfigDO);
tbPayconfigService.updateById(payconfigDO);
return JsonResult.success();
}
}
常用的校验注解
javax.validation.constraints.xxx
注解 说明
@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(value) 被注释的元素必须符合指定的正则表达式。
@Email 被注释的元素必须是电子邮件地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串必须非空
@Range 被注释的元素必须在合适的范围内
附 @JsonFormat
有时使用 @JsonFormat 注解时,查到的时间可能会比数据库中的时间少八个小时,这是由于时区差引起的,JsonFormat 默认的时区是 Greenwich Time, 默认的是格林威治时间,而我们是在东八区上,所以时间会比实际我们想得到的时间少八个小时。需要在后面加上一个时区,如下示例:
1
@JsonFormat(pattern=“yyyy-MM-dd”,timezone=“GMT+8”)
private Date date;
@JsonFormat(pattern=“yyyy-MM-dd”,timezone=“GMT+8”)
private Date date;