8.编写control模块整体结构|引入ctemplate|编写view获取题目列表和指定题目(C++)

编写control模块整体结构

#pragma once
  
#include <iostream>
#include <string>
#include <vector>
  
#include "../comm/util.hpp"
#include "../comm/log.hpp"
#include "oj_model.hpp"
  
namespace ns_control
{
    using namespace std;
    using namespace ns_log;
    using namespace ns_util;
    using namespace ns_model;
  
    class Control
    {
    private:
        Model model_;
    public:
        Control()
        {}
        ~Control()
        {}
    public:
        //根据题目数据构建网页
        // html: 输出型参数
        bool AllQuestions(string *html)
        {
            vector<struct Question> all;
            if (model_.GetAllQuestions(&all))
            {
                // 获取题目信息成功,将所有的题目数据构建成网页
            }
            else
            {
  
            }
        }
        bool Question(const string &number, string *html)
        {
            struct Question q;
            if (model_.GetOneQuestion(number, &q))
            {
                // 获取指定题目信息成功,将所有的题目数据构建成网页
            }
            else
            {
  
            }
        }
    };
}

oj_server.cc

#include <iostream>

#include "../comm/httplib.h"
#include "oj_control.hpp"
  
using namespace httplib;
using namespace ns_control;
  
int main()
{
    //用户请求的服务路由功能
    Server svr;
    Control ctrl;
  
    // 获取所有的题目列表
    svr.Get("/all_questions", [&ctrl](const Request &req, Response &resp){
        //返回一张包含有所有题目的html网页
        std::string html;
        ctrl.AllQuestions(&html);
        //用户看到的是什么呢??网页数据 + 拼上了题目相关的数据
        resp.set_content(html, "text/html; charset=utf-8");
        //resp.set_content("这是所有题目的列表", "text/plain; charset=utf-8");
    });
  
    // 用户要根据题目编号,获取题目的内容
    // /question/100 -> 正则匹配
    // R"()", 原始字符串raw string,保持字符串内容的原貌,不用做相关的转义
    svr.Get(R"(/question/(\d+))", [&ctrl](const Request &req, Response &resp){
        std::string number = req.matches[1];
        std::string html;
        ctrl.Question(number, &html);
        resp.set_content(html, "text/html; charset=utf-8");
        //resp.set_content("这是指定的一道题:" + number, "text/plain; charset=utf-8");
    });
    // 用户提交代码,使用我们的判题功能(1. 每道题的测试用例 2. compile_and_run)
    svr.Post(R"(/judge/(\d+))", [](const Request &req, Response &resp){
        std::string number = req.matches[1];
        resp.set_content("指定题目的判题: " + number, "text/plain; charset=utf-8");
    });
    svr.set_base_dir("./wwwroot");
    svr.listen("0.0.0.0", 8080);
    return 0;
}

引入ctemplate

安装
git clone https://github.com/OlafvdSpek/ctemplate.git
./autogen.sh  
./configure  
make
make install

如果./autogen.sh报错,安装下面的工具

yum  -y install autoconf automake libtool
测试

原理:将保存数据的字典加到待被渲染的网页内容里
test.cc

#include <iostream>
#include <string>
#include <ctemplate/template.h>

int main()
{
    std::string in_html = "./test.html";
    std::string value = "在线OJ";
  
    // 形成数据字典
    ctemplate::TemplateDictionary root("test"); //unordered_map<> test;
    root.SetValue("key", value);                //test.insert({});
  
    // 获取被渲染网页对象
    ctemplate::Template *tpl = ctemplate::Template::GetTemplate(in_html, ctemplate::DO_NOT_STRIP);
  
    // 添加字典数据到网页中
    std::string out_html;
    tpl->Expand(&out_html, &root);
  
    //完成了渲染
    std::cout << out_html << std::endl;
}

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用来测试</title>
</head>
<body>
    <p>{{key}}</p>
    <p>{{key}}</p>
    <p>{{key}}</p>
    <p>{{key}}</p>
    <p>{{key}}</p>
</body>
</html>

编译

