JavaWeb 项目 --- 在线 OJ 平台 (三)

1. 设计网页页面

在这里插入图片描述

1.1 列表页

只是大概模板

在这里插入图片描述

1.2 详情页

只是大概模板

在这里插入图片描述

2. 设计网页的前后端交互接口

在这里插入图片描述

约定交互1: 获取题目的列表

在这里插入图片描述

约定交互2: 获取指定题目的详情信息

在这里插入图片描述

约定交互3: 向服务器提交编写的代码

在这里插入图片描述

3. 服务器的API

由于这些前后交互需要用到 json 格式去传入数据.(可以不用,但是我这里约定了使用这样的一个格式)

3.1 导入 JackSon 库

在这里插入图片描述

3.2 创建 ProblemServlet 类

创建 api 包, 在包下创建 这个类
这个类对应的是交互1

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 是 Jackson 中的一个重要的类
    private final ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setStatus(200);
        resp.setContentType("application/json;charset=utf8");

        // 获取全部的题目列表
        ProblemDao problemDao = new ProblemDao();
        List<Problem> problems = problemDao.selectAll();

        // 转化成json格式字符串
        String respString = objectMapper.writeValueAsString(problems);
        resp.getWriter().write(respString);
    }
}

在这里插入图片描述

3.3 测试 ProblemServlet 类

在这里插入图片描述

3.4 创建 DescServlet 类

同样在api包下, 创建 DescServlet 类
这个类对应交互2

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;

@WebServlet("/desc")
public class DescServlet extends HttpServlet {
    
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setStatus(200);
        resp.setContentType("application/json;charset=utf8");

        // 首先获取到id
        String idString = req.getParameter("id");
        if(idString == null || "".equals(idString)){
    
    
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().write("<h3>id丢失</h3>");
            return;
        }
        int id = Integer.parseInt(idString);
        // 获取对应id题目的详情页
        ProblemDao problemDao = new ProblemDao();
        Problem problem = problemDao.selectOne(id);
        // 将problem 转成json格式字符串 写回响应
        String respString = objectMapper.writeValueAsString(problem);
        resp.getWriter().write(respString);
    }
}

3.5 测试 DescServlet 类

在这里插入图片描述

3.6 创建 ResultServlet 类

同样放到 api 包里.
这个类对应的是交互3

由于这里请求也需要带着这个json格式.所以使用两个静态内部类来表示请求body和响应body的格式.

静态内部类 ResultRequest

    /**
     * 结果的请求body格式
     */
    static class ResultRequest{
    
    
        public int id;
        public String code;
    }

静态内部类 ResultResponse

    /**
     * 结果的响应body格式
     */
    static class ResultResponse{
    
    
        // error 0:运行成功 1: 编译出错 2: 运行出错 3:其他错误
        public int error;
        public String reason;
        public String stdout;
    }

实现 doPost

private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setStatus(200);
        resp.setContentType("application/json;charset=utf8");
        // 1. 读取请求正文, 按照json格式读取
        String body = readBody(req);
        ResultRequest resultRequest = objectMapper.readValue(body, ResultRequest.class);
        // 2. 根据 id 从数据库中查找到题目的测试用例
        ProblemDao problemDao = new ProblemDao();
        Problem problem = problemDao.selectOne(resultRequest.id);
        // 测试用例代码
        String testCode = problem.getTestCode();
        // 提交的代码
        String requestCode = resultRequest.code;
        // 3. 把用户提交的代码和测试用例的代码,给瓶装成一个完整的代码
        String finalCode = mergeCode(requestCode,testCode);
        // 4. 创建一个 Task 实例, 调用里面的 compileAndRun 来进行编译运行
        Task task = new Task();
        Question question = new Question();
        question.setCode(finalCode);
        Answer answer = task.compileAndRun(question);
        // 5. 根据 Task 运行的结果, 包装成一个 Http 响应
        ResultResponse resultResponse = new ResultResponse();
        resultResponse.error = answer.getError();
        resultResponse.reason = answer.getReason();
        resultResponse.stdout = answer.getStdout();

        String respString = objectMapper.writeValueAsString(resultResponse);
        resp.getWriter().write(respString);
    }

实现 readBody 方法

    /**
     * 读取请求的正文
     * @param req 请求
     * @return 以字符串形式返回
     * @throws UnsupportedEncodingException 字符编码不支持的异常
     */
    private String readBody(HttpServletRequest req) throws UnsupportedEncodingException {
    
    
        // 1. 根据 Content-Length 获取 body 中的长度(单位是字节)
        int contentLength = req.getContentLength();
        // 2. 按照找个长度准备一个 byte[]
        byte[] buffer = new byte[contentLength];
        // 3. 通过 req 里面的 getInputStream 方法, 获取body的流对象(body比较长)
        try (InputStream inputStream = req.getInputStream()){
    
    
            // 4. 基于这个流对象,读取内容,将读取到内容放到byte[]数组中
            inputStream.read(buffer);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        // 5. 把这个 byte[] 的内容构造成一个 String
        return new String(buffer,"utf8");
    }

实现 mergeCode 方法

    /**
     * 测试用例代码和提交的代码合并
     * @param requestCode 提交的代码
     * @param testCode 测试用例代码
     * @return 返回合并后的代码
     */
    private String mergeCode(String requestCode, String testCode) {
    
    
        // 找到最后一个"}"的位置
        int index =requestCode.lastIndexOf("}");
        if (index == -1){
    
    
            // 这里是不存在的情况
            return null;
        }
        // 截取前面的代码
        String curCode = requestCode.substring(0,index);
        // 拼接代码
        return curCode + testCode + "\n}";
    } 

3.7 测试 ResultServlet 类

打开postman应用
如果不会使用postman 可以看 博文 Postman的使用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.8 这里发现 如果 id不存在 或者 code为空的时候出现服务器错误.

更改代码
在这里插入图片描述
并在 comon包中 创建这两个类继承 Exception
在这里插入图片描述
在这里插入图片描述
当catch到异常的时候, 设置状态码为3
在这里插入图片描述

3.9 再次对 ResultServlet 进行测试

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wwzzzzzzzzzzzzz/article/details/124946263