在线 OJ 项目(二) · 操作数据库 · 设计前后端交互的 API · 实现在线编译运行功能

news2025/1/4 16:13:30

  • 一、操作数据库前的准备
  • 二、封装操作数据库数据的相关操作
  • 三、设计前后端交互的 API
  • 四、实现在线编译运行功能

一、操作数据库前的准备

设计数据库表

我们需要对数据库中存储的题目进行操作.

创建一个 “题目表” oj_table
题目的序号 id. 作为题目表的自增主键。
标题 title.
难度 level. 题目分为 “简单”,“中等”,“困难” 三种难度。
描述 description. 题目的基本描述,示例,提示等信息。
代码模板 templateCode. 给用户展示的初始代码,用户要在此代码模板上开发。
测试用例 testCode. 一组测试的代码,判断用户的代码是否正确。

create database if not exists oj_database;

use oj_database;

drop table if exists oj_table;
create table oj_table(
    id int primary key auto_increment,
    title varchar(50),
    level varchar(50),
    description varchar(4096),
    templateCode varchar(4096),
    testCode varchar(4096)
);

封装数据库操作 DBUtil

public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/oj_database?characterEncoding=utf8%useSSL=false";
    // 自己电脑上的 MySQL 账户密码
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";

    //懒汉式
    private static volatile DataSource dataSource = null;

    private static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    MysqlDataSource mysqlDataSource = new MysqlDataSource();
                    mysqlDataSource.setURL(URL);
                    mysqlDataSource.setUser(USERNAME);
                    mysqlDataSource.setPassword(PASSWORD);
                    dataSource = mysqlDataSource;
                }
            }
        }
        return dataSource;
    }
    
    // 提供方法获取连接
    public static Connection getConnection() throws SQLException {
        return getDataSource().getConnection();
    }
    
    // 关闭释放连接的操作
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

存储题目实体类的Problem

public class Problem {
    private int id;
    private String title;
    private String level;
    private String description;
    private String templateCode;
    private String testCode;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getTemplateCode() {
        return templateCode;
    }

    public void setTemplateCode(String templateCode) {
        this.templateCode = templateCode;
    }

    public String getTestCode() {
        return testCode;
    }

    public void setTestCode(String testCode) {
        this.testCode = testCode;
    }

    @Override
    public String toString() {
        return "Problem{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", level='" + level + '\'' +
                ", description='" + description + '\'' +
                ", templateCode='" + templateCode + '\'' +
                ", testCode='" + testCode + '\'' +
                '}';
    }
}

二、封装操作数据库数据的相关操作

ProblemDAO

// 通过这个类来实现题目的增删改查
// 1. 新增题目
// 2. 删除题目
// 3. 查询题目列表
// 4. 查询题目详情
public class ProblemDAO {

