编写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
运行成功
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>
添加template模板文件
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)
{
}
};
}
编译运行
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>