Java在线OJ项目(三)、前后端交互API模块

news2024/11/16 2:53:52

Java在线OJ项目(三)、前后端交互API模块

    • 1. 客户端向服务器请求所有题目 或者 单个题目
        • 前端
            • 获取所有题目
            • 获取一个题目
        • 后端
    • 2. 后端读取前端提交的代码,进行编译运行,返回结果
        • 前端提交代码
        • 后端处理

1. 客户端向服务器请求所有题目 或者 单个题目

前端:通过problem的URL地址访问(如果没有其它参数,则是查询所有题目,如果有id参数,就是查询具体题目)
后端:返回题目的具体详情
在这里插入图片描述在这里插入图片描述

前端

获取所有题目
        <script>
            // 在页面加载的时候, 尝试从服务器获取题目列表. 通过 ajax 的方式来进行获取
            function getProblems() {
                // 1. 先通过 ajax 从服务器获取到题目列表. 
                $.ajax({
                    url: "problem",
                    type: "GET",
                    success: function(data, status) {
                        // data 是响应的 body, status 是响应的状态码
                        // 2. 把得到的响应数据给构造成 HTML 片段
                        makeProblemTable(data);
                    }
                })
            }

            // 通过这个函数来把数据转换成 HTML 页面片段
            function makeProblemTable(data) {
                let problemTable = document.querySelector("#problemTable");
                for (let problem of data) {
                    let tr = document.createElement("tr");

                    let tdId = document.createElement("td");
                    tdId.innerHTML = problem.id;
                    tr.appendChild(tdId);

                    let tdTitle = document.createElement("td");
                    let a = document.createElement("a");
                    a.innerHTML = problem.title;
                    a.href = 'problemDetail.html?id=' + problem.id;
                    a.target = '_blank';
                    tdTitle.appendChild(a);
                    tr.appendChild(tdTitle);

                    let tdLevel = document.createElement("td");
                    tdLevel.innerHTML = problem.level;
                    tr.appendChild(tdLevel);

                    problemTable.appendChild(tr);
                }
            }

            getProblems();
        </script>
获取一个题目
<script>
            // 通过 ajax 从服务器获取到题目的详情
            function getProblem() {
                // 1. 通过 ajax 给服务器发送一个请求
                $.ajax({
                    url: "problem" + location.search,
                    type: "GET",
                    success: function (data, status) {
                        makeProblemDetail(data);
                    }
                })
            }

            function makeProblemDetail(problem) {
                // 1. 获取到 problemDesc, 把题目详情填写进去
                let problemDesc = document.querySelector("#problemDesc");

                let h3 = document.createElement("h3");
                h3.innerHTML = problem.id + "." + problem.title + "_" + problem.level
                problemDesc.appendChild(h3);

                let pre = document.createElement("pre");
                let p = document.createElement("p");
                p.innerHTML = problem.description;
                pre.appendChild(p);
                problemDesc.appendChild(pre);

                // 2. 把代码的模板填写到编辑框中. 
                // let codeEditor = document.querySelector("#codeEditor");
                // codeEditor.innerHTML = problem.templateCode;
                editor.setValue(problem.templateCode)
</script>

后端

package api;

import com.fasterxml.jackson.databind.ObjectMapper;
import dao.Problem;
import dao.ProblemDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/problem")
public class ProblemServlet extends HttpServlet {
    //ObjectMapper类(com.fasterxml.jackson.databind.ObjectMapper)是Jackson的主要类,它可以帮助我们快速的进行各个类型和Json类型的相互转换。
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置返回的状态码 200表示成功
        resp.setStatus(200);
        //返回的数据类型
        resp.setContentType("application/json;charset=utf8");

        ProblemDAO problemDAO = new ProblemDAO();
        // 尝试获取 id 参数. 如果能获取到, 说明是获取题目详情; 如果不能获取到, 说明是获取题目列表.
        String idString = req.getParameter("id");
        if (idString == null || "".equals(idString)) {
            // 没有获取到 id 字段. 查询题目列表
            List<Problem> problems = problemDAO.selectAll();
            String respString = objectMapper.writeValueAsString(problems);
            resp.getWriter().write(respString);
        } else {
            // 获取到了题目 id. 查询题目详情
            Problem problem = problemDAO.selectOne(Integer.parseInt(idString));
            String respString = objectMapper.writeValueAsString(problem);
            resp.getWriter().write(respString);
        }

    }
}

