---
# System prepended metadata

title: Intellij plugin
tags: [Spring boot]

---

## 創建 plugin 專案
* 左側選單選取IDE Plugin
![image](https://hackmd.io/_uploads/ryoe__lia.png)
## 各檔案說明
* [**resource/META-INF/plugin.xml**](https://juejin.cn/post/6930813959775715336) -> plugin的設定檔
    * id -> 這個plugin的唯一識別值(不能和其他的重複)
    * name -> plugin名稱(在搜索時會出現的名稱)
    * version -> 版本號
    * vender -> 開發者主頁&email
    * depends -> 依賴項
    * ==actions== -> 控制點選功能以後對應到的java class
        * id -> 唯一值
        * class -> 對應到的java(點選後要執行的java class)
        * text -> 顯示的名稱
        * description -> 描述
        * group-id -> plugin的功能鍵要顯示在哪裡
        * anchor -> 功能鍵位置
        * keyboard-shortcut -> 快捷鍵
        ``` xml
        <action id="tw.sc.demo2.Hello" class="tw.sc.demo2.Hello" text="Hello" description="show Hello">
            <add-to-group group-id="HelpMenu" anchor="first"/>
            <keyboard-shortcut keymap="$default" first-keystroke="meta alt ENTER"/>
        </action>
        ```
        ps. https://blog.csdn.net/justry_deng/article/details/121874359 此網址為基礎建置教學，實測後照做可以正常執行，==內含常用group-id==

* **main/java/自定義**
    * class 需要extends AnAction，並Override actionPerformed
        * actionPerformed為plugin功能鍵點選後的直行進入點
        * 以下程式碼為簡易的CreateGetController
        ```java
        public class CreateGetController extends AnAction {
            @Override
            public void actionPerformed(@NotNull AnActionEvent e) {
                Project project = e.getProject();
                if (project != null) {
                    // get editor
                    Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
                    if (editor != null) {
                        // insert code
                        WriteCommandAction.runWriteCommandAction(project, () -> {
                            int offset = editor.getCaretModel().getOffset();
                            String codeToInsert = generateControllerCode("get");
                            editor.getDocument().insertString(offset, codeToInsert);
                        });
                    }
                }
            }

            private String generateControllerCode(String type) {
                String controllerCode = "";
                switch(type){
                    case "get":
                    default:
                        controllerCode = "@GetMapping(value = \"/\", produces = \"application/json\")\n" +
                            "public BaseModel Controller() {\n" +
                            "   return new BaseModel();\n" +
                            "}";
                        break;
                    case "post":
                        controllerCode = "@PostMapping(value = \"/\", produces = \"application/json\")\n" +
                            "public BaseModel Controller() {\n" +
                            "   return new BaseModel();\n" +
                            "}";
                        break;
                }
                return controllerCode;
            }
        }
        ```

## swing
* swing創建，創建後會有兩個檔案(java & form)
![image](https://hackmd.io/_uploads/B1_tCuliT.png)
* form 檔用於拉介面，java檔跟介面相關的執行檔
* form拉的介面==要在對應的java中宣告==，且form中的field name要和宣告的變數名稱一樣
    :point_down: 拉一個JText
    ![image](https://hackmd.io/_uploads/rJFBkKgoa.png)
    :point_down: 左側的field name(form檔) ==要和宣告一樣==
    ![image](https://hackmd.io/_uploads/Hk_HJFxoa.png)
    :point_down: 宣告(java檔) ==要和field name一樣==
    ![image](https://hackmd.io/_uploads/r1urkKgs6.png)
* **java**
    * 要extends DialogWrapper，並Override createCenterPanel
    ``` java
    public class CreateControllerClassDialog extends DialogWrapper {
        @Override
        protected @Nullable JComponent createCenterPanel() {
           
        }
    }
    ```

## 實作範例
* 自動寫入getController
:point_down:  plugin.xml
``` xml
<group id="tw.sc.demo2.SCProd" text="_SCProd" description="SCProd">
    <add-to-group group-id="EditorPopupMenu" anchor="last"/>
    <action id="tw.sc.demo2.SCProd.CreateGetController" class="tw.sc.demo2.CreateGetController" text="CreateGetController" description="show Hello"/>

    <add-to-group group-id="EditorPopupMenu" anchor="last"/>
    <action id="tw.sc.demo2.Hello" class="tw.sc.demo2.Hello" text="Hello" description="show Hello">
        <add-to-group group-id="HelpMenu" anchor="first"/>
    </action>
</group>
```
![image](https://hackmd.io/_uploads/SkBAZFeo6.png)

:point_down: java
```java
public class CreateGetController extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        if (project != null) {
            // get editor
            Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
            if (editor != null) {
                // insert code
                WriteCommandAction.runWriteCommandAction(project, () -> {
                    int offset = editor.getCaretModel().getOffset();
                    String codeToInsert = generateControllerCode("get");
                    editor.getDocument().insertString(offset, codeToInsert);
                });
            }
        }
    }

    private String generateControllerCode(String type) {

        String controllerCode = "";
        switch(type){
            case "get":
            default:
                controllerCode = "@GetMapping(value = \"/\", produces = \"application/json\")\n" +
                        "public BaseModel Controller() {\n" +
                        "   return new BaseModel();\n" +
                        "}";
                break;
            case "post":
                controllerCode = "@PostMapping(value = \"/\", produces = \"application/json\")\n" +
                        "public BaseModel Controller() {\n" +
                        "   return new BaseModel();\n" +
                        "}";
                break;
        }
        return controllerCode;
    }
}
```

* 自動創建java file
:point_down: plugin.xml
```xml
<action id="CreatePsiJavaFile"
        class="tw.sc.demo2.action.CreateController"
        text="Create Controller File">
        <!-- 在 New 操作组的下面 -->
    <add-to-group group-id="ProjectViewPopupMenu" anchor="after" relative-to-action="WeighingNewGroup"/>
    <!--快捷鍵-->
<!-- <keyboard-shortcut keymap="$default" first-keystroke="meta alt ENTER"/>-->
</action>
```
:point_down: java
```java
public class CreateController extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        PsiElement psiElement =e.getData(CommonDataKeys.PSI_ELEMENT);
        PsiDirectory psiDirectory;
        if (psiElement instanceof PsiDirectory) {
            psiDirectory = (PsiDirectory) psiElement;
        } else {
            psiDirectory = psiElement.getContainingFile().getContainingDirectory();
        }

        new CreateControllerClassDialog(psiDirectory).show();
    }
}

```
:point_down: swing的java ==目前僅能新建一個java檔，但程式碼邏輯內包含新建class、constructor等，但尚未成功==
```java
public class CreateControllerClassDialog extends DialogWrapper {

    private final boolean createState;

    private Project myProject;
    private PsiDirectory myPsiDirectory;
    private JPanel mainPanel;
    private JLabel classNameLabel;
    private JTextField className;

    public CreateControllerClassDialog(@Nonnull PsiDirectory directory) {
        super(true);
        createState = true;
        setTitle("create.java.file");// 對話框標題
        myPsiDirectory = directory;
        myProject = myPsiDirectory.getProject();
        init();
    }


    @Override
    protected @Nullable JComponent createCenterPanel() {
        mainPanel = new JPanel(new BorderLayout());
        // 初始化
        classNameLabel = new JLabel("Class Name: ");
        className = new JTextField();

        // 把組件加到mainPanel
        mainPanel.add(classNameLabel, BorderLayout.WEST);
        mainPanel.add(className, BorderLayout.CENTER);
//        // 如果是 Class 展示添加 @Data 注解的???
//        types.addItemListener(l -> dataPane.setVisible(l.getItem().equals(ClassType.Class)));
        return mainPanel;
    }

    public String getClassName() {
        return className.getText();
    }

    @Override
    protected void doOKAction() {
        if (createState) {
            createJavaFile();
        } else {
//            editJavaFile();
        }
        // 關閉視窗
        super.doOKAction();
    }

    private void createJavaFile() {
        String classNameText = className.getText();
        // use WriteCommandAction to do not-read(create、edit、delete)
        WriteCommandAction.runWriteCommandAction(myProject, "create.java.file", "Psi", () -> {
            try {

                PsiFile javaFile = myPsiDirectory.createFile(classNameText + ".java");

                // 添加 PsiClass 到 PsiFile
                PsiClass psiClass = JavaDirectoryService.getInstance().createClass(myPsiDirectory, classNameText);

                // 在 PsiClass 中加入code
                addCodeToPsiClass(psiClass);

                javaFile.add(psiClass);

                // 添加 PsiFile 到 PsiDirectory
                myPsiDirectory.add(javaFile);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        });
    }

    private void addCodeToPsiClass(PsiClass psiClass) {
        String classCode = "public class MyClass {\n" +
                "    // 添加方法\n" +
                "    public void myMethod() {\n" +
                "        // Your code here\n" +
                "    }\n" +
                "\n" +
                "    // 添加constructor\n" +
                "    public MyClass() {\n" +
                "        // Your code here\n" +
                "    }\n" +
                "}\n";

        // 使用 PsiElementFactory 建 PsiClass
        PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
        PsiClass newClass = elementFactory.createClassFromText(classCode, null);

        // 取文件的大括號的位置
        PsiElement lBrace = psiClass.getLBrace();
        PsiElement rBrace = psiClass.getRBrace();

        // 新建的添加到文件的大括號中
        if (lBrace != null && rBrace != null) {
            psiClass.addBefore(newClass, rBrace);
        }
    }

    public enum ClassType {
        Class, Interface, Enum
    }
}
```
:point_down: swing的form
![image](https://hackmd.io/_uploads/BJm8NteoT.png)

## 參考資料
* https://zhuanlan.zhihu.com/p/400059601?utm_id=0 -> 內含github，實測過後可使用
* https://blog.csdn.net/justry_deng/article/details/121874359 -> 初步教學
* https://www.cnblogs.com/Jcloud/p/17510682.html -> 後半段是較為進階的教學
