在上一篇中我们讲到了将日志保存到数据库,有点遗憾的地方是方法的中文名字得在
Log2DB
和ApiOperation
中写两次,有点不人性化。今天我们就来解决这个问题。
如果只能写一次,那我们只能改自己的代码读取ApiOperation
中的value
属性(因为swagger
是不会改代码适配你d的),那如果要读取别人的属性,有什么方法呢?
- 继承
- 扫描ApiOperation
我们看下RestController的注解,其实是继承了Controller注解的
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller//就在这里继承的
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
但是注解的继承依赖如下一个因素:
- 首先要想
Annotation
能被继承,需要在注解定义的时候加上@Inherited
,并且如果要被反射应用的话,还需要@Retention(RetentionPolicy.RUNTIME)
标识 - JDK文档中说明的是:只有在类上应用
Annotation
才能被继承,而实际应用结果是:除了类上应用的Annotation
能被继承外,没有被重写的方法的Annotation
也能被继承; - 当方法被重写后,
Annotation
不会被继承 Annotation
的继承不能应用在接口上
遗憾的是ApiOperation不符合条件,那我们就只剩下第二个方法了。
第二个我们要解决几个问题
1、怎么扫描读取ApiOperation所有的配置
2、用什么key存储关系
先解决第一个,我们可以在工程启动的时候获取所有的ApiOperation
,如下
@Slf4j
@Component
public class ApisScaner {
@Resource
private ApplicationContextProvider applicationContextProvider;
//key是全类名.方法名,value是ApiOperation的name属性
public static Map<String,String> APIS = new HashMap<String,String>();
@PostConstruct
public void handler() throws ClassNotFoundException {
log.info("SwaggerScaner.handler");
ApplicationContext applicationContext = applicationContextProvider.getApplicationContext();
//获取自定义注解的配置
final Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Api.class);
for (String key : beansWithAnnotation.keySet()) {
Method[] methods = Class.forName(beansWithAnnotation.get(key).getClass().getName()).getMethods();
for (Method method : methods) {
ApiOperation annotation = AnnotationUtils.findAnnotation(method, ApiOperation.class);
if(annotation!=null){
String value = annotation.value();
String className = beansWithAnnotation.get(key).toString();
String methodName = method.getName();
className = className.substring(0,className.indexOf("@"));
APIS.put(className+"."+methodName,value);
}
}
}
for (String item : APIS.keySet()) {
log.info("item:{}-->value:{}",item, APIS.get(item));
}
}
}
ApplicationContextProvider
(动态获取spring的bean对象)的源码也贴下:
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
/**
* 上下文对象实例
*/
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextProvider.applicationContext = applicationContext;
}
/**
* 获取Spring上下文
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通过name获取Bean
*
* @param name
* @return
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通过class获取Bean
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过name,以及Clazz返回指定的Bean
*
* @param name
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
好了,看了代码大伙基本也明白了,用什么存储,我暂时是用map存储的,大家可以写到数据库中,也可以用redis,mongodb,随意。启动一下试试:
SwaggerScaner.handler
item:com.example.lesson20.controller.TestController.getUser-->value:获取用户1
item:com.example.lesson20.controller.TestController.postUser-->value:保存用户1
数据我们都拿到了,改下上一节的一个小点即可:
//name = logAnnotation.name();
name = ApisScaner.APIS.get(clazz_method);
这样我们就搞定了,so easy!
LGKK233LV3
兄弟对BeanPostProcessor和BeanFactory有没有研究🥹