Go to file
Himit_ZH 9e6b88ee1a 文档修改 2021-02-24 17:42:14 +08:00
hoj-springboot 完善测试比赛相关接口,验证权限及数据计算 2021-02-24 01:08:47 +08:00
hoj-vue 完善测试比赛相关接口,验证权限及数据计算 2021-02-24 01:08:47 +08:00
judger 文档修改 2021-02-24 17:32:05 +08:00
sqlAndsetting 文档修改 2021-02-24 17:42:14 +08:00
README.md 文档修改 2021-02-24 17:42:14 +08:00

README.md

一、介绍

基于前后端分离分布式架构的在线测评平台hoj

  • 前端:
    • 技术以Vue为主element-ui为主要框架网站风格样式模仿qdoj
    • 支持手机端,响应式布局
    • 以CodeMirror作为在线代码编辑器
    • 以Mavon-Editor作为富文本编辑器
    • 支持用户头像上传可选择性获取用户Codeforces分数
    • 定时获取例如Codeforces等其它知名OJ的近期比赛数据
    • 当前支持HDU的Virtual Judge远程虚拟判题与题目获取
    • 题目支持特别判题
    • 题目支持可选择性去除提交代码的末尾空白符会影响CE判定
    • 题目支持可选择性允许用户查看各个测试点结果状态运行时间运行空间OI题目的测试点得分暂不支持测试点数据公开。
    • 管理后台支持题目数据以ZIP上传或手动输入上传
    • 管理后台支持监控服务系统的状态及各判题服务的状态
    • 管理后台支持动态修改网站配置,例如邮件系统配置,数据库配置等
    • 比赛支持封榜支持ACM与OI模式
    • 比赛支持私有赛(需要密码才可查看与提交),保护赛(每个用户都可查看,提交需要密码),公开赛(每个用户都可查看与提交)三种模式
    • 用户提交失败时可重新提交,管理员支持提交重判与比赛题目所有提交重判
    • ......
  • 后端:
    • Web框架技术以Springboot为主
    • 以Nacos为分布式注册中心及分布式配置中心支持配置文件动态刷新支持判题服务Ribbon的负载均衡
    • 以Mybatis-Plus为数据库中间件负责数据实体类与数据库数据的转化与获取。
    • 以Jsoup为爬虫框架负责远程虚拟OJ的题目获取及提交结果获取同时定时获取各用户的Codeforces分数以及其它知名OJ的近期比赛。
    • 以Shiro为安全框架支持用户角色权限管理支持token刷新
    • 以redis的发布订阅者作为判题服务的消息提醒以此调用判题服务
    • 后端分为数据后台服务DataBackup及判题服务JudgeServer
      1. 数据后台服务:负责提供接口,提供相关数据给前端等
      2. 判题服务只负责获取数据后台服务传输过来的判题的提交调用VJ判题或调用判题机Go-Judge进行评测将对应结果写回数据库
  • 判题机:
    • 支持HDU的VJ判题
    • 支持Codefoces的VJ判题
    • 以HttpAPI的形式调用Go-Jugde(高性能可复用的判题沙盒)判题安全沙盒进行提交程序的评测(调用线程池多线程跑评测)
  • 数据库
    • Mysql
  • 缓存中间件
    • Redis

当前任务

  • 测试HDU判题整套流程
  • 修改前端编辑器样式以及md格式转换
  • 修复代码编辑器bug
  • 测试比赛相关接口,验证权限及数据计算
  • 增加codeforce的vj判题
  • 部署判题服务器到云服务器半正式上线HOJ
  • 完善文档

开发记录

