vue-codemirror + Java Compiler實現Java Web IDE
阿新 • • 發佈:2020-05-23
# 背景
>最近同事告訴我一個很有趣的需求:讓使用者(應用場景中,一般為其他開發者)自己填入**Java程式碼片段**,程式碼片段的內容為已經規定好的模板類的**繼承類**,實現模板類定義的方法。我們的專案要實現動態編譯程式碼片段,儲存程式碼片段和使用者操作記錄的對映關係,並能夠在業務中載入程式碼片段執行。
這有點像我們提供一個模板模式的架構,只不過模板類的實現類由外部介面填入程式碼片段動態實現。相較讓其他開發者直接參與專案開發,無疑:
1. 降低了侵入風險
2. 向其他開發者隱藏了大部分實現
3. 降低操作難度和開發門檻
4. 便於管理
……
這相當於要實現一個簡單的線上Java開發環境,提供基礎的程式碼填寫、編譯和儲存的功能。
# 效果演示
![切換主題](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy82ODEwNjIwLTAzMWUyOTZkYWMyNWQ1YzQuZ2lm)
![聯動填寫類名](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy82ODEwNjIwLTMwNGZkZjM2NGQ4NzEzYTIuZ2lm)
![測試編譯](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy82ODEwNjIwLWZkNDI3Y2ZlMTg3MjMxZTkuZ2lm)
基於`vue-codemirror`和`Java Compiler`的動態編譯,實現了上述需求,目前完成的Web端IDE主要功能點包括:
- 頁面展示Java程式碼塊(程式碼高亮,有行號、可自動補全括號等)
- 從服務端獲取模板類程式碼,並提供示例
- 實時動態編譯並獲取編譯結果(通過/失敗 todo:返回編譯錯誤資訊)
- 將輸入字串載入成Java Class
以及小的功能點:自動縮排、補全括號、切換主題、聯動填寫類名等等。
下面給出涉及到的技術和實現方法。
---
# CodeMirror
CodeMirror是一個JS庫,可以支援實現有豐富的附加功能和多種語言支援。我們專案的前端使用Vue框架,可以很方便地整合並使用CodeMirror提供的外掛,實現我們的線上IDE多種特性。
參考:[CodeMirror官網](https://codemirror.net/)
## 引入
安裝依賴:` "vue-codemirror": "^4.0.6"`
在`src`目錄下的`main.js`中引入:
```javascript
import VueCodeMirror from 'vue-codemirror'
import 'codemirror/lib/codemirror.css'
Vue.use(VueCodeMirror)
```
## 使用
新建元件`JavaIDE.vue`
```vue
```
元件化地使用它,我們可以方便地操作它繫結的值(code)和其他附加選項(cmOption)。
在元件建立時為code賦值,即可實現載入模板程式碼。
> 根據官網,我們可以直接使用CodeMirror的預設建構函式,也可以提供一個`textarea DOM`元素作為構造CodeMirror物件的引數。
可以使用`readOnly`引數將程式碼塊設定為只讀。
### 聯動填寫類名功能
希望實現:在上面頂欄中填寫類名,在程式碼中聯動填寫。
實現方式: 使用正則匹配替換程式碼片段,再進行替換
使用相同的方法,也可以實現動態補全類名等功能
>參考更多[JavaScript的正則表示式](https://www.runoob.com/js/js-regexp.html)
為輸入框加上監聽函式`@input="changeClassName"`
```javascript
changeClassName(className) {
var reg = new RegExp(/public class .*? extends ActionParamBuilder/);
this.code = this.code.replace(reg,
"public class " + className + " extends ActionParamBuilder"
);
}
```
### 切換主題
引入主題`css`樣式檔案
```
import "codemirror/theme/eclipse.css";
import "codemirror/theme/darcula.css";
import "codemirror/theme/blackboard.css";
```
使用String陣列定義支援的主題,並使用 `Element-UI`提供的`Select`元件支援主題切換:
```
```
* 使用`slot`實現在選擇器中嵌入圖示,並支援`tooltip`功能,使工具欄更加緊湊。 `slot`意為插槽,是封裝好的元件預留的可以自定義的空間,我們可以使用`slot = ""`把DOM元素置入到元件內部,非常靈活。
### 樣式覆寫
使用`!important`關鍵字覆蓋原有CodeMirror樣式。注意,將該樣式放在全域性而不是區域性`scoped`樣式表中。
```
.CodeMirror {
height: 500px !important;
}
```
# JavaCompiler
不用將傳入的程式碼儲存成`.java`檔案寫入磁碟,直接就可以使用`JavaCompiler`工具對字串進行編譯。
> 為了實現實時動態編譯功能,我搜索了關於如何將字串編譯成class的方法,還看了一些動態代理的實現思路。後來看到這一篇:[
Java執行時動態生成class的方法](https://www.liaoxuefeng.com/article/1080190250181920),發現這就是我想要的!
使用Java SDK(since 1.6)提供的JavaCompiler工具。該工具提供編譯方法:
```java
CompilationTask getTask(Writer out,
JavaFileManager fileManager,
DiagnosticListener diagnosticListener,