g++ test.cc -std=c++11 -lctemplate -lpthread

如果报错,没有找到依赖

./a.out: error while loading shared libraries: libctemplate.so.3: cannot open shared object file: No such file or directory

引入

export LD_LIBRARY_PATH=/usr/local/lib/:$LD_LIBRARY_PATH

运行成功
![[Pasted image 20250225110521.png]]

view获取全部题目列表

oj_control.hpp

#pragma once
  
#include <iostream>
#include <string>
#include <vector>
  
#include "../comm/util.hpp"
#include "../comm/log.hpp"
#include "oj_model.hpp"
#include "oj_view.hpp"
  
namespace ns_control
{
    using namespace std;
    using namespace ns_log;
    using namespace ns_util;
    using namespace ns_model;
    using namespace ns_view;
  
    class Control
    {
    private:
        Model model_; //提供后台数据
        View view_;   //提供网页渲染功能
    public:
        Control()
        {}
        ~Control()
        {}
    public:
        //根据题目数据构建网页
        // html: 输出型参数
        bool AllQuestions(string *html)
        {
            bool ret = true;
            vector<struct Question> all;
            if (model_.GetAllQuestions(&all))
            {
                // 获取题目信息成功,将所有的题目数据构建成网页
                view_.AllExpandHtml(all, html);
            }
            else
            {
                *html = "获取题目失败, 形成题目列表失败";
                ret = false;
            }
            return ret;
        }
        bool Question(const string &number, string *html)
        {
            bool ret = true;
            struct Question q;
            if (model_.GetOneQuestion(number, &q))
            {
                // 获取指定题目信息成功,将所有的题目数据构建成网页
                view_.OneExpandHtml(q, html);
            }
            else
            {
                *html = "指定题目: " + number + " 不存在!";
                ret = false;
            }
            return ret;
        }
    };
}
代码框架
#pragma once
  
#include <iostream>
#include <string>
#include <ctemplate/template.h>
  
#include "oj_model.hpp"
  
namespace ns_view
{
    using namespace ns_model;
  
    class View
    {
    public:
        View(){}
        ~View(){}
    public:
        void AllExpandHtml(const vector<struct Question> &questions, std::string *html)
        {
            // 题目的编号 题目的标题 题目的难度
            // 推荐使用表格显示
        }
        void OneExpandHtml(const struct Question &q, std::string *html)
        {
  
        }
    };
}
运行server

makefile

oj_server:oj_server.cc
    g++ -o $@ $^ -std=c++11 -lpthread -lctemplate
  
.PHONY:clean
clean:
    rm -f oj_server

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>这是我的个人OJ系统</title>
</head>
<body>
    <h1>欢迎来到我的OJ</h1>
    <p>这是我个人独立开发的在线OJ平台</p>
    <table>
        <tr>
            <th>题目编号</th>
            <th>题目标题</th>
            <th>题目难度</th>
        </tr>
        <tr>
            <td>1111</td>
            <td>2222</td>
            <td>3333</td>
        </tr>
        <tr>
            <td>1111</td>
            <td>2222</td>
            <td>3333</td>
        </tr>
        <tr>
            <td>1111</td>
            <td>2222</td>
            <td>3333</td>
        </tr>
    </table>
</body>
</html>

![[Pasted image 20250225122611.png]]

添加template模板文件
![[Pasted image 20250225123202.png]]

