https://www.w3cschool.cn/intellij_idea_doc/
JDK要求必须11以上,我这里使用的是17。
下载JDK17
https://www.oracle.com/cn/java/technologies/downloads/#jdk17-windows
安装后确认下版本
java --version
环境变量中的JAVA_HOME
也要设置为JDK17的路径。
创建项目
项目打开后点击plugin.xml配置插件的基本信息
如下
<idea-plugin>
<id>cn.psvmc.VueComp</id>
<name>VueComp</name>
<vendor email="183518918@qq.com" url="https://www.psvmc.cn">码客说</vendor>
<description><![CDATA[
方便生成Vue页面模板.<br>
<em>支持TS+Less+组合式API</em>
<em>模板、脚本和样式分离</em>
]]></description>
<depends>com.intellij.modules.platform</depends>
<extensions defaultExtensionNs="com.intellij">
</extensions>
<actions>
<action id="cn.psvmc.vuecomp.CreateVueCompAction"
class="cn.psvmc.vuecomp.CreateVueCompAction"
text="创建Vue组件/页面">
<add-to-group group-id="NewGroup" anchor="first"/>
<!-- 可通过 ctrl + H 快捷键触发 -->
<keyboard-shortcut keymap="$default" first-keystroke="ctrl H"/>
</action>
</actions>
</idea-plugin>
报错
Could not resolve org.jetbrains.intellij.plugins:gradle-intellij-plugin:1.8.0
环境变量中的JAVA_HOME
也要设置为JDK17的路径。
这里我们只是简单的在右下角弹出通知显示项目根目录
CreateVueCompAction.java
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
public class CreateVueCompAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
Notifications.Bus.notify(new Notification("Print", "", e.getProject().getBasePath(), NotificationType.INFORMATION), e.getProject());
}
}
当然也可以弹窗显示
Messages.showMessageDialog(e.getProject().getBasePath(), "Project BasePath", Messages.getInformationIcon());
在plugin.xml的根节点下添加
<actions>
<action id="cn.psvmc.vuecomp.CreateVueCompAction"
class="cn.psvmc.vuecomp.CreateVueCompAction"
text="创建Vue组件/页面">
<add-to-group group-id="NewGroup" anchor="first"/>
<!-- 可通过 ctrl + H 快捷键触发 -->
<keyboard-shortcut keymap="$default" first-keystroke="ctrl H"/>
</action>
</actions>
也可以在代码文件夹上点击鼠标右键,选择 New
=> Plugin DevKit
=> Action
如果没有的话,那么可能需要在先在IDEA中装个 Plugin DevKit插件。
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.ArrayList;
import java.util.List;
public class CreateVueCompAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
if (project == null) {
Messages.showMessageDialog("No project found", "Error", Messages.getErrorIcon());
return;
}
VirtualFile[] files = e.getData(com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE_ARRAY);
if (files == null || files.length == 0) {
Messages.showMessageDialog("No file selected", "Error", Messages.getErrorIcon());
return;
}
List<String> folderPathList = new ArrayList<>();
for (VirtualFile file : files) {
if (file.isDirectory()) {
folderPathList.add(file.getPath());
}
}
String folderPaths= String.join("\n", folderPathList);
Messages.showMessageDialog(folderPaths, "选择的文件夹", Messages.getInformationIcon());
}
}
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import java.io.IOException;
public class CreateVueCompAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
ApplicationManager.getApplication().runWriteAction(() -> {
Project project = e.getProject();
if (project == null) {
return;
}
VirtualFile[] files = e.getData(com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE_ARRAY);
if (files == null || files.length == 0) {
Messages.showMessageDialog("未选择文件夹!", "错误", Messages.getErrorIcon());
return;
}
for (VirtualFile file : files) {
if (file.isDirectory()) {
try {
String fileName = "main.txt";
VirtualFile newFile = file.findChild(fileName);
if (newFile == null) {
newFile = file.createChildData(this, fileName);
String content = "Hello, World!";
VirtualFile finalNewFile = newFile;
WriteAction.run(() -> {
finalNewFile.setBinaryContent(content.getBytes());
});
}
} catch (IOException ignored) {
}
}
}
VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
});
}
}
import cn.psvmc.vuecomp.utils.ZFreeMarkerUtils;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CreateVueCompAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
ApplicationManager.getApplication().runWriteAction(() -> {
Project project = e.getProject();
if (project == null) {
return;
}
VirtualFile[] files = e.getData(com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE_ARRAY);
if (files == null || files.length == 0) {
Messages.showMessageDialog("未选择文件夹!", "错误", Messages.getErrorIcon());
return;
}
for (VirtualFile file : files) {
if (file.isDirectory()) {
String fileName = file.getName();
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("fileName", fileName);
List<Map<String, String>> templateList = new ArrayList<>();
Map<String, String> templateMap = new HashMap<>();
templateMap.put("templateName", "ts_vue.ftl");
templateMap.put("fileNameAll", fileName + ".vue");
templateList.add(templateMap);
Map<String, String> styleMap = new HashMap<>();
styleMap.put("templateName", "style.ftl");
styleMap.put("fileNameAll", fileName + ".less");
templateList.add(styleMap);
for (Map<String, String> item : templateList) {
try {
String fileNameAll = item.get("fileNameAll");
String templateName = item.get("templateName");
VirtualFile newFile = file.findChild(fileNameAll);
if (newFile == null) {
newFile = file.createChildData(this, fileNameAll);
String content = ZFreeMarkerUtils.getStrByFtl(templateName, dataModel);
VirtualFile finalNewFile = newFile;
WriteAction.run(() -> {
finalNewFile.setBinaryContent(content.getBytes());
});
} else {
Notification notice = new Notification("Print", "", "文件已存在", NotificationType.INFORMATION);
Notifications.Bus.notify(notice, e.getProject());
}
} catch (IOException ignored) {
}
}
}
}
VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
});
}
}
对应的模板文件
ts_vue.ftl
<template>
<div class="${fileName}">
{{ loginName }}
</div>
</template>
<script lang="ts" setup>
import {ref} from "vue";
const loginName = ref(null)
</script>
<style src="./${fileName}.less" lang="less" scoped>
</style>
style.ftl
.${fileName} {
}
使用的时候,先创建我们的组件文件夹,比如MainView,右键点击创建Vue组件/页面
,就会在这个文件夹中创建跟文件夹同名的两个文件。
Gradle中通过Tasks/build/build
来打包我们的插件。
构建好后我们可以在build/distributions
目录下面找到我们的zip包,拿到后直接在idea上面进行离线安装即可。
注意
网上有说用
intellij/buildPlugin
打包,这是不对的,这样打的是Jar包,我们代码中引用的模板文件不会打进去,就不能正常使用。
build.gradle.kts
plugins {
id("java")
id("org.jetbrains.intellij") version "1.8.0"
}
group = "cn.psvmc"
version = "1.0-SNAPSHOT"
repositories {
maven("https://maven.aliyun.com/repository/central")
maven("https://maven.aliyun.com/repository/public")
maven ("https://maven.aliyun.com/repository/gradle-plugin")
maven ("https://maven.aliyun.com/repository/apache-snapshots")
mavenCentral()
gradlePluginPortal()
mavenCentral()
}
// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
version.set("2021.3.3")
type.set("IC") // Target IDE Platform
plugins.set(listOf(/* Plugin Dependencies */))
}
tasks {
// Set the JVM compatibility versions
withType<JavaCompile> {
options.encoding = "UTF-8"
sourceCompatibility = "11"
targetCompatibility = "11"
}
patchPluginXml {
sinceBuild.set("213")
untilBuild.set("223.*")
}
}
注意相比于自动生成项目的配置,这里更改了如下几点:
repositories {
maven("https://maven.aliyun.com/repository/central")
maven("https://maven.aliyun.com/repository/public")
maven ("https://maven.aliyun.com/repository/gradle-plugin")
maven ("https://maven.aliyun.com/repository/apache-snapshots")
mavenCentral()
gradlePluginPortal()
mavenCentral()
}
要设置编码,否则中文会乱码。
withType<JavaCompile> {
options.encoding = "UTF-8"
sourceCompatibility = "11"
targetCompatibility = "11"
}
项目本身也设置为UTF-8
intellij
中的version.set("2021.3.3")
和patchPluginXml中的sinceBuild.set("213")
要匹配。
这是我们插件支持的最低IDEA版本
运行的时候会自动下载该版本的IDEA来运行我们的插件。
这个版本可以在IDEA的 Help
=> About
查看
还有这个版本要和对应IDEA依赖的Java版本一致,可以和我们插件项目依赖的Java版本不一致,我就是用的JDK17,而这里配置的11,可以正常编译运行。
withType<JavaCompile> {
sourceCompatibility = "11"
targetCompatibility = "11"
}
默认的7.5我在构建的时候报错,所以就更换为7.6版本了。
gradle-wrapper.properties
#Wed Mar 20 15:45:42 HKT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
镜像地址
https://mirrors.cloud.tencent.com/gradle/
Caused by: java.lang.NullPointerException: getHeaderField(“Location”) must not be null
这个错误不影响。
build.gradle.kts中添加
dependencies {
implementation("org.freemarker:freemarker:2.3.31")
}
resources/templates/template.ftl
# This is an example template
Hello, ${name}!
工具类
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class ZFreeMarkerUtils {
public static String getStrByFtl(String templateName,Map<String, Object> dataModel) {
try {
// 配置 Freemarker
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(ZFreeMarkerUtils.class, "/templates");
Template template = cfg.getTemplate(templateName);
try (StringWriter out = new StringWriter()) {
template.process(dataModel, out);
String result = out.toString();
System.out.println(result);
return result;
} catch (TemplateException e) {
return "";
}
} catch (IOException ex) {
return "";
}
}
public static void test(){
// 创建数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("name", "World");
getStrByFtl("template.ftl",dataModel);
}
}