业务背景
对于所有请求,如果请求涉及对业务资源进行增删改,需要记录审计日志。在代码中使用@Log注解实现,添加到controller对应的mapping方法上,即可在接收到对应请求时上报审计日志。
但是没有防呆机制,可能出现新开发接口时,忘记审计日志这回事,导致漏报情况。
需求:写自动化防护,校验controller的非getMapping方法有@Log注解,同时,部分非getMapping方法如果没有修改资源,不涉及日志上报,提供排除方法
代码实现
先定义一个注解,用于指定该方法可以不用上报审计日志
@Target(ElementType.METHOD)
@interface NoLog{
String reason();
}
写DT
@Test
void LogTest{
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotionTypeFilter(RestController.class));
Set<String> res = new HashSet();
Set<BeanDefinition> beans = provider.findCandidateComponents("com.test");
Set<Class<?>> controllers = new HashSet();
for (BeanDefinition beanDefinition : beans) {
controllers.add(Class.forName(beanDefinition.getBeanClassName()));
}
for (Class<?> clazz : controllers) {
String methodPrefix = clazz.getName + ".";
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(NoLog.class)) {
continue;
}
if (isNotGetMappingMethod(method)) {
if (!method.isAnnotationPresent(Log.class)) {
res.add(methodPrefix + method.getName());
}
}
}
}
assertThat(res).isEmpty();
}
boolean isNotGetMappingMethod(Method method) {
if (method.isAnnotationPresent(DeleteMapping.class) ||
method.isAnnotationPresent(PostMapping.class) ||
method.isAnnotationPresent(PutMapping.class) ||
method.isAnnotationPresent(PatchMapping.class)
) {
return true;
}
if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping annotation = method.getAnnotation(RequestMapping.class);
RequestMethod[] types = annotation.method();
for (RequestMethod type : types) {
if (RequestMethod.DELETE == type ||
RequestMethod.POST == type ||
RequestMethod.PUT == type ||
RequestMethod.PATCH == type
) {
return true;
}
}
}
return false;
}