赞
踩
依赖
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
或
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate effectDay;
"effectDay": "2027-10-16"
查询时自动将数据库中的data类型转换为yyyy-MM-dd HH:mm:ss,一般常使用在响应实体
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")// 中国GMT+8
private LocalDate createTime;
/**
* 疫苗响应实体
*/
@Data
public class CowsVaccineVO implements Serializable {
/**
* 接种时间
*/
@ApiModelProperty("接种时间")
// @JsonFormat(shape= JsonFormat.Shape.STRING,pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
@JsonFormat(shape= JsonFormat.Shape.STRING,pattern="yyyy/MM/dd",timezone="GMT+8")
private LocalDateTime inoculationTime;
@Deprecated是java内置注解,此注解可以用在方法,属性,类上,表示不推荐程序员使用,但是还可以使用
被注解的元素其值必须大于等于指定的值,并且类型为int,long,float,double。
验证 Number 和 String 对象是否小等于指定的值,并且类型为int,long,float,double。
验证对象(Array,Collection,Map,String)被注解的元素的长度必须在指定范围内,并且类型为String,Array,List,Map。
@Size(min = 1, message = "至少要有一个属性")
max和min是对你填的“数字”是否大于或小于指定值,这个“数字”可以是number或者string类型。长度限制用length。
判断该属性是否为null,“”
判断该属性是否为null
判断该属性是否为[]
- @Data 自动生成get和set方法
- @ToString 重写toString
- @EqualsAndHashCode 可以使用字段为该类生成 Equals 和 HashCode 方法。
- @NoArgsConstructor 生成无参构造器
- @AllArgsConstructor 生成全参构造器
- @Slf4j 日志 log.
整数或零
@PositiveOrZero(message = "排序要大于等于0")
private Integer sort;
@Positive(message = "数量要是整数")
private Integer sum;
验证注解的元素值的整数位数和小数位数上限 ,并且类型为float,double,BigDecimal。
@Digits(integer = 12,fraction = 2,message = "整数位上限为12,小数位上限为2")
验证注解的元素值在最小值和最大值之间,并且类型为BigDecimal,BigInteger,CharSequence,byte,short,int,long。
@Range(min = 0,max = 100,message = "必须大于等于0,小于等于100")
注解 :验证注解的元素值长度在min和max区间内 ,并且类型为String。
@Length(min = 11, max = 11, message = "手机号只能为11位")
验证注解的元素值大于等于@DecimalMin指定的value值,并且类型为BigDecimal、BigInteger、double、float。
@DecimalMin(value = "0",message = "初始单价需要大于等于{value}")
@DecimalMin(value = "0",inclusive = false,message = "初始单价需要大于且不等于{value}")
验证注解的元素值小于等于@DecimalMax指定的value值 ,并且类型为BigDecimal、BigInteger、double、float。
@DecimalMax(value = "100",message = "初始单价需要小于等于{value}")
@DecimalMax(value = "100",inclusive = false,message = "初始单价需要小于且不等于{value}")
被注解的元素必须为过去的一个时间,并且类型为java.util.Date。
被注解的元素必须为未来的一个时间,并且类型为java.util.Date。
被注解的元素必须为true,并且类型为boolean。
被注解的元素必须为false,并且类型为boolean。
使用3~9注解前提是在Controller中添加:
@Validated
或 @Valid
才会生效
匹配正则表达式
@NotBlank(message = "手机号码不能为空")
@Length(min = 11, max = 11, message = "手机号只能为11位")
@Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
private String phone;
常用正则表达式
数字
1、数字校验 @Pattern(regexp = "^[0-9]*$",message = "必须为数字") ^[0-9]*$ 2、n位的数字 ^\d{n}$ 3、至少n位的数字 ^\d{n,}$ 4、m-n位的数字 ^\d{m,n}$ 5、零开头的数字 ^(0|[1-9][0-9]*)$ 6、非零开头的最多带两位小数的数字 ^([1-9][0-9]*)+(.[0-9]{1,2})?$ 7、正数、负数、和小数 ^(\-|\+)?\d+(\.\d+)?$ 8、有两位小数的正数值 ^[0-9]+(.[0-9]{2})?$ 9、非零的正整数 ^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$ 10、非零的负整数 ^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$ 11、非负整数 ^\d+$ 或 ^[1-9]\d*|0$ 12、非正整数 ^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$ 13、非负浮点数 ^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ 14、非正浮点数 ^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ 15、正浮点数 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ 16、负浮点数 ^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ 17、浮点数 ^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
字符串
1、汉字 ^[\u4e00-\u9fa5]{0,}$ 2、英文和数字 ^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$ 3、长度为3-20的所有字符 ^.{3,20}$ 4、由26个英文字母组成的字符串 ^[A-Za-z]+$ 5、由26个大写英文字母组成的字符串 ^[A-Z]+$ 6、由26个小写英文字母组成的字符串 ^[a-z]+$ 7、由数字和26个英文字母组成的字符串 ^[A-Za-z0-9]+$ 8、由数字、26个英文字母或者下划线组成的字符串 ^\w+$ 或 ^\w{3,20}$ 9、中文、英文、数字包括下划线 ^[\u4E00-\u9FA5A-Za-z0-9_]+$ 10、可以输入含有^%&',;=?$\"等字符 [^%&',;=?$\x22]+ 11、禁止输入含有~的字符: [^~\x22]+
其他
1、Email地址 ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 2、域名 [a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.? 3、InternetURL [a-zA-z]+://[^\s]* 或 ^https://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ 4、手机号码 ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$ 5、电话号码 ^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 6、国内电话号码(0511-4405222、021-87888822) \d{3}-\d{8}|\d{4}-\d{7} 7、身份证号 15或18位身份证:^\d{15}|\d{18}$ 15位身份证:^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$ 18位身份证:^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$ 8、短身份证号码(数字、字母x结尾) ^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$ 9、帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线) ^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 10、密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线) ^[a-zA-Z]\w{5,17}$ 11、强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间) ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 12、日期格式: ^\d{4}-\d{1,2}-\d{1,2} 13、一年的12个月(01~09和1~12) ^(0?[1-9]|1[0-2])$ 14、中文字符的正则表达式 [\u4e00-\u9fa5] 15、空白行的正则表达式 \n\s*\r (可以用来删除空白行) 16、HTML标记的正则表达式 <(\S*?)[^>]*>.*?|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力) 17、首尾空白字符的正则表达式 ^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式) 18、腾讯QQ号(腾讯QQ号从10000开始) [1-9][0-9]{4,} 19、中国邮政编码(中国邮政编码为6位数字) [1-9]\d{5}(?!\d) 20、IP地址 \d+\.\d+\.\d+\.\d+
这里需要统一处理一下validation的错误信息
@RestControllerAdvice @Order(1) public class ParamCheckExceptionHandler { /** * 校验错误拦截处理 * * @param exception MethodArgumentNotValidException错误类 * @return 错误信息 */ @ExceptionHandler(MethodArgumentNotValidException.class) public Result validationBodyException(MethodArgumentNotValidException exception) { BindingResult result = exception.getBindingResult(); //返回第一个错误 String errMsg = result.getAllErrors().get(0).getDefaultMessage(); return Result.fail(errMsg); } }
@Transactional(rollbackFor = Exception.class)
@ComponentScan(basePackages = {"com.ssy.lingxi"})
@EntityScan(basePackages = {"com.ssy.lingxi.member.merchant.entity"})
@EnableJpaRepositories(basePackages = {"com.ssy.lingxi.member.repositories","come.ssy.lingxi.member.repositories"})
@EnableFeignClients(basePackages = {"com.ssy.lingxi.order.api.feign", "com.ssy.lingxi.workflow.api.feign", "com.ssy.lingxi.sms.api.feign", "com.ssy.lingxi.pay.api.feign", "com.ssy.lingxi.order.api.feign", "com.ssy.lingxi.platform.manage.api.feign", "com.ssy.lingxi.report.api.feign", "com.ssy.lingxi.message.api.feign", "com.ssy.lingxi.product.api.feign", "com.ssy.lingxi.search.api.feign","com.ssy.lingxi.platform.template.api.feign.inner", "com.ssy.lingxi.scheduler.api.feign","com.ssy.lingxi.feign"})
如果需要按照name注入,需要配合@Qualifier(“bookDao”),指定name来使用即可
@Resource装配顺序:
(1)如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
(2)如果指定了name,则从Spring上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
(3)如果指定了type,则从Spring上下文中找到类型匹配的唯一bean进行装配,找不到或找到多个,都抛出异常
(4)如果既没指定name,也没指定type,则自动按照byName方式进行装配。如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入。
@Valid是使用Hibernate validation的时候使用
标准JSR-303规范的标记型注解,用来标记验证属性和方法返回值,进行级联和递归校验
@Validated是只用Spring Validator校验机制使用@Validation对@Valid进行了二次封装,在使用上并没有区别,但在分组、注解位置、嵌套验证等功能上有所不同
Spring的注解,是标准JSR-303的一个变种(补充),提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
方法级别:
@Validated注解可以用于类级别,用于支持Spring进行方法级别的参数校验。@Valid可以用在属性级别约束,用来表示级联校验。
@Validated只能用在类、方法和参数上,而@Valid可用于方法、字段、构造器和参数上
注意:
如果存在嵌套验证可以在入参
添加@Validated
,在需要验证的属性
上添加@Valid
,即可实现嵌套验证
那么何为嵌套验证
这里有个ClassGrade班级的实体类:
@Data
public class ClassGrade{
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为大于0")
private Long id;
@NotNull(message = "props不能为空")
@Size(min = 1, message = "至少要有一个属性")
@Valid
private List<Student> students;
}
班级里有很多学生Student带有很多属性:
@Data public class Student{ @NotNull(message = "id不能为空") @Min(value = 1, message = "id必须为大于0") private Long id; @NotBlank(message = "name不能为空") private String name; @NotNull(message = "age不能为空") private Integer age; @NotBlank(message = "adderss不能为空") private String adderss; }
学生Student这个实体也有自己的验证机制name不能为空,id必须为大于0等
controller必须加@Valid,嵌套验证才会生效
@RestController("/user")
public class ItemController {
@PostMapping("/class/add")
public void addItem(@RequestBody @Valid @Validated ClassGrade classGrade) {
doSomething();
}
}
如果ClassGrade
实体类中的students
属性不额外加注释,只有@NotNull和@Size,无论入参采用@Validated还是@Valid验证,Spring Validation框架只会对ClassGrade的id和students做非空和数量验证,不会对students
字段里的Student
实体进行字段验证,也就是@Validated和@Valid加在方法参数前,都不会自动对参数进行嵌套验证。也就是说如果传的List<Student>
中的id为空或者是负数,入参验证不会检测出来。
为了能够进行嵌套验证,必须手动在ClassGrade
实体的students
字段上明确指出这个字段里面的实体也要进行验证。由于@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能,那么我们能够推断出:@Valid加在方法参数时并不能够自动进行嵌套验证,而是用在需要嵌套验证类的相应字段上,来配合方法参数上@Validated或@Valid来进行嵌套验证。
因此在Controller中的参数添加@Validated注解,并且ClassGrade实体类中的students属性上添加@Valid注解
,这里在Controller中已经添加,所以在Student中添加@Valid注解即可实现嵌套验证
@Data
public class ClassGrade{
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为大于0")
private Long id;
@Valid// 嵌套验证必须用@Valid
@NotNull(message = "props不能为空")
@Size(min = 1, message = "至少要有一个属性")
private List<Student> students;
}
/** * id */ @ApiModelProperty("id") @NotNull(message = "id不能为空",groups = {Update.class, Delete.class}) private Long id; /** * 分类名字 */ @ApiModelProperty("分类名字") @NotBlank(message = "分类名字不能为空", groups = {Insert.class, Update.class}) private String name; /** * 父分类id */ @ApiModelProperty("父分类id") @NotNull(message = "父分类id不能为空", groups = {Insert.class}) @Min(value = 1, message = "父分类id需要大于0", groups = {Insert.class, Update.class}) private Long parentId; private class Insert { } private class Update { }
/** * 新增代码分类 * @param request 请求参数 * @return 结果 */ @ApiOperation(value = "新增代码分类", notes = "新增代码分类", httpMethod = "POST") @PostMapping("/add") public Wrapper add(@RequestBody @Validated(Insert.class) StandardCodeCategoryRequest request) { codeCategoryService.add(request); return Wrapper.success(); } /** * 修改代码分类 * @param request 请求参数 * @return 结果 */ @ApiOperation(value = "修改代码分类", notes = "修改代码分类", httpMethod = "POST") @PostMapping("/update") public Wrapper update(@RequestBody @Validated(Update.class) StandardCodeCategoryRequest request) { codeCategoryService.update(request); return Wrapper.success(); }
或
@PostMapping("/addOrUpdate")
public Wrapper addOrUpdate(@RequestBody TestEntity testEntity) {
System.out.println("testEntity = " + testEntity.toString());
ValidatorUtil.validateParam(testEntity, Insert.class);
return Wrapper.success();
}
/** * 交易类型枚举 * @version 1.0.0 * @date 2022/12/28 */ public enum TransactionTypeEnum { /** * 支付宝支付 - 1 */ ALIPAY_PAY(1, "支付宝支付"), /** * 微信支付 - 2 */ WECHAT_PAY(2, "微信支付"), /** * 银行卡支付 - 3 */ UNION_PAY(3, "银行卡支付"), /** * B2B线上支付 - 4 */ B2B_ONLINE_PAY(4, "B2B线上支付"), /** * 线下支付 - 5 */ OFFLINE_PAY(5, "线下支付"); TransactionTypeEnum(Integer code, String name) { this.code = code; this.name = name; } /** * 类型枚举值 */ private Integer code; /** * 类型名称 */ private String name; public Integer getCode() { return code; } public String getName() { return name; } /** * 根据枚举值获得名称 * @param code 类型枚举值 * @return 类型名称 */ public static String getNameByCode(Integer code) { TransactionTypeEnum typeEnum = Arrays.stream(TransactionTypeEnum.values()).filter(e -> e.getCode().equals(code)).findFirst().orElse(null); return typeEnum == null ? "未知" : typeEnum.getName(); } /** * 获取枚举所有id */ public static List<Integer> toList() { return Arrays.stream(TransactionTypeEnum.values()).map(TransactionTypeEnum::getCode).collect(Collectors.toList()); } /** * 获取所有id和name */ public static List<DropdownItem> toDropdownList() { return Arrays.stream(TransactionTypeEnum.values()).sorted(Comparator.comparingInt(TransactionTypeEnum::getCode)).map(e -> new DropdownItem(e.getCode(), e.getName())).collect(Collectors.toList()); } }
DropdownItem
/** * 下拉框内容返回VO * @version 2.0.0 * @date 2020-07-14 */ @Data public class DropdownItem implements Serializable { public DropdownItem() { } public DropdownItem(Integer id, String text) { this.id = id; this.text = text; } /** * 下拉选择框的id */ private Integer id; /** * 下拉选择框的文本内容 */ private String text; }
通常情况下用枚举判断,名称可能会常变化,但枚举较少
@PostConstruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。
@SpringBootApplication @ComponentScan(basePackages = {"com.my.spider"}) @MapperScan("com.my.spider.mapper") public class MySpiderApplication { @Autowired private SpiderHandle spiderHandle; @Autowired private ContentNoticeHandle contentNoticeHandle; public static void main(String[] args) { SpringApplication.run(MySpiderApplication.class, args); } @PostConstruct public void task(){ contentNoticeHandle.spiderData(); }/* @PostConstruct public void task(){ spiderHandle.spiderData(); } */ }
左移 << 正数左移低位补零,负数左移高位舍弃低位补零
负数例:-6<<2
表示将-6变为2进制数字后整体左移2位,-6的二进制数表示:11111111111111111111111111111010,计算6的负数二进制 = 6的二进制110取反得(111111111111111[符号位补1,符号位+数值位的总位数32位])001,然后加一得(11111111111111111111111111111)010,左移两位变为:(111111111111111111111111111)01000【高位舍弃,低位补零,然后取反+1,即10111(取反)+00001=11000(补码)】,左移后十进制数为 -(24+23)=-(16+8)=-24,其实左移快捷简单的算法可以理解为
注意:符号位不参与移位,负数以补码的形式表示,正数的补码和原码一样,负数的补码由去掉符号位的原码(该数的绝对值)的反码再加一可得
带符号右移 >> 正数右移高位补0,负数右移高位补1
无符号右移 >>> 无论是正数还是负数,高位通通补0
使用方法:多线程下访问(互斥)共享资源时, 访问前加锁,访问结束以后解锁.
// 创建可重入锁
private static final Lock lock = new ReentrantLock();
lock.lock();
try{
代码块;
}finally{
// 释放锁
lock.unlock();
}
public synchronized void syncMethod(){
othercode1();
mutextMethod();
othercode2();
}
改进后
public void syncMethod2(){
othercode1();
synchronized(this){
mutextMethod();
}
othercode2();
}
一个简单的例子就是 jdk 内置的 ConcurrentHashMap 与 SynchronizedMap。
Collections.synchronizedMap 其本质是在读写 map 操作上都加了锁,在高并发下性能一般。
使用数据库的悲观锁for update,在 sql后面加上
for update
在sql语句后加 for update就加上了锁,在查询的时候进行加锁,在加锁后不能进行查询。提交时候后其他人才能查询。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。