2.利用aop自定义注解4.0.0 org.springframework.boot spring-boot-starter-parent 2.5.5 com.yhy custom-annotation 0.0.1-SNAPSHOT custom-annotation Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-validation org.projectlombok lombok 1.18.20 cn.hutool hutool-all 5.7.13 org.springframework.boot spring-boot-maven-plugin
annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnalysisActuator {
String note() default "";
}
aop
通知需要用到自定义注解类,方便拿到注解信息,就写在serviceStatistics方法参数里,spring自动注入
@Aspect
@Component
public class AnalysisActuatorAspect {
final static Logger log = LoggerFactory.getLogger(AnalysisActuatorAspect.class);
ThreadLocal beginTime = new ThreadLocal<>();
@Pointcut("@annotation(analysisActuator)")
public void serviceStatistics(AnalysisActuator analysisActuator) {
}
@Before("serviceStatistics(analysisActuator)")
public void doBefore(JoinPoint joinPoint, AnalysisActuator analysisActuator) {
// 记录请求到达时间
beginTime.set(System.currentTimeMillis());
log.info("note:{}", analysisActuator.note());
}
@After("serviceStatistics(analysisActuator)")
public void doAfter(AnalysisActuator analysisActuator) {
log.info("statistic time:{}, note:{}", System.currentTimeMillis() - beginTime.get(), analysisActuator.note());
}
}
service
@Service
public class HelloWorldService {
@AnalysisActuator(note = "获取聊天信息方法")
public String getHelloMessage(String name) {
return "Hello " + Optional.ofNullable(name).orElse("World!");
}
}
controller
@RestController
@RestController
public class HelloWorldController {
@Autowired
private HelloWorldService helloWorldService;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello(String name) {
return helloWorldService.getHelloMessage(name);
}
}
访问 http://127.0.0.1:8081/hello
结果
note:获取聊天信息方法 statistic time:0, note:获取聊天信息方法3. 自定义校验注解
需求:导入表格每行数据封装到类里,然后要校验数据合法性,如果数据有错误,则返回错误信息
问题:如果属性很多,一个一个if判断,那就得写很多if,不优雅
解决:通过实现ConstraintValidator完成自定义校验注解,填写错误信息,然后手动校验,错误则获取错误信息
@Constraint 指定校验实现类,两个属性groups和payload是必须添加的(实现ConstraintValidator需要)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ExcelDataValidator.class})
public @interface ExcelDataVaild {
int min() default 2;
int max() default 255;
String message() default "";
Class>[] groups() default {};
Class extends Payload>[] payload() default {};
}
校验类需要实现ConstraintValidator接口。
接口使用了泛型,需要指定两个参数,第一个自定义注解类,第二个为需要校验的数据类型。
实现接口后要override两个方法,分别为initialize方法和isValid方法。其中initialize为初始化方法,可以在里面做一些初始化操作。isValid方法就是我们最终需要的校验方法了,可以在该方法中实现具体的校验步骤。
public class ExcelDataValidator implements ConstraintValidator{ private int min; private int max; @Override public void initialize(ExcelDataVaild excelDataVaild) { min = excelDataVaild.min(); max = excelDataVaild.max(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (StrUtil.isBlank(value) || value.length() < min || value.length() > max) { return false; } return true; } }
需要校验的类
@Data
public class User {
@ExcelDataVaild(min = 2, max = 6,message = "名字错误")
private String name;
@ExcelDataVaild(min = 11, max = 11,message = "手机号错误")
private String phone;
@ExcelDataVaild(min = 5, max = 32,message = "地址错误")
private String address;
}
手动校验工具
@Slf4j
public class ValidatorUtils {
private static Validator validatorFast = Validation.byProvider(Hibernatevalidator.class).configure().failFast(true).buildValidatorFactory().getValidator();
private static Validator validatorAll = Validation.byProvider(Hibernatevalidator.class).configure().failFast(false).buildValidatorFactory().getValidator();
public static Set> validateFast(T domain) {
Set> validateResult = validatorFast.validate(domain);
if (validateResult.size() > 0) {
log.info(validateResult.iterator().next().getPropertyPath() + ":" + validateResult.iterator().next().getMessage());
}
return validateResult;
}
public static Set> validateAll(T domain) {
Set> validateResult = validatorAll.validate(domain);
if (validateResult.size() > 0) {
Iterator> it = validateResult.iterator();
while (it.hasNext()) {
ConstraintViolation cv = it.next();
log.info(cv.getPropertyPath() + ":" + cv.getMessage());
}
}
return validateResult;
}
}
业务层
@Service
public class UserService {
public void vaildUser() {
//假装读取excel表格数据并封装到user
User user = new User();
user.setName("1");
user.setPhone("1231233213");
user.setAddress("eeddd");
Set> validateResult = null;
try {
validateResult = ValidatorUtils.validateAll(user);
if (validateResult.size() > 0) {
//获取检验信息,进行业务处理
System.out.println(validateResult.iterator().next().getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制层
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/user", method = RequestMethod.GET)
public void user() {
userService.vaildUser();
}
}
访问 http://127.0.0.1:8081/user
结果
phone:手机号错误 name:名字错误