    // 1. 新增题目
    public void insert(Problem problem) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1. 获取数据库连接
            connection = DBUtil.getConnection();
            // 2. 构造 SQL
            String sql = "insert into oj_table values(null, ?, ?, ?, ?, ?)";
            // 3. 动态替换
            statement = connection.prepareStatement(sql);
            statement.setString(1, problem.getTitle());
            statement.setString(2, problem.getLevel());
            statement.setString(3, problem.getDescription());
            statement.setString(4, problem.getTemplateCode());
            statement.setString(5, problem.getTestCode());
            // 4. 执行 SQL
            int ret = statement.executeUpdate();
            if (ret != 1) {
                System.out.println("新增题目失败");
            } else {
                System.out.println("新增题目成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }

    // 2. 删除题目
    public void delete(int id) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "delete from oj_table where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1, id);
            int ret = statement.executeUpdate();
            if (ret != 1) {
                System.out.println("删除题目失败!");
            } else {
                System.out.println("删除题目成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }

    // 3. 查询题目
    public List<Problem> selectAll() {
        List<Problem> problems = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select id, title, level from oj_table";
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();
            while (resultSet.next()) {
                Problem problem = new Problem();
                problem.setId(resultSet.getInt("id"));
                problem.setTitle(resultSet.getString("title"));
                problem.setLevel(resultSet.getString("level"));
                problems.add(problem);
            }
            return problems;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }

    // 4. 查询题目详情
    public Problem selectOne(int id) {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select * from oj_table where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1, id);
            resultSet = statement.executeQuery();
            if (resultSet.next()) {
                Problem problem = new Problem();
                problem.setId(resultSet.getInt("id"));
                problem.setTitle(resultSet.getString("title"));
                problem.setLevel(resultSet.getString("level"));
                problem.setDescription(resultSet.getString("description"));
                problem.setTemplateCode(resultSet.getString("templateCode"));
                problem.setTestCode(resultSet.getString("testCode"));
                return problem;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }
}

单元测试

测试功能是否有问题.

    // 单元测试
    private static void testInsert() {
        ProblemDAO problemDAO = new ProblemDAO();
        Problem problem = new Problem();
        problem.setTitle("两数之和");
        problem.setLevel("简单");
        problem.setDescription("给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。\n" +
                "\n" +
                "你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。\n" +
                "\n" +
                "你可以按任意顺序返回答案。\n" +
                "\n" +
                " \n" +
                "\n" +
                "示例 1:\n" +
                "\n" +
                "输入:nums = [2,7,11,15], target = 9\n" +
                "输出:[0,1]\n" +
                "解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。\n" +
                "示例 2:\n" +
                "\n" +
                "输入:nums = [3,2,4], target = 6\n" +
                "输出:[1,2]\n" +
                "示例 3:\n" +
                "\n" +
                "输入:nums = [3,3], target = 6\n" +
                "输出:[0,1]\n" +
                " \n" +
                "\n" +
                "提示:\n" +
                "\n" +
                "2 <= nums.length <= 104\n" +
                "-109 <= nums[i] <= 109\n" +
                "-109 <= target <= 109\n" +
                "只会存在一个有效答案\n" +
                " \n" +
                "\n" +
                "进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?\n" +
                "\n" +
                "来源:力扣(LeetCode)\n" +
                "链接:https://leetcode.cn/problems/two-sum\n" +
                "著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。");
        problem.setTemplateCode("class Solution {\n" +
                "    public int[] twoSum(int[] nums, int target) {\n" +
                "\n" +
                "    }\n" +
                "}");
        problem.setTestCode("    // 这个 main 方法就相当于测试用例的代码.\n" +
                "    public static void main(String[] args) {\n" +
                "        Solution solution = new Solution();\n" +
                "        // testcase1\n" +
                "        int[] nums = {2,7,11,15};\n" +
                "        int target = 9;\n" +
                "        int[] result = solution.twoSum(nums, target);\n" +
                "        if (result.length == 2 && result[0] == 0 && result[1] == 1) {\n" +
                "            System.out.println(\"testcase1 OK\");\n" +
                "        } else {\n" +
                "            System.out.println(\"testcase1 failed!\");\n" +
                "        }\n" +
                "\n" +
                "        // testcase2\n" +
                "        int[] nums2 = {3,2,4};\n" +
                "        int target2 = 6;\n" +
                "        int[] result2 = solution.twoSum(nums2, target2);\n" +
                "        if (result2.length == 2 && result[0] == 1 && result[1] == 2) {\n" +
                "            System.out.println(\"testcase2 OK\");\n" +
                "        } else {\n" +
                "            System.out.println(\"testcase2 failed!\");\n" +
                "        }\n" +
                "    }");
        problemDAO.insert(problem);
    }


    private static void testSelectAll() {
        ProblemDAO problemDAO = new ProblemDAO();
        List<Problem> problems = problemDAO.selectAll();
        System.out.println(problems);
    }


    private static void testSelectOne() {
        ProblemDAO problemDAO = new ProblemDAO();
        Problem problem = problemDAO.selectOne(2);
        System.out.println(problem);
    }


    private static void testDelete() {
        ProblemDAO problemDAO = new ProblemDAO();
        problemDAO.delete(2);
    }


    public static void main(String[] args) {
//        testInsert();
//        testSelectAll();
//        testSelectOne();
        testDelete();
    }
}

三、设计前后端交互的 API

已经把数据库的相关操作封装好了。

接下来可以设计服务器提供的 API,一些 HTTP 风格的接口,通过这些接口和网页前端进行交互。

需要设计哪些网页?

a)题目列表页。功能是展示当前题目的列表。方法:向服务器发送请求,题目的列表。

b)题目详情页。
功能一:展示题目的详细要求。方法:向服务器请求,获取指定题目的详细信息。
功能二:能够有一个代码编辑框,让用户来编写代码。此过程不需要和服务器交互,前端实现。
功能三:有提交按钮,点击提交按钮,就能把用户编辑的代码发送到服务器上,进行编译和运行,最后返回结果。方法:向服务器发送用户当前编写的代码,并获取到结果。

约定 API

目前比较流行的前后端交互的方式,主要是通过 JSON 格式来组织的。我们可以引入第三方库来帮忙解析 JSON 格式,会方便很多。

Jackson 依赖导入

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

具体设计以下几个前后端交互的 API

向服务器请求,题目的列表.
请求:GET /problem
响应:[{id:1, title:“两数之和”, level:“简单”,}, {id:2, title:“两数相加”, level:“简单”,}]

向服务器请求,获取指定题目的详细信息.
请求:GET /problem?id=1
响应:{id:1, title:“两数之和”, level:“简单”, description:“题目的详细要求…”, templateCode:“代码模板”, testCode:" ",}

向服务器发送用户当前编写的代码,并且获取到结果.
请求:POST /compile {id:1, code:“编辑框的代码…”}
响应:{error:0, reason:“出错的详细原因”, stdout:“测试用例的输出情况,包含了通过几个用户这样的信息”}

编写获取题目列表和题目详细信息的功能

@WebServlet("/problem")
public class ProblemServlet extends HttpServlet {
    // json 的核心类
    private 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();
        // 尝试获取 id 参数,如果能获取到,说明是获取题目详情;如果不能获取到,说明是获取题目列表
        String idString = req.getParameter("id");
        if (idString == null || "".equals(idString)) {
            // 没有获取到 id 字段,查询题目列表
            List<Problem> problems = problemDAO.selectAll();
            // 将 problems 进行转换成 json 结构的字符串
            String respString = objectMapper.writeValueAsString(problems);
            // 将得到的字符串响应回去-设置 HTTP 响应的 body 部分
            resp.getWriter().write(respString);
        } else {
            // 获取到了题目的 id,查询题目详情
            Problem problem = problemDAO.selectOne(Integer.parseInt(idString));
            String respString = objectMapper.writeValueAsString(problem);
            resp.getWriter().write(respString);
        }
    }
}

