idea插件,如何通过psi文件追加代码背景 为了提高插件的实用性,我们考虑加入代码的追加的功能,简单来讲,就是通过插件
背景
为了提高插件的实用性,我们考虑加入代码的追加的功能,简单来讲,就是通过插件,去生成controller和service的层级代码,避免我们为了创建层级去来回切换,同时也是强制保持代码的规范。
实践
我们考虑是在右键菜单中添加一个组件,进行控制 大概是这个效果 首先需要继承AnAction类,重写actionPerformed方法,控件触发的时候,会执行这个方法
public class GenerateMethodAction extends AnAction {
private final IProjectGenerator<MethodConfigVO> methodGenerator = new MethodGeneratorImpl();
@Override
public void actionPerformed(AnActionEvent event) {
Project project = event.getProject();
if (project == null) {
return;
}
PropertiesComponent instance = PropertiesComponent.getInstance(project);
String projectStruct = instance.getValue(CommonConstants.PROJECT_STRUCT_KEY);
MethodConfigVO methodConfigVO = JSONUtil.toBean(projectStruct, MethodConfigVO.class);
// 定义对话框,当前组件执行的时候进行显示
GenerateMethodDialog dialog = new GenerateMethodDialog(project);
}
}
然后就是获取psi文件,并追加代码。
Project project = event.getProject();
if (project == null) {
return;
}
// 获取LocalFileSystem实例
LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
// 将文件系统路径转换为VirtualFile
VirtualFile virtualFile = localFileSystem.findFileByPath(outputPath);
我们需要获取当前的项目和本地的文件系统,查找对应的路径的VirtualFile,VirtualFile是idea基于硬盘上的文件进行映射的,简单理解就是本地文件的一个引用。由于idea会不停的刷新VirtualFile,所以我们还需要调用virtualFile.isValid()方法,判断文件是否已经失效。
// 获取PsiElementFactory实例
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
// 获取PsiManager实例
PsiManager psiManager = PsiManager.getInstance(project);
// 获取导包列表
List<PsiImportStatement> psiImportStatements = buildImportStatement(factory, methodTemplate);
// 从VirtualFile获取PsiFile
PsiFile psiFile = psiManager.findFile(virtualFile);
然后在获取java的psi元素,用来获取引入的包列表,然后通过virtualFile获取到对应的psi文件,psi就是idea专门提供的用来简化解析代码文件操作的一个类。
if (psiFile instanceof PsiJavaFile) {
PsiClass psiClass = PsiTreeUtil.findChildOfType(psiFile, PsiClass.class, false);
if (psiClass != null) {
// 添加方法
boolean isInterface = PsiUtil.isJavaInterfaceFile(psiFile);
PsiMethod newMethod = buildPsiMethod(factory, psiClass, methodTemplate, isInterface);
psiClass.add(newMethod);
// 格式化新插入的代码
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
codeStyleManager.reformat(newMethod);
// 导包
PsiJavaFile psiJavaFile = (PsiJavaFile) psiClass.getContainingFile();
PsiImportList importList = psiJavaFile.getImportList();
List<String> existImports = Arrays.stream(importList.getImportStatements()).map(PsiImportStatement::getQualifiedName).collect(Collectors.toList());
for (PsiImportStatement importStatement : psiImportStatements) {
if (!existImports.contains(importStatement.getQualifiedName())) {
importList.add(importStatement);
}
}
}
}
获取对应的psiclass文件,构建新的方法,并添加到PsiClass中
private static PsiMethod buildPsiMethod(PsiElementFactory factory, PsiClass psiClass, MethodDTO methodTemplate, boolean isInterface) {
PsiType returnType = PsiType.VOID;
if (Objects.nonNull(methodTemplate.getReturnTypeClass())) {
returnType = factory.createTypeFromText(methodTemplate.getReturnType(), null);
}
// 创建新方法
PsiMethod newMethod = factory.createMethod(methodTemplate.getName(), returnType);
// 添加参数列表
addParametersToMethod(factory, newMethod, methodTemplate);
if (isInterface) {
newMethod = handleInterface(factory, newMethod);
} else {
if (StringUtils.isNotEmpty(methodTemplate.getApiName())) {
addApiAnnotationToMethod(factory, newMethod, methodTemplate.getApiName());
addApiBodyToMethod(factory, psiClass, newMethod, returnType, methodTemplate);
} else {
addOverrideToMethod(factory, newMethod);
addBodyToMethod(factory, psiClass, newMethod, returnType);
}
}
addCommentToMethod(factory, newMethod, methodTemplate);
return newMethod;
}
最后的效果
总结
想要基于idea去追加代码,首先需要知道对应的文件的项目路径,并且获取到对应的VirtualFile文件,通过VirtualFile获取到对应的psi文件,最后在psi文件中追加对应的方法即可。
转载自:https://juejin.cn/post/7411724375848861736