在线编程网站开发教程:二、开发webcoding,实现在线编程
itomcoil 2024-12-23 11:08 40 浏览
一、准备工作
- 下载bootstrap,解压缩到statics目录下。
- 下载codemirror,解压缩到statics目录下。
- 在templates目录下创建webcoding,新建模板文件codit.html。
- ubuntu下apt命令安装docker、docker-compose。
- 下载JudgeServer,git clone https://github.com/QingdaoU/JudgeServer
二、简版在线编程网页前端
先上效果图:
在codit.html中利用<div>来布局,用<textarea>作为代码编辑窗口。在head部分,引入bootstrap4的css文件和js文件,同时引入jquery.js配合bootstrap使用的,通过样式来控制页面布局。div作为总的容器,内部包含若干行,每行分为12列,根据需要从左右分成几个部分,宽度由col-md-x中为个数字x(1<=x<=12)来分配。
表单放在第二行,左右各空1例,代码窗口占7列,语言选择、标准输入和提交按钮占3列,标准输出窗口在下方第三行。表单元素中定义了id和name,id是网页中js要使用的,name是提交表单到后端使用的。html代码如下:
<html>
<head>
<title> 在线程序编辑器 </title>
<link rel="stylesheet" href="/static/bootstrap4/css/bootstrap.css">
</head>
<script type="text/javascript" src="/static/bootstrap4/js/bootstrap.js"></script>
<script type="text/javascript" src="/static/bootstrap4/jquery.min.js"></script>
<body>
<br><br>
<div class='container'>
<div class='row' ><!--第一行-->
<div class='col-md-4'></div>
<div class='col-md-5'> <font size='7' > 在线编程简化版 </font></div>
<div class='col-md-3'></div>
</div>
<br>
<form id='frm_coding' method='POST'>
<div class='row'><!--第二行,表单-->
<div class='col-md-1'></div>
<div class='col-md-7'>
<textarea id='src_coding' name='src_coding' style='width:600px;height:450px;'> </textarea>
</div>
<div class='col-md-3'>
<select id='language' name='language'>
<option value='text/x-csrc'>c</option>
<option value='text/x-python' selected="selected">python</option>
<option value='text/x-c++src'>c++</option>
<option value='text/x-java'>java</option>
</select><br>
<font size='6' color='green'> input </font><br>
<textarea id='cin_coding' name='cin_coding' style='width:200px;height:300px;'></textarea>
<br><br>
<button class='btn btn-primary' id='sub_coding' type='button' onclick='up_data()'>调试运行</button>
</div>
<div class='col-md-1'></div>
</div>
</form>
<div class='row'><!--第三行,输出运行结果-->
<div class='col-md-1'></div>
<div class='col-md-10'>
<font size='6' color='green'> output </font><br><br>
<textarea id='cout_coding' name='cout_coding' style="border:1px solid gray;width:100%; height:150px;overflow-y:auto"></textarea>
</div>
<div class='col-md-1'></div>
</div>
</div>
</body>
</html>
表单提交采用了ajax局部提交,提交代码如下:
<script type="text/javascript">
function up_data(){
udata = $('#frm_coding').serializeArray();
$.ajax({
type: 'POST',
url: '/codej/',
data:JSON.stringify(udata),
contentType: 'application/json',
dataType: 'json',
success: function(data){
$("#cout_coding").text(data);
console.log(data);
},
error: function(data){
$("#cout_coding").text(data);
},
});
}
</script>
上述代码提交表单后,返回的信息更新到页面中最下面的cout_conding文本框中。有关ajax()详情参见https://www.cnblogs.com/tylerdonet/p/3520862.html 。
三、后端编译运行代码
在webcoding中的views.py中添加两个执行代码的视图:def codejudge(request): 及def codejudgeserver(request):,在almond中的urls.py中添加三个路由地址:
# webcoding的路由
path('codev/', codevelop, name='codev'),
path('codej/', codejudge, name='codej'),
path('codejs/', codejudgeserver, name='codejs'),
这里是把所有的路由放在主应用的urls.py文件中的,与大多数的django教程中不同 —— 在各自的应用中有urls.py文件放置各自应用的路由,在主应用的urls.py文件中包含其他应用的urls.py文件。
下面实现视图codejudge,前后端是采用json格式来传递数据的。下面代码有详细解释
#简化版 后端 代码编译 运行
def codejudge(request):
#首先获取表单数据udata,对数据整理一下放入字典x中
udata = json.loads(request.body)
print(udata)
x = dict()
for val in udata:
x[str(val['name'])] = val['value']
print(x)
result={}
#获取表单数据也可以用request.POST来,看情况定
#根据选用的语言组织不同的编译命令和运行命令
if x['language'] == 'text/x-csrc':
fsource = open('test.c','w')
fsource.write(x['src_coding'])
fsource.close()
fstdin = open('stdin.txt','w')
fstdin.write(x['cin_coding'])
fstdin.close()
compile_cmd ='gcc test.c -o test.so'
run_cmd='./test.so < stdin.txt'
elif x['language'] == 'text/x-c++src':
fsource = open('test.cpp','w')
fsource.write(x['src_coding'])
fsource.close()
fstdin = open('stdin.txt','w')
fstdin.write(x['cin_coding'])
fstdin.close()
compile_cmd ='g++ test.cpp -o test.so'
run_cmd='./test.so < stdin.txt'
elif x['language'] == 'text/x-java':
fsource = open('main.java','w')
fsource.write(x['src_coding'])
fsource.close()
fstdin = open('stdin.txt','w')
fstdin.write(x['cin_coding'])
fstdin.close()
compile_cmd ='javac main.java '
run_cmd='java main'
elif x['language'] == 'text/x-python':
fsource = open('test.py','w')
fsource.write(x['src_coding'])
fsource.close()
fstdin = open('stdin.txt','w')
fstdin.write(x['cin_coding'])
fstdin.close()
compile_cmd ='python -m py_compile test.py'
run_cmd='python __pycache__/test.cpython-310.pyc < stdin.txt'
#利用pyhon的子进程模块subprocess来编译和运行程序
out = err = ""
cominfo = subprocess.Popen(compile_cmd, shell=True,
stdin=subprocess.PIPE,stdout=subprocess.PIPE,
stderr=subprocess.PIPE,universal_newlines=True)
#等子进程编译程序结束,并获取信息
out, err = cominfo.communicate()
if err :
#编译出错,返回出错信息
print("compile err:",err)
result = err
else:
#编译通过,运行编译之后的字节码 或 可执行文件
runinfo = subprocess.Popen(run_cmd, shell=True,
stdin=subprocess.PIPE,stdout=subprocess.PIPE,
stderr=subprocess.PIPE,universal_newlines=True)
err = out = ""
#等子进程运行结束,并获取运行结果信息
out, err = runinfo.communicate()
if err :
print('run error',err)
result = err
else:
result = out
return JsonResponse(result,safe=False)
若编译有语法错误,就返回错误信息到前端;编译通过再运行程序,返回相应信息。信息采用json格式传递。
这里有一个重要问题是当提交的代码有死循环等有害代码时会对服务器的运行造成不利。接下来用到沙盒来隔离运行代码,并通过服务来向前端提供编译运行环境,避免并发造成服务器的阻塞。
四、使用OnlineJudgeServer运行代码
准备工作:onlinejudge是开源的编程在线测评系统,由四个模块组成。这里用到其中Judger和JudgeServer,git clone https://github.com/QingdaoU/JudgeServer 下载到本地,当前目录会有JudgeServer目录,进入其中,复制cp ./docker-compose.example.yml ./docker-compose.yml。这是基于docker来布署的,你的系统要安装docker、docker-compose。使用命令docker-compose up -d,根据docker-compose.yml文件的内容来布署,第一次运行会下载docker镜像并运行容器,以后会随系统一起启动。使用命令docker ps可以查询已经运行的docker容器。
wuxc@wubuntu:~$ docker ps -f id=b4b5 --format "{{.ID}} {{.Image}} {{.Names}} "
b4b53a76634c wuxc/judgeserver:1.0.1 judgeserver_judge_server_1
这是我修改JudgeServer目录下的Dockerfile文件,docker build .来创建自己的JudgeServer镜像,再修改docker-compose.yml相应部分。这样可以使用编译软件的新版本及增加其他的编程语言。有关docker 的更多知识请查阅相关资料。
如何使用:准备语言配置和调用方法,放在文件judge.py中供视图webcoding.codejudgeserer视图调用,部分内容如下
#语言配置
py3_lang_config = {
"compile": {
"src_name": "solution.py",
"exe_name": "__pycache__/solution.cpython-38.pyc",
"max_cpu_time": 3000,
"max_real_time": 5000,
"max_memory": 128 * 1024 * 1024,
"compile_command": "/usr/bin/python3 -m py_compile {src_path}",
},
"run": {
"command": "/usr/bin/python3 {exe_path}",
"seccomp_rule": "general",
"env": ["PYTHONIOENCODING=UTF-8"] + default_env
}
}
其他语言类似。定义一个调用服务的类,
class JudgeClient(object):
def __init__(self, token, server_base_url):
self.token = hashlib.sha256(token.encode("utf-8")).hexdigest()
self.server_base_url = server_base_url.rstrip("/")
def _request(self, url, data=None):
kwargs = {"headers": {"X-Judge-Server-Token": self.token,
"Content-Type": "application/json"}}
if data:
kwargs["data"] = json.dumps(data)
try:
return requests.post(url, **kwargs).json()
except Exception as e:
raise JudgeError(str(e))
def ping(self):
return self._request(self.server_base_url + "/ping")
def judge(self, src, language_config, max_cpu_time, max_memory, test_case_id=None, test_case=None, spj_version=None,
spj_config=None,
spj_compile_config=None, spj_src=None, output=False):
if not (test_case or test_case_id) or (test_case and test_case_id):
raise ValueError("invalid parameter")
......
这个类准备了一些参数,通过方法judge()来调用服务执行代码。judge.py根据JudgeServer目录下的client/Python下的几个文件整理而来的。 接下来看看webcoding下的视图函数codejudgeserver():
#沙盒代码编译执行代码
def codejudgeserver(request):
#获取表单提交数据
........
#根据表单数据选择 语言配置
if x['language'] == "x-src-python":
lang_config = py3_lang_config
......
src = x['src_coding']
stdinput = x['cin_coding']
#调用JudgeServer,token值要与docker镜像中一致
token = "YOUR_TOKEN_HERE"
client = JudgeClient(token=token, server_base_url="http://127.0.0.1:12357")
#测试与JudgeServer接连良好
print("ping")
print(client.ping(), "\n\n")
#执行代码,返回结果,指定cpu memory最大值
result = client.judge(src=src, language_config=lang_config,
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
test_case=[{"input": stdinput, "output": ""}], output=True)
if result['err'] != None:
y = result
else:
rusd = dict(result['data'][0])
print(rusd)
y = result['data'][0]['output']+'\n'
for k,v in rusd.items():
if k in ['cpu_time','memory','real_time']:
y += k+";"+str(v)+" "
print(y)
return JsonResponse(y, safe=False)
通过设置max_cpu_time和max_memory的值终止有害代码的无限运行。test_case测试用例中仅用于stdinput输入,不用output对比。对输出的评判后续介绍,这里能利用JudgeServer来编译和运行程序就行了。
五、用codemirror作代码编辑器
CodeMirror是一款在线的功能齐全的代码编辑器,提供了很多流行语言的代码高亮、自动缩进功能和符号匹配等功能。在模板codit.html中作些调整,下面两个是使用 CodeMirror 必须引入的两个主文件
<!-- 引入codemirror -->
<link rel="stylesheet" href="/static/codemirror/lib/codemirror.css">
<script type="text/javascript" src="/static/codemirror/lib/codemirror.js"></script>
实现当前行背景高亮和括号匹配功能引入下列文件:
<script type="text/javascript" src="/static/codemirror/addon/selection/active-line.js"></script>
<script type="text/javascript" src="/static/codemirror/addon/edit/matchbrackets.js"></script>
实现某语言语法高亮显示功能引入下列文件:
<script type="text/javascript" src="/static/codemirror/mode/clike/clike.js"></script>
<script type="text/javascript" src="/static/codemirror/mode/python/python.js"></script>
clike.js 实现了c,c++,java三个语言的语法高亮显示功能。
实现编辑器的主题样式功能引入下列文件:
<link rel="stylesheet" href="/static/codemirror/theme/monokai.css">
<link rel="stylesheet" href="/static/codemirror/theme/twilight.css">
引入两个样式,可以切换使用。
实现快捷键功能引入下列文件:
<script type="text/javascript" src="/static/codemirror/keymap/sublime.js"></script>
在模板文件templates/webcoding/codit.hml的head中添加以上各行代码,再于up_data()函数的第一行加入:$('#src_coding').val(editor.getValue()),意思是把codemirror的编辑器editor中的代码给表单元素id值为src_coding的文本框,以便提交。
在up_data()函数的之后,添加函数modechange(value),作用是在选择编程语言时切换相应的语法高亮。
function modechange(value){
//alert(value);
txt = editor.getValue();
editor.setOption("mode", value);
editor.setValue(txt);
}
在模板文件codit.html最后加入定义设置editor的代码:
<script>
// Script for the editor.
var editor = CodeMirror.fromTextArea(document.getElementById("src_coding"), {
styleActiveLine: true,
lineNumbers: true,
lineWrapping: true,
mode: 'text/x-python',
keyMap: "sublime",
autoCloseBrackets: true,
matchBrackets: true,
showCursorWhenSelecting: true,
theme: "monokai",
tabSize: 4,
indentUnit: 4,
smartIndent: true,
});
//editor.setCursor(0);
editor.setSize('auto', '480px');
</script>
大功告成,看看运行效果。
相关推荐
- selenium(WEB自动化工具)
-
定义解释Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8,9,10,11),MozillaF...
- 开发利器丨如何使用ELK设计微服务中的日志收集方案?
-
【摘要】微服务各个组件的相关实践会涉及到工具,本文将会介绍微服务日常开发的一些利器,这些工具帮助我们构建更加健壮的微服务系统,并帮助排查解决微服务系统中的问题与性能瓶颈等。我们将重点介绍微服务架构中...
- 高并发系统设计:应对每秒数万QPS的架构策略
-
当面试官问及"如何应对每秒几万QPS(QueriesPerSecond)"时,大概率是想知道你对高并发系统设计的理解有多少。本文将深入探讨从基础设施到应用层面的解决方案。01、理解...
- 2025 年每个 JavaScript 开发者都应该了解的功能
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.Iteratorhelpers开发者...
- JavaScript Array 对象
-
Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...
- Gemini 2.5编程全球霸榜,谷歌重回AI王座,神秘模型曝光,奥特曼迎战
-
刚刚,Gemini2.5Pro编程登顶,6美元性价比碾压Claude3.7Sonnet。不仅如此,谷歌还暗藏着更强的编程模型Dragontail,这次是要彻底翻盘了。谷歌,彻底打了一场漂亮的翻...
- 动力节点最新JavaScript教程(高级篇),深入学习JavaScript
-
JavaScript是一种运行在浏览器中的解释型编程语言,它的解释器被称为JavaScript引擎,是浏览器的一部分,JavaScript广泛用于浏览器客户端编程,通常JavaScript脚本是通过嵌...
- 一文看懂Kiro,其 Spec工作流秒杀Cursor,可移植至Claude Code
-
当Cursor的“即兴编程”开始拖累项目质量,AWS新晋IDEKiro以Spec工作流打出“先规范后编码”的系统工程思维:需求-设计-任务三件套一次生成,文档与代码同步落地,复杂项目不...
- 「晚安·好梦」努力只能及格,拼命才能优秀
-
欢迎光临,浏览之前点击上面的音乐放松一下心情吧!喜欢的话给小编一个关注呀!Effortscanonlypass,anddesperatelycanbeexcellent.努力只能及格...
- JavaScript 中 some 与 every 方法的区别是什么?
-
大家好,很高兴又见面了,我是姜茶的编程笔记,我们一起学习前端相关领域技术,共同进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力在JavaScript中,Array.protot...
- 10个高效的Python爬虫框架,你用过几个?
-
小型爬虫需求,requests库+bs4库就能解决;大型爬虫数据,尤其涉及异步抓取、内容管理及后续扩展等功能时,就需要用到爬虫框架了。下面介绍了10个爬虫框架,大家可以学习使用!1.Scrapysc...
- 12个高效的Python爬虫框架,你用过几个?
-
实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫,为什么呢?因为Python确实很适合做爬虫,丰富的第三方库十分强大,简单几行代码便可实...
- pip3 install pyspider报错问题解决
-
运行如下命令报错:>>>pip3installpyspider观察上面的报错问题,需要安装pycurl。是到这个网址:http://www.lfd.uci.edu/~gohlke...
- PySpider框架的使用
-
PysiderPysider是一个国人用Python编写的、带有强大的WebUI的网络爬虫系统,它支持多种数据库、任务监控、项目管理、结果查看、URL去重等强大的功能。安装pip3inst...
- 「机器学习」神经网络的激活函数、并通过python实现激活函数
-
神经网络的激活函数、并通过python实现whatis激活函数感知机的网络结构如下:左图中,偏置b没有被画出来,如果要表示出b,可以像右图那样做。用数学式来表示感知机:上面这个数学式子可以被改写:...
- 一周热门
- 最近发表
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)