2. 后端读取前端提交的代码,进行编译运行,返回结果

在这里插入图片描述

前端提交代码

<script>
                // 3. 给提交按钮注册一个点击事件
                let submitButton = document.querySelector("#submitButton");
                submitButton.onclick = function () {
                    // 点击这个按钮, 就要进行提交. (把编辑框的内容给提交到服务器上)
                    let body = {
                        id: problem.id,
                        // code: codeEditor.value,
                        code: editor.getValue(),
                    };
                    $.ajax({
                        type: "POST",
                        url: "compile",
                        data: JSON.stringify(body),
                        success: function (data, status) {
                            let problemResult = document.querySelector("#problemResult");
                            if (data.error == 0) {
                                // 编译运行没有问题, 把 stdout 显示到页面中
                                problemResult.innerHTML = data.stdout;
                            } else {
                                // 编译运行没有问题, 把 reason 显示到页面中
                                problemResult.innerHTML = data.reason;
                            }
                        }
                    });
                }
            }

</script>

后端处理

package api;

import com.fasterxml.jackson.databind.ObjectMapper;
import common.CodeInValidException;
import common.ProblemNotFoundException;
import compile.Answer;
import compile.Question;
import compile.Task;
import dao.Problem;
import dao.ProblemDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

@WebServlet("/compile")
public class CompileServlet extends HttpServlet {
    static class CompileRequest {
        public int id;
        public String code;
    }

    static class CompileResponse {
        // 约定 error 为 0 表示编译运行 ok, error 为 1 表示编译出错, error 为 2 表示运行异常(用户提交的代码异常了), 3 表示其他错误
        public int error;
        public String reason;
        public String stdout;
    }

    private ObjectMapper objectMapper = new ObjectMapper();


//    {
//        "id": 2,
//        "code": "class Solution {\n    public int[] twoSum(int[] nums, int target) {\n        int[] a = {0, 1};\n        return a;\n    }\n}    "
//    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 临时加一下这个代码, 来获取到 SmartTomcat 的工作目录
        System.out.println("用户的当前工作目录: "+System.getProperty("user.dir"));

