代码编辑器
输出结果
等待代码执行...
Python实例题
题目
问题描述
解题思路
关键代码框架
模板文件示例
难点分析
扩展方向
基于 Flask 的在线代码编辑器
开发一个简单的在线代码编辑器,支持以下功能:
import os
import uuid
import subprocess
import tempfile
from flask import Flask, render_template, request, jsonify, redirect, url_for, session
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from flask_socketio import SocketIO, send, emit
# 配置
UPLOAD_FOLDER = 'projects'
ALLOWED_EXTENSIONS = {'py', 'js', 'html', 'css', 'java', 'c', 'cpp'}
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_FILE_SIZE
# 确保项目目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
# 初始化Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
# 初始化SocketIO
socketio = SocketIO(app)
# 用户模型
class User(UserMixin):
def __init__(self, id, username, password_hash):
self.id = id
self.username = username
self.password_hash = password_hash
def check_password(self, password):
return check_password_hash(self.password_hash, password)
# 模拟用户数据库
users = {}
# 用户加载回调
@login_manager.user_loader
def load_user(user_id):
return users.get(user_id)
# 辅助函数
def allowed_file(filename):
"""检查文件扩展名是否允许"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def get_project_dir(username):
"""获取用户项目目录"""
return os.path.join(UPLOAD_FOLDER, username)
def get_project_file_path(username, project_name, filename):
"""获取项目文件完整路径"""
return os.path.join(get_project_dir(username), project_name, filename)
def create_user(username, password):
"""创建新用户"""
user_id = str(uuid.uuid4())
password_hash = generate_password_hash(password)
user = User(user_id, username, password_hash)
users[user_id] = user
# 创建用户项目目录
os.makedirs(get_project_dir(username), exist_ok=True)
return user
def create_project(username, project_name):
"""创建新项目"""
project_dir = os.path.join(get_project_dir(username), project_name)
os.makedirs(project_dir, exist_ok=True)
return project_dir
def get_projects(username):
"""获取用户所有项目"""
user_dir = get_project_dir(username)
if not os.path.exists(user_dir):
return []
return [d for d in os.listdir(user_dir) if os.path.isdir(os.path.join(user_dir, d))]
def get_project_files(username, project_name):
"""获取项目所有文件"""
project_dir = os.path.join(get_project_dir(username), project_name)
if not os.path.exists(project_dir):
return []
return [f for f in os.listdir(project_dir) if os.path.isfile(os.path.join(project_dir, f))]
def read_file_content(file_path):
"""读取文件内容"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
return f"读取文件失败: {str(e)}"
def write_file_content(file_path, content):
"""写入文件内容"""
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
return True
except Exception as e:
print(f"写入文件失败: {str(e)}")
return False
# 路由
@app.route('/')
@login_required
def index():
"""主页"""
projects = get_projects(current_user.username)
return render_template('index.html', projects=projects)
@app.route('/register', methods=['GET', 'POST'])
def register():
"""注册页面"""
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# 检查用户名是否已存在
for user in users.values():
if user.username == username:
return render_template('register.html', error='用户名已存在')
# 创建新用户
user = create_user(username, password)
login_user(user)
return redirect(url_for('index'))
return render_template('register.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
"""登录页面"""
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# 查找用户
for user in users.values():
if user.username == username and user.check_password(password):
login_user(user)
return redirect(url_for('index'))
return render_template('login.html', error='用户名或密码错误')
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
"""登出"""
logout_user()
return redirect(url_for('login'))
@app.route('/project/create', methods=['POST'])
@login_required
def create_new_project():
"""创建新项目"""
project_name = request.form['project_name']
if not project_name:
return jsonify({'success': False, 'message': '项目名称不能为空'})
create_project(current_user.username, project_name)
return jsonify({'success': True, 'message': '项目创建成功'})
@app.route('/project/')
@login_required
def project_detail(project_name):
"""项目详情页"""
files = get_project_files(current_user.username, project_name)
return render_template('project.html', project_name=project_name, files=files)
@app.route('/file/create', methods=['POST'])
@login_required
def create_new_file():
"""创建新文件"""
project_name = request.form['project_name']
filename = request.form['filename']
if not allowed_file(filename):
return jsonify({'success': False, 'message': '不支持的文件类型'})
file_path = get_project_file_path(current_user.username, project_name, filename)
# 检查文件是否已存在
if os.path.exists(file_path):
return jsonify({'success': False, 'message': '文件已存在'})
# 创建文件
try:
with open(file_path, 'w') as f:
f.write('')
return jsonify({'success': True, 'message': '文件创建成功'})
except Exception as e:
return jsonify({'success': False, 'message': f'创建文件失败: {str(e)}'})
@app.route('/file//')
@login_required
def file_detail(project_name, filename):
"""文件详情页"""
file_path = get_project_file_path(current_user.username, project_name, filename)
content = read_file_content(file_path)
# 获取文件扩展名,用于CodeMirror模式
ext = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
# 映射文件扩展名到CodeMirror模式
mode_map = {
'py': 'python',
'js': 'javascript',
'html': 'htmlmixed',
'css': 'css',
'java': 'clike',
'c': 'clike',
'cpp': 'clike'
}
mode = mode_map.get(ext, 'text')
return render_template('editor.html', project_name=project_name,
filename=filename, content=content, mode=mode)
@app.route('/file/save', methods=['POST'])
@login_required
def save_file():
"""保存文件"""
project_name = request.form['project_name']
filename = request.form['filename']
content = request.form['content']
file_path = get_project_file_path(current_user.username, project_name, filename)
if write_file_content(file_path, content):
return jsonify({'success': True, 'message': '文件保存成功'})
else:
return jsonify({'success': False, 'message': '文件保存失败'})
# 代码执行路由
@app.route('/execute', methods=['POST'])
@login_required
def execute_code():
"""执行代码"""
code = request.json['code']
language = request.json['language']
# 创建临时文件
with tempfile.TemporaryDirectory() as temp_dir:
if language == 'python':
file_path = os.path.join(temp_dir, 'main.py')
with open(file_path, 'w', encoding='utf-8') as f:
f.write(code)
try:
# 执行Python代码
result = subprocess.run(
['python3', file_path],
capture_output=True,
text=True,
timeout=10 # 限制执行时间为10秒
)
output = result.stdout
error = result.stderr
return jsonify({
'success': True,
'output': output,
'error': error
})
except subprocess.TimeoutExpired:
return jsonify({
'success': False,
'error': '执行超时(超过10秒)'
})
except Exception as e:
return jsonify({
'success': False,
'error': f'执行错误: {str(e)}'
})
elif language == 'javascript':
file_path = os.path.join(temp_dir, 'main.js')
with open(file_path, 'w', encoding='utf-8') as f:
f.write(code)
try:
# 执行JavaScript代码
result = subprocess.run(
['node', file_path],
capture_output=True,
text=True,
timeout=10
)
output = result.stdout
error = result.stderr
return jsonify({
'success': True,
'output': output,
'error': error
})
except Exception as e:
return jsonify({
'success': False,
'error': f'执行错误: {str(e)}'
})
else:
return jsonify({
'success': False,
'error': f'暂不支持的语言: {language}'
})
# SocketIO事件处理
@socketio.on('connect')
def handle_connect():
"""客户端连接事件"""
print('客户端已连接')
emit('connected', {'data': '连接成功'})
@socketio.on('disconnect')
def handle_disconnect():
"""客户端断开连接事件"""
print('客户端已断开连接')
if __name__ == '__main__':
# 创建测试用户
if not users:
create_user('test', 'test123')
# 启动应用
socketio.run(app, debug=True)
{{ filename }} - 代码编辑器