时间 更新内容 更新者
2020-10-26 数据库设计,登录和注册接口,文档记录开始。 Himit_ZH
2020-10-28 用户模块接口,题目模块接口,比赛模块接口,排行模块接口 Himit_ZH
2020-10-30 评测模块接口判题服务系统初始化前端vue项目 Himit_ZH
2020-11-08 前端vue主页题目列表页登录注册重置密码弹窗逻辑 Himit_ZH
2020-11-16 前端提交列表页,提交详情页,题目详情页,排行(ACM,OI)页,比赛列表页,个人主页,个人设置页 Himit_ZH
2020-11-22 前端比赛首页,比赛题目列表,比赛排行榜,比赛公告,首页布局调整 Himit_ZH
2020-11-24 介绍页,导航栏移动端优化,首页优化,公告栏优化 Himit_ZH
2020-11-28 前端项目重构,加入管理端部分页面,增加case表 Himit_ZH
2020-12-01 前端管理端基本完成,准备开始前后端接口对接与测试 Himit_ZH
2020-12-21 管理端前后端接口对接基本完成,准备客户端接口对接 Himit_ZH
2021-01-04 客户端首页,题目,提交模块的接口对接完毕 Himit_ZH
2021-01-08 比赛列表页,排行榜,用户主页的接口对接完毕 Himit_ZH
2021-01-11 个人设置页,用户信息更新,头像上传,登录优化 Himit_ZH、Howie
2021-01-16 比赛首页比赛题目列表比赛题目详情等接口对接完毕定时爬取其它oj比赛及rating分完成 Himit_ZH、Howie
2021-01-19 比赛排行榜比赛题目对应提交重判比赛AC助手完成 Himit_ZH
2021-02-02 正式加入安全沙箱,判题机服务器 Himit_ZH
2021-02-04 完善判题机制加入pe可选择性判断加入测试点可选择性公开 Himit_ZH
2021-02-08 完善判题服务调度机制(负载均衡策略),完善题目评测数据上传与下载 Himit_ZH
2021-02-12 初始化构建HDU虚拟判题流程 Howie、Himit_ZH
2021-02-16 完善测试特殊判题题目的操作 Himit_ZH
2021-02-19 正式完善HDU虚拟判题以及题目添加 Himit_ZH
2021-02-20 测试HDU判题整套流程完成 Himit_ZH
2021-02-22 修改前端编辑器样式以及md格式转换 Himit_ZH
2021-02-24 完善测试比赛相关接口,验证权限及数据计算 Himit_ZH

二、系统架构

总概四大系统

  1. 前端vue页面显示系统

  2. 数据交互后台系统

  3. 判题服务系统

  4. 爬虫系统

判题逻辑概述

  1. 前端用户提交数据。
  2. 后端数据服务DataBackup获取到数据先将提交数据初始化同时将该提交的状态变成等待中写入数据库。
  3. 通过Redis的发布订阅者将该判题信息发送给对应的==等待判题频道订阅者==
  4. 订阅者收到信息初始化传输数据使用springcloud alibaba通过nacos注册中心调用判题微服务。
  5. 若是调用判题服务失败(没有空闲的判题服务器),则重新通过发布者将该提交信息发布到对应==等待判题频道==重回3。
  6. 若是调用失败超过40次则将提交的状态修改为提交失败不再进行判题服务的调用。
  7. 前端用户可看到提交变成提交失败可点击状态进行重新提交重回2重新提交不影响提交时间等数据
  8. 判题微服务获取到提交数据:
    • 若是远程调用则通过Redis的发布订者发布到对应的==远程判题等待提交频道==,对应==频道接收者==获取提交信息进行远程提交获取对应的提交ID再通过==远程判题等待结果频道===发布给对应频道接收者,该频道接收者接受到信息,进行结果获取,获取结果失败,则再次重复发布;获取成功,写回数据库。
    • 若是自家题目提交则启用线程池多线程使用Http将对应测试点数据与代码提交给Go-Judge判题沙盒进行编译与评测最后获取各个评测点结果进行结果计算写回数据库。

HOJ基本逻辑架构图

image-20201030234527577

springcloud alibaba 分布式微服务架构图

Consumer后台数据交互服务

Provider判题服务

Nacos注册中心Consumer通过nacos调用Provider

spingcloud-Alibaba.png

三、网站部分截图

hoj1

hoj2

hoj3

hoj4

hoj5

hoj6

hojmb1

hojmb2

#四、特判程序例子

#include<iostream>
#include<cstdio>
#define AC 100
#define WA 101
#define ERROR 102
using namespace std;


int spj(int user_output, FILE *output);

void close_file(FILE *f){
    if(f != NULL){
        fclose(f);
    }
}

int main(int argc, char *args[]){
    FILE *output;
    int result;
    if(argc != 2){
        return ERROR;
    }
    int user_output;
    cin>>user_output;
    cout<<user_output<<endl;
    output = fopen(args[1], "r");
	
    result = spj(user_output, output);
    printf("result: %d\n", result);
    
    close_file(output);
    return result;
}

int spj(int user_output, FILE *output){
    /*
      parameter: 
        - output标程输出文件的指针
        - user_output用户输出数据
      return: 
        - 如果用户答案正确返回AC
        - 如果用户答案错误返回WA
        - 如果主动捕获到自己的错误如内存分配失败返回ERROR
      */
      int std_out;
      while(fscanf(output, "%d", &std_out) != EOF){
          if(user_output+1 != std_out){
             cout<<user_output<<endl<<std_out;
              return WA;
          }
      }
      return AC;
}

五、附加:

数据库表内容及API文档

Go-Sanbox API文档

go-judge