自定义注解实现验证逻辑
- 导包
<!-- hibernate 验证框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
- 定义BO对象,前端传来的业务对象,对象中的属性需要校验
package com.imooc.boapi;
//import com.imooc.annotationcustom.VlogId;
import com.imooc.annotationcustom.VlogId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class VlogBOApi {
private String id;
@VlogId(message = "用户不存在,禁止插入视频")
private String vlogerId;
private String url;
private String cover;
private String title;
private Integer width;
private Integer height;
private Integer likeCounts;
private Integer commentsCounts;
}
- 定义一个校验注解
package com.imooc.annotationcustom;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = VlogIdValidator.class) //校验的逻辑处理类
public @interface VlogId {
String message();
/**
* 将validator进行分类,不同的类group中会执行不同的validator操作
*
* @return validator的分类类型
*/
Class<?>[] groups() default {};
/**
* 主要是针对bean,很少使用
*
* @return 负载
*/
Class<? extends Payload>[] payload() default {};
}
- 同时需要一个校验类,实现一个注解检验的逻辑
package com.imooc.annotationcustom;
import com.imooc.mapper.UsersMapper;
import com.imooc.pojo.Users;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Slf4j
@Component
public class VlogIdValidator implements ConstraintValidator<VlogId, String> {
@Autowired
UsersMapper usersMapper;
@Override
public void initialize(VlogId constraintAnnotation) {
log.info("注解逻辑初始化");
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
Users user = new Users();
user.setId(s);
Users reslut = usersMapper.selectByPrimaryKey(user);
System.out.println("注解拦截生效+package com.imooc.annotationcustom;");
if (reslut == null) {
return false;
} else {
return true;
}
}
}
- 业务代码
@PostMapping("publish")
public GraceJSONResult publish(@Valid @RequestBody VlogBOApi vlogBO) {
// vlogService.createVlog(vlogBO);
return GraceJSONResult.ok();
}
- 校验失败异常,定义一个全局异常捕获,将这个错误返回给前端
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public GraceJSONResult returnMethodArgumentNotValid(MethodArgumentNotValidException e) {
BindingResult result = e.getBindingResult();
Map<String, String> map = getErrors(result);
return GraceJSONResult.errorMap(map);
}
自定义注解来简化开发
目的:做一个点赞次数拦截的功能。过程:需要拦截以后自行确定多少时间内的点赞次数
- 定义注解:
package com.imooc.annotationcustom;
import java.lang.annotation.*;
@Inherited
@Documented
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
/**
* 时间内 秒为单位
* @return
*/
int second() default 10;
/***
* 允许访问次数
* @return
*/
int maxCount() default 5;
}
- 拦截器代码,这里需要获取接口上的自定义注解handlerMethod.getMethodAnnotation
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
//获取RequestLimit注解
RequestLimit requestLimit = handlerMethod.getMethodAnnotation(RequestLimit.class);
if (null == requestLimit) {
System.out.println("没有获取到注解");
return true; //每加注解说明没有限制,多少次都ok
}
//限制的时间范围
int seconds = requestLimit.second();
//限制时间内的最大次数
int maxCount = requestLimit.maxCount();
//获取用户ip
String userIp = IPUtil.getRequestIp(request);
//判断redis中是否有ip
boolean keyIsExist = redis.keyIsExist(LIKE_VLOG_OPERATE_COUNT + ":" + userIp);
//如果没有这个键,说明当前用户在20s内没有点过赞,因为这个拦截器就是拦截点赞的后端接口,所以如果没有这个键就设置一个键
if (keyIsExist == false) {
redis.set(LIKE_VLOG_OPERATE_COUNT + ":" + userIp, "0", seconds);
System.out.println("ok");
return true;
}
// 返回true,就要判断这个键对应的值的个数
String res = redis.get(LIKE_VLOG_OPERATE_COUNT + ":" + userIp);
if (Integer.valueOf(res) >= maxCount) {
GraceException.display(ResponseStatusEnum.LIKE_VLOG_WAIT_ERROR);
return false;
}
}
return true;
}
- 业务代码
@PostMapping("like")
//TODO: 这里需要调试
@RequestLimit(maxCount = 3, second = 60)
public GraceJSONResult like(@RequestParam String userId,
@RequestParam String vlogerId,
@RequestParam String vlogId,
HttpServletRequest request) {
vlogService.userLikeVlog(userId, vlogId);
redis.increment(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + vlogerId, 1);
redis.increment(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId, 1);
redis.set(REDIS_USER_LIKE_VLOG + ":" + userId + ":" + vlogId, "1");
//------------------------------------------//
//新增功能,限制点赞次数,
String userIp = IPUtil.getRequestIp(request);
redis.increment(LIKE_VLOG_OPERATE_COUNT + ":" + userIp,1);
//-------------------------------------------//
return GraceJSONResult.ok();
}