如何在SpringBoot+Vue的项目中实现在线代码编译及执行(支持编译运行C、C++、Java),研究了一天,真实能用,下面直接上源码!!!
——————————————————————————————————————————
一、后端(直接接收字符串进行代码编译)
(1)C编译执行方法(直接调用,传入字符串即可完成编译)
package complier.complier_c;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import complier.util.FileUtil;
/**
* C编译器
* @author tpw
*
*/
public class CComplier {
private final static String CplusplusFILEPATH=System.getProperty("user.dir") + "\\cCode\\";
private final static String CplusplusFILENAME="main.c";
private final static String CplusplusEXE="main.exe";
private String inputData; //输入数据
private String outputData; //输出数据
private String errorMsg; //程序错误信息
public CComplier() {
this.inputData="";
this.errorMsg="";
}
public CComplier(String inputData) {
super();
this.inputData = inputData;
this.errorMsg="";
}
public CComplier(String inputData, String outputData, String errorMsg) {
super();
this.inputData = inputData;
this.outputData = outputData;
this.errorMsg = errorMsg;
}
public void complier() {
// 这里调用执行写入工具类,其他两个好像没写,这里给出个demo
FileUtil.writeFile(inputData,CplusplusFILEPATH+CplusplusFILENAME);
// 进入c代码存放文件夹
// 使用gcc命令来编译c文件,来生成一个exe文件
// 直接运行exe文件
// cmd命令:cd /d d:\javaworkspace\complier\cCode
// cmd命令:gcc main.cpp
// cmd命令:main.exe
StringBuffer errorInfo = new StringBuffer();
Process p=null;
try {
//1.编译C++文件
p = Runtime.getRuntime().exec("gcc "+CplusplusFILEPATH+CplusplusFILENAME+" -o "+CplusplusFILEPATH+"main");
// 获取进程的错误流
final InputStream is1 = p.getErrorStream();
// 开一个线程,读标准错误流
new Thread() {
public void run() {
try {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1,Charset.forName("GBK")));
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null) {
errorInfo.append(line1 + "\n");
}
}
if(!errorInfo.toString().equals("")) {
errorMsg=errorInfo.toString();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
p.waitFor();
p.destroy();
//2.如果没错的话就运行exe文件
if (errorInfo.toString().equals("")) {
try {
Process process = Runtime.getRuntime().exec(CplusplusFILEPATH+CplusplusEXE);
BufferedWriter bout = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bout.write(this.inputData);
bout.close();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(),Charset.forName("GBK")));
String line = null;
StringBuffer b = new StringBuffer();
while ((line = br.readLine()) != null) {
b.append(line + "\n");
}
this.outputData=b.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
try {
p.getErrorStream().close();
p.getInputStream().close();
p.getOutputStream().close();
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
public String getInputData() {
return inputData;
}
public void setInputData(String inputData) {
this.inputData = inputData;
}
public String getOutputData() {
return outputData;
}
public void setOutputData(String outputData) {
this.outputData = outputData;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
(2)C++编译执行方法(直接调用,传入字符串即可完成编译)
package complier.complier_cplusplus;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
/**
* C++编译器
* @author tpw
*
*/
public class CplusplusComplier {
private final static String CplusplusFILEPATH=System.getProperty("user.dir") + "\\c++Code\\";
private final static String CplusplusFILENAME="main.cpp";
private final static String CplusplusEXE="main.exe";
private String inputData; //输入数据
private String outputData; //输出数据
private String errorMsg; //程序错误信息
public CplusplusComplier() {
this.inputData="";
this.errorMsg="";
}
public CplusplusComplier(String inputData) {
super();
this.inputData = inputData;
this.errorMsg="";
}
public CplusplusComplier(String inputData, String outputData, String errorMsg) {
super();
this.inputData = inputData;
this.outputData = outputData;
this.errorMsg = errorMsg;
}
public void complier() {
// 进入c++代码存放文件夹
// 使用g++命令来编译c++文件,来生成一个exe文件
// 直接运行exe文件
// cmd命令:cd /d d:\javaworkspace\complier\c++Code
// cmd命令:g++ main.cpp
// cmd命令:main.exe
StringBuffer errorInfo = new StringBuffer();
Process p=null;
try {
//1.编译C++文件
p = Runtime.getRuntime().exec("g++ "+CplusplusFILEPATH+CplusplusFILENAME+" -o "+CplusplusFILEPATH+"main");
// 获取进程的错误流
final InputStream is1 = p.getErrorStream();
// 开一个线程,读标准错误流
new Thread() {
public void run() {
try {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1,Charset.forName("GBK")));
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null) {
errorInfo.append(line1 + "\n");
}
}
if(!errorInfo.toString().equals("")) {
errorMsg=errorInfo.toString();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
p.waitFor();
p.destroy();
//2.如果没错的话就运行exe文件
if (errorInfo.toString().equals("")) {
try {
Process process = Runtime.getRuntime().exec(CplusplusFILEPATH+CplusplusEXE);
BufferedWriter bout = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bout.write(this.inputData);
bout.close();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(),Charset.forName("GBK")));
String line = null;
StringBuffer b = new StringBuffer();
while ((line = br.readLine()) != null) {
b.append(line + "\n");
}
this.outputData=b.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
try {
p.getErrorStream().close();
p.getInputStream().close();
p.getOutputStream().close();
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
public String getInputData() {
return inputData;
}
public void setInputData(String inputData) {
this.inputData = inputData;
}
public String getOutputData() {
return outputData;
}
public void setOutputData(String outputData) {
this.outputData = outputData;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
(3)Java编译执行方法(直接调用,传入字符串即可完成编译)
package complier.complier_java;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
/**
* java编译器
* @author tpw
*
*/
public class JavaComplier {
private final static String jAVAFILEPATH=System.getProperty("user.dir") + "\\javaCode";
private final static String JAVAFILENAME="Main.java";
private final static String jAVAFILECLASNAME="Main";
private String inputData; //输入数据
private String outputData; //输出数据
private String errorMsg; //程序错误信息
public JavaComplier() {
this.inputData="";
this.errorMsg="";
}
public JavaComplier(String inputData) {
super();
this.inputData = inputData;
this.errorMsg="";
}
public JavaComplier(String inputData, String outputData, String errorMsg) {
super();
this.inputData = inputData;
this.outputData = outputData;
this.errorMsg = errorMsg;
}
public void complier() {
// 进入java代码存放文件夹
// 使用javac命令来编译java文件,来生成一个class文件
// 使用java命令来运行类
// cmd命令:cd /d d:\javaworkspace\complier\javaCode
// cmd命令:javac Main.java
// cmd命令:java Main
StringBuffer errorInfo = new StringBuffer();
Process p=null;
try {
//1.编译java文件
p = Runtime.getRuntime().exec("javac "+JAVAFILENAME, null, new File(jAVAFILEPATH));
// 获取进程的错误流
final InputStream is1 = p.getErrorStream();
// 开一个线程,读标准错误流
new Thread() {
public void run() {
try {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1,Charset.forName("GBK")));
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null) {
errorInfo.append(line1 + "\n");
}
}
if(!errorInfo.toString().equals("")) {
errorMsg=errorInfo.toString();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
p.waitFor();
p.destroy();
//2.如果没错的话就运行java文件
if (errorInfo.toString().equals("")) {
try {
Process process = Runtime.getRuntime().exec("java "+jAVAFILECLASNAME, null, new File(jAVAFILEPATH));
BufferedWriter bout = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bout.write(this.inputData);
bout.close();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(),Charset.forName("GBK")));
String line = null;
StringBuffer b = new StringBuffer();
while ((line = br.readLine()) != null) {
b.append(line + "\n");
}
this.outputData=b.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
try {
p.getErrorStream().close();
p.getInputStream().close();
p.getOutputStream().close();
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
public String getInputData() {
return inputData;
}
public void setInputData(String inputData) {
this.inputData = inputData;
}
public String getOutputData() {
return outputData;
}
public void setOutputData(String outputData) {
this.outputData = outputData;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
(4)字符串写入工具类(直接调用,传入字符串即可完成写入)
package complier.util;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class FileUtil {
public static void writeFile(String content,String filePath) {
try {
BufferedWriter out = new BufferedWriter(new FileWriter(filePath));
out.write(content);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(5)测试调用Demo
package complier.complier_java;
public class Test {
public static void main(String[] args) {
// 这里调用的Java编译,其他类同
JavaComplier javaComplier=new JavaComplier("Hello!!");
javaComplier.complier();
String proError=javaComplier.getErrorMsg();
if(!proError.equals("")) {
System.err.println(proError);
}else {
System.out.println(javaComplier.getOutputData());
}
}
}
二、前端(输入字符串,简单的直接输入框,复杂点就用ACE插件或者其他,此案例使用的ACE)
js引入方式可以采取以下方式,推荐本地下载包引入:
在线js引入举例(这两个是可以用的):
<script src="http://cdn.bootcss.com/ace/1.2.4/ace.js"></script>
<script src="http://cdn.bootcss.com/ace/1.2.4/ext-language_tools.js"></script>
本地js引入举例:
<script src="/codemirror/src-noconflict/ace.js"></script>
<template>
<div class="Ace">
<div class="code_tool_bar">
<span style="position: relative;left: 10px; top: 16px; font-size: 18px;">这个要比我写的样式要好(复制别人的)</span>
<el-button icon="el-icon-s-tools" @click="dialogTableVisible = true" style="float: right;margin: 10px;"></el-button>
<el-button icon="el-icon-refresh" @click="refresh_code" style="float: right; margin: 10px;"></el-button>
<el-select v-model="selectLanguageValue" @change="changSelectValue1" filterable style="float: right;margin: 10px;">
<el-option
v-for="item in languagesOptions"
:key="item.label"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-dialog :visible.sync="dialogTableVisible"
:append-to-body="true"
top="40px"
width="39.194%"
:destroy-on-close="true"
:show-close="false"
custom-class="code-editor-config-dialog">
<el-card style="margin: -59px -20px 0 -20px;"
shadow="never">
<div slot="header" class="clearfix">
<span>代码编辑器设置</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="dialogTableVisible = false">x</el-button>
</div>
<div class="row">
<el-row>
<el-col :span="16">
<div class="code-editor-option-title">主题</div>
<div class="code-editor-option-description">对白色界面感到厌倦了吗?可以尝试其他的背景和代码高亮风格。</div>
</el-col>
<el-col :span="8">
<el-select v-model="selectThemeValue"
@change="changSelectValue"
filterable>
<el-option
v-for="item in themesOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
<hr>
</div>
<div class="row">
<el-row>
<el-col :span="16">
<div class="code-editor-option-title">编辑类型</div>
<div class="code-editor-option-description">更喜欢Vim或者Emacs的输入方式吗?我们也为你提供了这些选项。</div>
</el-col>
<el-col :span="8">
<el-select v-model="selectEditorValue"
@change="setEditorMode"
filterable>
<el-option
v-for="item in editorOption"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
<hr>
</div>
<div class="row">
<el-row>
<el-col :span="16">
<div class="code-editor-option-title">缩进长度</div>
<div class="code-editor-option-description">选择代码缩进的长度。默认是4个空格。</div>
</el-col>
<el-col :span="8">
<el-select v-model="selectTabValue"
@change="setTabSize"
filterable>
<el-option
v-for="item in tabOption"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
<hr>
</div>
<div class="row">
<el-row>
<el-col :span="16">
<div class="code-editor-option-title">主题</div>
<div class="code-editor-option-description">对白色界面感到厌倦了吗?可以尝试其他的背景和代码高亮风格。</div>
</el-col>
<el-col :span="8">
<el-select v-model="selectThemeValue"
@change="changSelectValue"
filterable>
<el-option
v-for="item in themesOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
</el-row>
</div>
</el-card>
<el-button @click="dialogTableVisible = false" style="margin: 20px 480px -12px 480px">确 定</el-button>
</el-dialog>
</div>
<div ref="ace" class="ace"></div>
<el-button class="submitBtn" round type="success" ><i class="fa fa-cloud-upload" aria-hidden="true"></i>提交代码</el-button>
<el-button class="debuggerBtn" round @click="debuggerCode" ><i class="fa fa-play-circle-o" aria-hidden="true"></i>调试代码</el-button>
</div>
</template>
<script>
import ace from 'ace-builds'
import 'ace-builds/webpack-resolver'; // 在 webpack 环境中使用必须要导入
//解决添加提示时控制台警告(提示必须引入的包)
import "ace-builds/src-noconflict/ext-language_tools"
import "ace-builds/src-noconflict/ext-emmet"
//语言提示
import 'ace-builds/src-noconflict/snippets/javascript'
import 'ace-builds/src-noconflict/snippets/c_cpp'
import 'ace-builds/src-noconflict/snippets/java'
import 'ace-builds/src-noconflict/snippets/golang'
import 'ace-builds/src-noconflict/snippets/python'
//输入类型
import 'ace-builds/src-noconflict/keybinding-emacs'
import 'ace-builds/src-noconflict/keybinding-vim'
import 'ace-builds/src-noconflict/keybinding-vscode'
export default {
name: 'CodeEditor',
props: {
value: {
type: String,
required: true
}
},
methods: {
changSelectValue(value) {
this.aceEditor.setTheme(`ace/theme/${value}`);
},
refresh_code() {
this.aceEditor.session.setValue('');
},
changSelectValue1(value) {
this.aceEditor.session.setMode(`ace/mode/${value}`);
},
debuggerCode() {
let value = this.aceEditor.session.getValue();
console.log(value);
},
setTabSize(size) {
this.aceEditor.session.setTabSize(size);
},
setEditorMode(value) {
this.aceEditor.setKeyboardHandler(`ace/keyboard/${value}`);
}
},
data() {
return {
dialogTableVisible: false,
themeValue: 'ambiance',
aceEditor: null,
themePath: 'ace/theme/monokai', // 不导入 webpack-resolver,该模块路径会报错
modePath: 'ace/mode/c_cpp', // 同上
codeValue: this.value || '',
editorOption:[{
value: 'vscode',
label: 'Standard'
},{
value: 'vim',
label: 'Vim'
},{
value: 'emacs',
label: 'Emacs'
}],
selectEditorValue: 'Standard',
tabOption:[{
value: '2',
label: '2个空格'
},{
value: '4',
label: '4个空格'
},{
value: '6',
label: '6个空格'
}],
selectTabValue: '4个空格',
themesOptions: [{
value: 'crimson_editor',
label: 'CrimsonEditor'
},{
value: 'monokai',
label: 'Monokai'
},{
value: 'terminal',
label: 'Terminal'
},{
value: 'xcode',
label: 'Xcode'
}],
selectThemeValue: 'Monokai',
languagesOptions: [{
value: 'c_cpp',
label: 'C++'
},{
value: 'c_cpp',
label: 'C'
},{
value: 'java',
label: 'Java'
},{
value: 'golang',
label: 'Golang'
},{
value: 'python',
label: 'Python'
},{
value: 'javascript',
label: 'Javascript'
}],
selectLanguageValue: 'C++'
};
},
mounted() {
this.aceEditor = ace.edit(this.$refs.ace,{
maxLines: 1000, // 最大行数,超过会自动出现滚动条
minLines: 22, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
fontSize: 14, // 编辑器内字体大小
theme: this.themePath, // 默认设置的主题
mode: this.modePath, // 默认设置的语言模式
tabSize: 4, // 制表符设置为 4 个空格大小
readOnly: false, //只读
highlightActiveLine: true,
value: this.codeValue
});
this.aceEditor.setOptions({
enableSnippets: true,
enableLiveAutocompletion: true,
enableBasicAutocompletion: true
});
// 快捷键
// this.aceEditor.commands.addCommand({
// name: 'myCommand',
// bindKey: {win: 'Ctrl-M', mac: 'Command-M'},
// exec: function(editor) {
// //...
// },
// readOnly: true // false if this command should not apply in readOnly mode
// });
},
watch: {
value(newVal) {
console.log(newVal);
this.aceEditor.setValue(newVal);
}
}
};
</script>
<style scoped lang="scss">
.code_tool_bar {
height: 60px;
width: 100%;
background: #f8f9fa;
border: 1px solid #c2c7d0;
margin-bottom: 0;
}
.code-editor-option-title {
font-size: 17px;
margin-bottom: 10px;
}
.code-editor-option-description {
font-size: 13px;
color: grey;
}
hr {
background: none !important;
height: 1px !important;
border: 0 !important;
border-top: 1px solid #eee !important;
margin-top: 20px;
margin-bottom: 20px;
}
.ace {
position: relative !important;
border: 1px solid lightgray;
margin: auto;
height: auto;
width: 100%;
}
.debuggerBtn {
float: right;
margin: 13px 20px 0 0;
}
.submitBtn {
float: right;
margin: 13px 0 0 0;
}
</style>
效果截图 :
三、编译执行代码还需要在项目的src同级目录下创建对应的编译文件夹,用于接收字符串写入并执行。下面放出目录截图,直接用记事本创建并更改扩展名即可,文件里面的内容都是空的。
四、此项目总体截图
输入代码(C):
代码执行结果: