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

x33g5p2x  于2022-05-27 转载在 Java  
字(4.9k)|赞(0)|评价(0)|浏览(788)

1. 设计网页页面

1.1 列表页

只是大概模板

1.2 详情页

只是大概模板

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

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

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

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

3. 服务器的API

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

3.1 导入 JackSon 库

3.2 创建 ProblemServlet 类

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

  1. package api;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import dao.Problem;
  4. import dao.ProblemDao;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.annotation.WebServlet;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.IOException;
  11. import java.util.List;
  12. @WebServlet("/problem")
  13. public class ProblemServlet extends HttpServlet {
  14. // 这个 ObjectMapper 是 Jackson 中的一个重要的类
  15. private final ObjectMapper objectMapper = new ObjectMapper();
  16. @Override
  17. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  18. resp.setStatus(200);
  19. resp.setContentType("application/json;charset=utf8");
  20. // 获取全部的题目列表
  21. ProblemDao problemDao = new ProblemDao();
  22. List<Problem> problems = problemDao.selectAll();
  23. // 转化成json格式字符串
  24. String respString = objectMapper.writeValueAsString(problems);
  25. resp.getWriter().write(respString);
  26. }
  27. }

3.3 测试 ProblemServlet 类

3.4 创建 DescServlet 类

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

  1. package api;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import dao.Problem;
  4. import dao.ProblemDao;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.annotation.WebServlet;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.IOException;
  11. @WebServlet("/desc")
  12. public class DescServlet extends HttpServlet {
  13. private final ObjectMapper objectMapper = new ObjectMapper();
  14. @Override
  15. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  16. resp.setStatus(200);
  17. resp.setContentType("application/json;charset=utf8");
  18. // 首先获取到id
  19. String idString = req.getParameter("id");
  20. if(idString == null || "".equals(idString)){
  21. resp.setContentType("text/html;charset=utf-8");
  22. resp.getWriter().write("<h3>id丢失</h3>");
  23. return;
  24. }
  25. int id = Integer.parseInt(idString);
  26. // 获取对应id题目的详情页
  27. ProblemDao problemDao = new ProblemDao();
  28. Problem problem = problemDao.selectOne(id);
  29. // 将problem 转成json格式字符串 写回响应
  30. String respString = objectMapper.writeValueAsString(problem);
  31. resp.getWriter().write(respString);
  32. }
  33. }

3.5 测试 DescServlet 类

3.6 创建 ResultServlet 类

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

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

静态内部类 ResultRequest

  1. /**
  2. * 结果的请求body格式
  3. */
  4. static class ResultRequest{
  5. public int id;
  6. public String code;
  7. }

静态内部类 ResultResponse

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

实现 doPost

  1. private final ObjectMapper objectMapper = new ObjectMapper();
  2. @Override
  3. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  4. resp.setStatus(200);
  5. resp.setContentType("application/json;charset=utf8");
  6. // 1. 读取请求正文, 按照json格式读取
  7. String body = readBody(req);
  8. ResultRequest resultRequest = objectMapper.readValue(body, ResultRequest.class);
  9. // 2. 根据 id 从数据库中查找到题目的测试用例
  10. ProblemDao problemDao = new ProblemDao();
  11. Problem problem = problemDao.selectOne(resultRequest.id);
  12. // 测试用例代码
  13. String testCode = problem.getTestCode();
  14. // 提交的代码
  15. String requestCode = resultRequest.code;
  16. // 3. 把用户提交的代码和测试用例的代码,给瓶装成一个完整的代码
  17. String finalCode = mergeCode(requestCode,testCode);
  18. // 4. 创建一个 Task 实例, 调用里面的 compileAndRun 来进行编译运行
  19. Task task = new Task();
  20. Question question = new Question();
  21. question.setCode(finalCode);
  22. Answer answer = task.compileAndRun(question);
  23. // 5. 根据 Task 运行的结果, 包装成一个 Http 响应
  24. ResultResponse resultResponse = new ResultResponse();
  25. resultResponse.error = answer.getError();
  26. resultResponse.reason = answer.getReason();
  27. resultResponse.stdout = answer.getStdout();
  28. String respString = objectMapper.writeValueAsString(resultResponse);
  29. resp.getWriter().write(respString);
  30. }

实现 readBody 方法

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

实现 mergeCode 方法

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

3.7 测试 ResultServlet 类

打开postman应用
如果不会使用postman 可以看 博文 Postman的使用

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

更改代码

并在 comon包中 创建这两个类继承 Exception

当catch到异常的时候, 设置状态码为3

3.9 再次对 ResultServlet 进行测试

相关文章