all_questions.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在线OJ—题目列表</title>
</head>
<body>
    <table>
        <tr>
            <th>编号</th>
            <th>标题</th>
            <th>难度</th>
        </tr>
        {{#question_list}}
        <tr>
            <td>{{number}}</td>
            <td>{{title}}</td>
            <td>{{star}}</td>
        </tr>
        {{/question_list}}
    </table>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>这是我的个人OJ系统</title>
</head>
<body>
    <h1>欢迎来到我的OJ</h1>
    <p>这是我个人独立开发的在线OJ平台</p>
    <a href="/all_questions">点击开始编程</a>
</body>
</html>

oj_view.hpp

#pragma once
  
#include <iostream>
#include <string>
#include <ctemplate/template.h>
  
#include "oj_model.hpp"
  
namespace ns_view
{
    using namespace ns_model;
  
    const std::string template_path = "./template_html/";
  
    class View
    {
    public:
        View(){}
        ~View(){}
    public:
        void AllExpandHtml(const vector<struct Question> &questions, std::string *html)
        {
            // 题目的编号 题目的标题 题目的难度
            // 推荐使用表格显示
            // 1. 形成路径
            std::string src_html = template_path + "all_questions.html";
            // 2. 形成数据字典
            ctemplate::TemplateDictionary root("all_questions");
            for (const auto& q : questions)
            {
                ctemplate::TemplateDictionary *sub = root.AddSectionDictionary("question_list");
                sub->SetValue("number", q.number);
                sub->SetValue("title", q.title);
                sub->SetValue("star", q.star);
            }
  
            //3. 获取被渲染的html
            ctemplate::Template *tpl = ctemplate::Template::GetTemplate(src_html, ctemplate::DO_NOT_STRIP);
  
            //4. 开始完成渲染功能
            tpl->Expand(html, &root);
        }
        void OneExpandHtml(const struct Question &q, std::string *html)
        {
  
        }
    };
}

编译运行
![[Pasted image 20250225124753.png]]

![[Pasted image 20250225124744.png]]

view获取指定题目功能

one_question.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{number}}.{{title}}</title>
</head>
<body>
    <h4>{{number}}.{{title}}.{{star}}</h4>
    <p>{{desc}}</p>
    <textarea name="code" cols="30" rows="10">{{pre_code}}</textarea>
</body>
</html>

oj_view.hpp

#pragma once
  
#include <iostream>
#include <string>
#include <ctemplate/template.h>
  
#include "oj_model.hpp"
  
namespace ns_view
{
    using namespace ns_model;
  
    const std::string template_path = "./template_html/";
  
    class View
    {
    public:
        View(){}
        ~View(){}
    public:
        void AllExpandHtml(const vector<struct Question> &questions, std::string *html)
        {
            // 题目的编号 题目的标题 题目的难度
            // 推荐使用表格显示
            // 1. 形成路径
            std::string src_html = template_path + "all_questions.html";
            // 2. 形成数据字典
            ctemplate::TemplateDictionary root("all_questions");
            for (const auto& q : questions)
            {
                ctemplate::TemplateDictionary *sub = root.AddSectionDictionary("question_list");
                sub->SetValue("number", q.number);
                sub->SetValue("title", q.title);
                sub->SetValue("star", q.star);
            }
  
            //3. 获取被渲染的html
            ctemplate::Template *tpl = ctemplate::Template::GetTemplate(src_html, ctemplate::DO_NOT_STRIP);
  
            //4. 开始完成渲染功能
            tpl->Expand(html, &root);
        }
        void OneExpandHtml(const struct Question &q, std::string *html)
        {
            // 1. 形成路径
            std::string src_html = template_path + "one_question.html";
  
            // 2. 形成数据字典
            ctemplate::TemplateDictionary root("one_question");
            root.SetValue("number", q.number);
            root.SetValue("title", q.title);
            root.SetValue("star", q.star);
            root.SetValue("desc", q.desc);
            root.SetValue("pre_code", q.header);
  
            //3. 获取被渲染的html
            ctemplate::Template *tpl = ctemplate::Template::GetTemplate(src_html, ctemplate::DO_NOT_STRIP);
            //4. 开始完成渲染功能
            tpl->Expand(html, &root);
        }
    };
}

all_questions.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在线OJ—题目列表</title>
</head>
<body>
    <table>
        <tr>
            <th>编号</th>
            <th>标题</th>
            <th>难度</th>
        </tr>
        {{#question_list}}
        <tr>
            <td>{{number}}</td>
            <td><a href="/question/{{number}}">{{title}}</a></td>
            <td>{{star}}</td>
        </tr>
        {{/question_list}}
    </table>
</body>
</html>

![[Pasted image 20250225130147.png]]

![[Pasted image 20250225130201.png]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值