        CompileRequest compileRequest = null;
        CompileResponse compileResponse = new CompileResponse();
        try {
            resp.setStatus(200);
            resp.setContentType("application/json;charset=utf8");
            // 1. 先读取请求的正文. 别按照 JSON 格式进行解析
            String body = readBody(req);
            compileRequest = objectMapper.readValue(body, CompileRequest.class);
            // 2. 根据 id 从数据库中查找到题目的详情 => 得到测试用例代码
            ProblemDAO problemDAO = new ProblemDAO();
            Problem problem = problemDAO.selectOne(compileRequest.id);
            if (problem == null) {
                // 为了统一处理错误, 在这个地方抛出一个异常.
                throw new ProblemNotFoundException();
            }
            // testCode 是测试用例的代码
            String testCode = problem.getTestCode();
            // requestCode 是用户提交的代码
            String requestCode = compileRequest.code;
            // 3. 把用户提交的代码和测试用例代码, 给拼接成一个完整的代码.
            String finalCode = mergeCode(requestCode, testCode);
            if (finalCode == null) {
                throw new CodeInValidException();
            }
            // System.out.println(finalCode);
            // 4. 创建一个 Task 实例, 调用里面的 compileAndRun 来进行编译运行.
            Task task = new Task();
            Question question = new Question();
            question.setCode(finalCode);
            Answer answer = task.compileAndRun(question);
            // 5. 根据 Task 运行的结果, 包装成一个 HTTP 响应
            compileResponse.error = answer.getError();
            compileResponse.reason = answer.getReason();
            compileResponse.stdout = answer.getStdout();
        } catch (ProblemNotFoundException e) {
            // 处理题目没有找到的异常
            compileResponse.error = 3;
            compileResponse.reason = "没有找到指定的题目! id=" + compileRequest.id;
        } catch (CodeInValidException e) {
            compileResponse.error = 3;
            compileResponse.reason = "提交的代码不符合要求!";
        } finally {
            String respString = objectMapper.writeValueAsString(compileResponse);
            resp.getWriter().write(respString);
        }
    }

    private static String mergeCode(String requestCode, String testCode) {
        // 1. 查找 requestCode 中的最后一个 }
        int pos = requestCode.lastIndexOf("}");
        if (pos == -1) {
            // 说明提交的代码完全没有 } , 显然是非法的代码.
            return null;
        }
        // 2. 根据这个位置进行字符串截取
        String subStr = requestCode.substring(0, pos);
        // 3. 进行拼接
        return subStr + testCode + "\n}";
    }

    private static String readBody(HttpServletRequest req) throws UnsupportedEncodingException {
        // 1. 先根据 请求头 里面的 ContentLength 获取到 body 的长度(单位是字节)
        int contentLength = req.getContentLength();
        // 2. 按照这个长度准备好一个 byte[] .
        byte[] buffer = new byte[contentLength];
        // 3. 通过 req 里面的 getInputStream 方法, 获取到 body 的流对象.
        try (InputStream inputStream = req.getInputStream()) {
            // 4. 基于这个流对象, 读取内容, 然后把内容放到 byte[] 数组中即可.
            inputStream.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 5. 把这个 byte[] 的内容构造成一个 String
        return new String(buffer, "UTF8");
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/812229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【程序设计】一文讲解程序设计原则SOLDI

前言 设计原则&#xff0c;是指导我们如何设计出低耦合、高内聚的代码&#xff0c;让代码能够更好的应对变化&#xff0c;从而降本提效。 设计原则的关键&#xff0c;是从『使用方的角度』看『提供方』的设计&#xff0c;一句话概括就是&#xff1a;请不要要我知道太多&#…

VBA技术资料MF36:VBA_在Excel中排序

【分享成果&#xff0c;随喜正能量】一个人的气质&#xff0c;并不在容颜和身材&#xff0c;而是所经历过的往事&#xff0c;是内在留下的印迹&#xff0c;令人深沉而安谧。所以&#xff0c;优雅是一种阅历的凝聚&#xff1b;淡然是一段人生的沉淀。时间会让一颗灵魂&#xff0…

IO流(2)-缓冲流

1. 缓冲流的简单介绍 我们上贴说到了 FileInputStream&#xff0c;FileOutputStream&#xff0c;FileReader&#xff0c;FileWriter。 其实这四个流&#xff0c;我们通常把它叫做原始流&#xff0c;它们是比较偏底层的&#xff1b;而今天我们要说的四个缓冲流&#xff0c;如…

自己创建的类,其他类中使用错误

说明&#xff1a;自己创建的类&#xff0c;在其他类中创建&#xff0c;报下面的错误&#xff08;Cannot resolve sysmbol ‘Redishandler’&#xff09;&#xff1b; 解决&#xff1a;看下是不是漏掉了包名 加上包名&#xff0c;问题解决&#xff1b;

第9届Python编程挑战赛初中组初赛真题剖析-2023年全国青少年信息素养大赛

[导读]&#xff1a;超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲&#xff0c;这是超平老师解读Python编程挑战赛系列的第13讲。 全国青少年信息素养大赛&#xff08;原全国青少年电子信息智能创新大赛&#xff09;是“世界机器人大会青少年机器人设计与…

PyCharm安装pip依赖,如何添加国内镜像源?

目录 前言 PyCharm如何安装依赖 PyCharm如何配置国内镜像源 前言 首先我们都知道&#xff0c;使用pip安装依赖的方式&#xff0c;却很少有人知道使用PyCharm如何安装依赖。 PyCharm如何安装依赖 但你会发现&#xff0c;基本都是安装失败的&#xff0c;因为你是去外网下载的…

左神算法之中级提升班(8)

目录 【案例1】 【题目描述】 【思路解析】 【代码实现】 【案例2】 【题目描述】 【思路解析】 【代码实现】 【案例3】 【题目描述】 【思路解析】 【案例4】 【题目描述】 【思路解析】 【代码实现】 【案例5】 【题目描述】 【子序列概念】 【思路解析1 经典…

CTF-MISC:BUUCTF练习汇总(持续更新)

CTF-MISC&#xff1a;BUUCTF练习汇总 1、金三胖2、你竟然赶我走3、二维码4、大白 1、金三胖 解题思路&#xff1a; flag隐藏在gif图片帧中&#xff0c;使用在线GIF拆分工具即可 在线GIF图片帧拆分工具&#xff1a;https://uutool.cn/gif2img/ flag为&#xff1a;flag{he11oho…

应用层协议——https

文章目录 1. HTTPS 是什么2. 什么是"加密"3. 常见的加密方式4. 数据摘要 && 数字签名5. HTTPS 的工作过程探究5.1 方案1 - 只使用对称加密5.2 方案2 - 只使用非对称加密5.3 方案3 - 双方都使用非对称加密5.4 方案4 - 非对称加密 对称加密5.5 中间人攻击5.6 …

【MTI 6.S081 Lab】locks

【MTI 6.S081 Lab】locks Memory allocator (moderate)实验任务Hint解决方案 Buffer cache (hard)实验任务Hint解决方案数据结构设计初始化数据结构getrelse 本实验前去看《操作系统导论》第29章基于锁的并发数据结构&#xff0c;将会是很有帮助的。 在这个实验室中&#xff0…

懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒!

前言 系列首发gong zhong hao[『非同质前端札记』] &#xff0c;若不想错过更多精彩内容&#xff0c;请“星标”一下&#xff0c;敬请关注gong zhong hao最新消息。 懒得改变原始对象&#xff1f;JavaScript代理模式教你怎样一步步偷懒&#xff01; 何为代理模式 例如&#x…

倍增与ST算法

倍增与ST算法 倍增倍增原理倍增法的局限例题 &#xff1a;国旗计划 (洛谷 P4155)例题题解带注释的代码 ST算法ST算法原理ST算法步骤ST算法应用场合例题 &#xff1a;【模板】ST表 (洛谷 P3865) 倍增 倍增原理 倍增法的局限 例题 &#xff1a;国旗计划 (洛谷 P4155) 例题题解 带…

华为OD机试真题 Java 实现【报文回路】【2023 B卷 100分】,俗称“礼尚往来”

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路1、报文回路2、异常情况&#xff1a;3、解题思路 五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&…

《JavaSE-第二十章》之线程的创建与Thread类

文章目录 什么是进程&#xff1f;什么是线程&#xff1f;为什么需要线程&#xff1f; 基本的线程机制创建线程1.实现 Runnable 接口2.继承 Thread 类3.其他变形 Thread常见构造方法1. Thread()2. Thread(Runnable target)3. Thread(String name)4. Thread(Runnable target, Str…

epoll复用

cli #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>// 服务器ip #define IP "192.168.250.100" // 服务器端口 #define PORT 8888int main…

c++11 标准模板(STL)(std::basic_ifstream)(一)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_ifstream : public std::basic_istream<CharT, Traits> 类模板 basic_ifstream 实现文件流上的高层输入操作。它将 std::basic_istream…

Flink - souce算子

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 1. 从Java的集合中读取数据 2. 从本地文件中读取数据 3. 从HDFS中读取数据 4. 从Socket中读取数据 5. 从Kafka中读取数据 6. 自定义Source 官方文档 - Flink1.13 1. 从Java的集合中读取数据 …

二叉树(C语言)

文章目录 1.树1.1概念1.2相关定义1.3 表示&#xff08;左孩子右兄弟&#xff09; 2.二叉树2.1概念2.2特殊的二叉树1. 满二叉树&#xff1a;2. 完全二叉树&#xff1a; 2.3二叉树的性质2.4练习 3.二叉树的存储结构1. 顺序存储2. 链式存储 4.完全二叉树的代码实现4.1堆的介绍1.堆…

ssm德宏贸易项目java人资企业办公jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 ssm德宏贸易项目 系统有1权限&#xff1a;管理员 二…

接口自动化测试平台

下载了大神的EasyTest项目demo修改了下<https://testerhome.com/topics/12648 原地址>。也有看另一位大神的HttpRunnerManager<https://github.com/HttpRunner/HttpRunnerManager 原地址>&#xff0c;由于水平有限&#xff0c;感觉有点复杂~~~ 【整整200集】超超超…