然后配置并启动 Tomcat,我们来测试是否能接收到请求。

能够通过网页请求到数据。

通过 Postman 也能够显示数据。
在这里插入图片描述

由于代码中通过 if 区分两种 API,所以我们可以尝试获取前端请求的 id 来测试是否能够获取到数据。

查找 id 为 1 的题目,显示 null。

通过 Postman 查询 id 为 4 的题目,能够显示。

在这里插入图片描述

很显然可以获取到数据,接下来我们实现在线编译运行功能。


四、实现在线编译运行功能

用户提交的代码,只是一个 Solution 这样的类,里面包含了一个核心方法。而要想编译运行,还需要一个 main 方法。main 方法在测试用例代码中,测试用例代码就在数据库中。

当前编译运行,请求和响应都是 JSON 格式的数据。为了方便解析和构造,就可以创建两个类,来对应这两个 JSON 结构。

    static class CompileRequest {
        public int id;
        public String code;
    }

    static class CompileResponse {
        // 0 表示没问题,1 表示编译出错,2 表示运行异常,3 表示其它错误
        public int error;
        public String reason;
        public String stdout;
    }

这两个类可以写在 CompileServlet 类中.

@WebServlet("/compile")
public class CompileServlet extends HttpServlet {

    static class CompileRequest {
        public int id;
        public String code;
    }

    static class CompileResponse {
        // 0 表示没问题,1 表示编译出错,2 表示运行异常,3 表示其它错误
        public int error;
        public String stdout;
        public String reason;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        // 1. 读取请求的正文
        String body = readBody(req);

        // 2. 根据 id 从数据库中查找到题目的详情 - 得到测试用例代码

        // 3. 把用户提交的代码和测试用例代码,拼接成一个完整的代码

        // 4. 创建一个 Task 实例,调用里面的 compileAndRun 来解析编译运行

        // 5. 根据 Task 运行的结果,包装成一个 HTTP 响应
    }

我们要实现编译运行功能,需要经过以下几个步骤:

  1. 读取请求的正文
  2. 根据 id 从数据库中查找到题目的详情 - 得到测试用例代码
  3. 把用户提交的代码和测试用例代码,拼接成一个完整的代码
  4. 创建一个 Task 实例,调用里面的 compileAndRun 来解析编译运行
  5. 根据 Task 运行的结果,包装成一个 HTTP 响应

先看第一步,读取到请求的正文

我们使用个方法 readBody,封装一下获取请求正文的操作。

//获取请求头中的内容,转换成字符串类型
    private static String readBody(HttpServletRequest req) throws UnsupportedEncodingException {
        // 1. 根据请求头里面的 ContentLength 获取到 body 的长度
        int contentLength = req.getContentLength();

        // 2. 按照这个长度准备好一个 byte[]
        byte[] buffer = new byte[contentLength];

        // 3. 通过 req 里面的方法,获取到 body 的流对象
        try(InputStream inputStream = req.getInputStream()) {

            // 4. 基于这个流对象,读取内容,然后把内容放到 byte[] 数字中即可
            inputStream.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 5. 把这个 byte[] 的内容构造成一个 String,同时设置转换字符集格式
        return new String(buffer, "utf8");
    }
return new String(buffer, "utf8");

这段代码,相当于把一个二进制数据,转换成一个文本数据。
把 byte[] (以字节为单位),转换成 String (以字符为单位)。

而后续的 "utf8" 是为了在转换的过程中指定字符集,告诉编码方式。
从请求中读取的 byte[] 不清楚是哪种格式,需要在构造 String 的时候告诉 String,当前的 byte[] 是按照啥样的格式来编码。

补充完 readBody 方法,我们继续

package api;

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

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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;

/**
 * Created by cc
 * Description:
 * User: CZH
 * Date: 2023-01-29
 * Time: 14:43
 */
@WebServlet("/compile")
public class CompileServlet extends HttpServlet {

    static class CompileRequest {
        public int id;
        public String code;
    }
    static class CompileResponse {
        // 0 表示没问题,1 表示编译出错,2 表示运行异常,3 表示其它错误
        public int error;
        public String stdout;
        public String reason;
    }

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 读取请求的正文,别按照 JSON 格式解析
        String body = readBody(req);
        // 类对象,获取类的信息
        CompileRequest compileRequest = objectMapper.readValue(body, CompileRequest.class);
        // 2. 根据 id 从数据库中查找到题目的详情 - 得到测试用例代码
       
        // 3. 把用户提交的代码和测试用例代码,拼接成一个完整的代码
      
        // 4. 创建一个 Task 实例,调用里面的 compileAndRun 来解析编译运行
   
        // 5. 根据 Task 运行的结果,包装成一个 HTTP 响应
    }

    // 通过请求头获取数据,转换成String 返回
    private static String readBody(HttpServletRequest req) throws UnsupportedEncodingException {
        int contentLength = req.getContentLength();
        byte[] bytes = new byte[contentLength];
        try(InputStream inputStream = req.getInputStream()) {
            inputStream.read(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new String(bytes, "utf8");
    }
}

这段代码,就是根据类对象 CompileRequest.class,获取到 CompileRequest 这个类都有哪些属性,叫什么名字,依次遍历这些属性。

例如拿到 id 这个属性,就去 json 字符串中找 key 为 id 的键值对。发现 value 是 2,于是就把 2 赋值到 new 出来的 CompileRequest 的 id 字段中。

完成步骤二的代码.
根据 id 从数据库中查找到题目的详情,从而得到测试用例代码。

      // 2. 根据 id 从数据库中查找到题目的详情 - 得到测试用例代码
        ProblemDAO problemDAO = new ProblemDAO();
        Problem problem = problemDAO.selectOne(compileRequest.id);
        // testCode 是测试用例的代码
        String testCode = problem.getTestCode();
        // requestCode 是用户提交的代码
        String requestCode = compileRequest.code;

完成步骤三的代码.
把用户提交的代码和测试用例代码,拼接成一个完整的代码。

拼接的思路呢,其实就是把 testCode 的这个 main 方法,嵌入到 requestCode 里面,做法就是把 testCode 放到 Solution 的最后一个 } 的前面即可~

    // 3. 把用户提交的代码和测试用例代码,拼接成一个完整的代码
    String finalCode = mergeCode(requestCode, testCode);
    
    // 拼接代码
    private static String mergeCode(String requestCode, String testCode) {
        // 1. 查找 requestCode 最后一个 }
        int pos = requestCode.lastIndexOf("}");
        if (pos == -1) {
            return null;
        }
        // 2. 截取字符串
        String substring = requestCode.substring(0, pos);
        // 3. 拼接字符串并返回
        return substring + testCode + "\n}";
    }

到这里我们测试一波~

目前看没什么问题,继续…

完成步骤四代码.
创建一个 Task 实例,调用里面的 compileAndRun 来解析编译运行.

        // 4. 创建一个 Task 实例,调用里面的 compileAndRun 来解析编译运行
        Task task = new Task();
        Question question = new Question();
        question.setCode(finalCode);
        Answer answer = task.compileAndRun(question);

完成步骤五代码.
根据 Task 运行的结果,包装成一个 HTTP 响应.

// 5. 根据 Task 运行的结果,包装成一个 HTTP 响应
        CompileResponse compileResponse = new CompileResponse();
        compileResponse.error = answer.getError();
        compileResponse.reason = answer.getReason();
        compileResponse.stdout = answer.getStdout();
        String respString = objectMapper.writeValueAsString(compileResponse);
        resp.getWriter().write(respString);

进行测试~

能够得到数据,没问题~

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

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

相关文章

Android之常见的使用技巧

文章目录1.全局获取Context的技巧2.使用Intent传递对象Serializable方式Parcelable方式3.定制自己的日志工具4.深色主题5.Java和Kotlin代码之间的转换1.全局获取Context的技巧 在Android中&#xff0c;你会发现有很多地方都需要用到Context&#xff0c;例如&#xff1a;弹出To…

设计模式在项目中的运用

一、如何管理庞大而复杂的项目开发&#xff1f;1、从设计原则和思想的角度来看&#xff0c;如何应对庞大而复杂的项目开发&#xff1f;① 封装与抽象&#xff1a;“一切皆文件”:封装了不同类型设备的访问细节&#xff0c;抽象为统一的文件访问方式&#xff0c;更高层的代码就能…

windows下解决Git报错: LF will be replaced by CRLF the next time Git touches it

问题 在命令行执行git add *的时候&#xff0c;提示Warning&#xff1a; 通常情况下是在 Windows环境中才会遇到。 原因 Uinx/Linux采用换行符LF表示下一行&#xff08;LF&#xff1a;LineFeed&#xff0c;中文意思是换行&#xff09;&#xff0c;即&#xff1a;\n&#xff1…

Visual Transformer开端——ViT及其代码实现

深度学习知识点总结 专栏链接: https://blog.csdn.net/qq_39707285/article/details/124005405 此专栏主要总结深度学习中的知识点&#xff0c;从各大数据集比赛开始&#xff0c;介绍历年冠军算法&#xff1b;同时总结深度学习中重要的知识点&#xff0c;包括损失函数、优化器…

购买和登录Linux云服务器

目录 云服务器的购买 SSH登录云服务器 云服务器的购买 我们以腾讯云为例, 其他的服务器厂商也是类似。 1. 进入腾讯云官方网站&#xff1a;学生云服务器_云校园特惠套餐 - 腾讯云 (tencent.com) 2. 登陆网站(可以使用微信登陆) 3.购买云服务器 购买最低级即可&#xff0c;对于…

36/365 java 类的加载 链接 初始化 ClassLoader

1.类的加载&#xff0c;链接&#xff0c;初始化 注意点&#xff1a; Class对象是在类的加载过程中生成的&#xff08;类的数据&#xff08;static,常量&#xff0c;代码&#xff09;在方法区&#xff0c;Class类对象在堆中&#xff09;&#xff0c;这个Class类对象作为方法区中…

Canvas 实现台球假想球精准定位

1. 前言 台球是一个让人非常着迷的运动项目&#xff0c;充满了各种计算逻辑&#xff0c;十分有趣。 对于初学者&#xff0c;母球、目标球、袋口三者在一条线上的时候&#xff0c;是非常容易进球的&#xff0c;但对于三者不在一条线上时&#xff0c;就是需要假想球的帮助&…

Windows 上安装 Insomnia 代替 Postman

Windows 上安装 Insomnia 代替 PostmanInsomnia 概述官网地址下载和安装 Insomnia使用 InsomniaInsomnia 概述 Insomnia 是一个开源桌面应用程序&#xff0c;它提供了设计、调试和测试API的简单方法。 通过对开发者友好的界面、内置的自动化和可扩展的插件生态系统&#xff0…

自动驾驶中间件:量产落地的关键技术

/ 导读 /对于初入自动驾驶行业的人来说&#xff0c;各色各样的新型传感器、线控系统、芯片域控制器、算法软件似乎是自动驾驶未来实现的重中之重&#xff0c;对于中间件大多数人可能都不太熟悉&#xff0c;有些甚至从未听说过其存在。但中间件却也是极为重要的一环&#xff0c;…

设计模式-创建型模式

目录 4.创建型模式 4.1 单例设计模式 4.1.1 单例模式的结构 4.1.2 单例模式的实现 4.1.3 存在的问题 4.1.4 JDK源码解析-Runtime类 4.2 工厂模式 4.2.1 概述 4.2.2 简单工厂模式 4.2.3 工厂方法模式 4.2.4 抽象工厂模式 4.2.5 模式扩展 4.2.6 JDK源码解析-Collecti…

Kotlin~生成器模式

介绍 主要作用 逐步构造复杂对象&#xff0c;该对象的属性更多的扩展属性&#xff0c;如Glide的使用。 组成 Builder&#xff1a;提供逐步创建产品的步骤 Director&#xff1a;创建可复用的特定产品&#xff08;规定Builder规定一系列的步骤创建产品&#xff0c;非必须&…

21新版FL Studio水果电音编曲Daw宿主软件好不好用?

首先是FL Studio&#xff08;以下简称FL&#xff09;的逻辑和其它宿主软件都不太一样&#xff0c;FL的逻辑就与众不同。FL的逻辑也可以分为三部分&#xff1a;通道机架、混音台和播放列表。在Live里每个发送轨都可以插入一个乐器以及若干个效果器。你有200个发送轨&#xff0c;…

vcenter 起不来报错VMware ESX 找不到虚拟磁盘“vCenter Server 7.0U3_12.vmdk”。请确认路径有效并重试

针对无快照时丢失.vmdk描述符文件&#xff1a;基础磁盘文件为-flat.vmdk是存在的 那个可以进行恢复操作步骤如下1.确定 flat.vmdk基础磁盘文件的大小&#xff08;字节&#xff09;2.创建与flat.vmdk相同大小的新的空虚拟磁盘。3.重命名新创建的.vmdk磁盘的描述符文件匹配原始虚…

如何运行一个py项目

在pycharm中打开项目文件确保安装python环境此时是使用python3.7版本&#xff0c;没有的话需要添加环境&#xff1a;add interpreter在anaconda&#xff08;安装参考https://blog.csdn.net/m0_67357141/article/details/123633490&#xff09;中选择基础环境&#xff08;base&a…

Python中的列表

1.创建列表 使用中括号把要添加的元素括起来&#xff0c;不同元素用逗号隔开。 >>> rhyme [1, 2, 3, 4, 5, "上山打老虎"] >>> print(rhyme) [1, 2, 3, 4, 5, 上山打老虎]2.访问列表中的元素 &#xff08;1&#xff09;希望顺序访问列表中的元…

博弈论入门

分类 要素 常见博弈 完全信息静态博弈 纳什均衡 囚徒困境 古诺双寡头模型 古诺双寡头模型的条件 市场中有且仅有两家公司策略为同质商品的量&#xff0c;qiq_iqi​边际成本为c&#xff0c;生产成本就为c*q&#xff0c;在这里我们的边际成本是常数。需求曲线&#xff1a;Pa−b∗…

2009-01-从学校毕业步入社会

在一间坐满学生的教室中&#xff0c;台上同学正在对自己毕业答辩项目进行介绍&#xff0c;台下第一排坐着打分的老师&#xff0c;这群人正在进行计算机专业的毕业答辩&#xff0c;台下人群中一个叫刘文轩的同学紧张又期盼的看着前面正在进行答辩的同学&#xff0c;看着同学们优…

react中useReduer和useEffect

相信很多人对于变成中reduce、reducer命名都存在困惑&#xff0c;为了更好理解useRedecuer&#xff0c;我们不妨先来说说reduce。 如何理解reduce和reducer reduce&#xff1a;函数式编程当中的一个术语&#xff0c;reduce操作被称为Fold折叠 // 通过reduce&#xff0c;数组…

公司内部有奖知识答题活动怎么做

公司年会趣味问答、员工业务知识考核、消防安全、党史等知识测试......公司内部的答题活动已经成了众多管理者、HR日常工作中一部分。如何让组织者更轻松、更公平公正地举办答题活动&#xff1f;如何让员工更积极参与呢&#xff1f;试试答题小博士的有奖答题。有奖答题活动形式…

中晶FileScan 3222扫描仪 Code:-206,卡纸或滚筒出错

中晶FileScan 3222是中晶品牌下的一款扫描仪。 型号 3222 产品类型 平板式+馈纸式 扫描光源 LED