文章《用C++实现类似于JAVA HttpServlet 的编程接口》中讲述了如何使用 acl_cpp 库之 HTTP 模块编写象 Java Servlet 一样的 WEB 应用。其中也讲到了 acl_cpp HTTP 模块中有关 Http Session、Cookie 的使用方法。而作为 WEB 编程中非常重要的网页模板引擎在 acl_cpp 并未实现。本文将结合谷歌的 ctemplate 库,讲解如何使用 acl_cpp 的 WEB 类库和谷歌的 ctemplate 模板引擎库来实现类似于 Java Servet + Velocity 的 WEB 应用。当然,用户也可以根据需要使用其它的模板引擎,如:CTPP(俄罗斯人写的)、Teng。关于 C++ 的模板引擎可以参考 《基于C++的模板引擎》。
一、HTML 模板:test.htm
<!--test.htm-->
<html>
<head>
<title> {{NAME}} </title>
</head>
{{!This is a example of template.}}
<body>
SID: {{SID}} <br>
COOKIE: {{COOKIE}} <br>
PARAM: {{PARAM}} <br>
<br>
Hello {{NAME}},
You have just won ${{VALUE}}!
<table border=1>
{{#IN_TABLE}}
<tr>
<td> {{ITEM}} </td>
<td> {{TAXED_VALUE}} </td>
</tr>
{{/IN_TABLE}}
</table>
<br>
{{!Include child template.}}
{{>INCLUDED_TEMPLATE}}
</body>
</html>
下面是内嵌在 test.htm 中的子模板:include.htm
<!--include.htm-->
<div>
{{INCLUDE_VAR}}
</div>
ctemplate 模板说明(摘自 marising 的《C++模板引擎Ctemplate的介绍》,该文中还有关于 ctemplate 更为高级的说明):
ctemplate大体上分为两个部分,一部分是模板,另一部分是数据字典。模板定义了界面展现的形式(V),数据字典就是填充模板的数据(M),你自己写业务逻辑去控制界面展现(C),典型的MVC模型。
ctemplate模板中有四中标记,对应的数据字典也有不同的处理方式:
1)变量,{{变量名}},用两个大括号包含的就是变量名,在c++代码中,可以对变量赋值,任何类型的值都可以(如字符,整数,日期等)。
2)片断,{{#片断名}},片断在数据字典中表现为一个子字典,字典是可以分级的,根字典下面有多级子字典。片断可以处理条件判断和循环。
3)包含,{{>模板名}}包含指的是一个模板可以包含其他模板,对应的也是一个字字典。
4)注释,{{!注释名}},包含注释。
二、使用 ctemplate 库来替换 test.htm 模板中的参数,同时将子模板 include.htm 包含进 test.htm 中,功能实现如下:
#include <string>
#include "ctemplate/template.h"
using namespace ctemplate;
// 打开模板文件将其中的标记进行替换,然后生成 HTML 页面
bool create_html(std::string* out, const char* sid,
const char* cookie, const char* param)
{
// 调用 google ctemplate 模板引擎生成页面
// 创建父模板
TemplateDictionary dict("example");
// 设置模板中的参数值
dict.SetValue("SID", sid ? sid : "null");
dict.SetValue("COOKIE", cookie ? cookie : "null");
dict.SetValue("PARAM", param ? param : "null");
dict.SetValue("NAME", "John Smith");
int winnings = rand() % 100000;
dict.SetIntValue("VALUE" , winnings);
// 设置模板中的片断
// 创建表格:10 行
for (int i = 0; i < 10; i++)
{
TemplateDictionary *dict1 = dict.AddSectionDictionary("IN_TABLE");
dict1->SetValue("ITEM", "Lihaibo");
dict1->SetFormattedValue("TAXED_VALUE", "%.2f", winnings * 0.83);
}
// 允许显示表格内容
dict.ShowSection( "IN_TABLE" );
// 创建 dict 模板的子模板
TemplateDictionary *dict3 = dict.AddIncludeDictionary("INCLUDED_TEMPLATE");
// 设置子模板文件名
dict3->SetFilename("include.htm" );
// 替换子模板中的标记
dict3->SetValue("INCLUDE_VAR", "This is a include template.");
// 根据 test.htm 页面模板创建 HTML 页面,并返回
return ExpandTemplate("test.htm", DO_NOT_STRIP, &dict, out);
}
三、使用 acl::HttpServlet 类编写 HTTP 处理过程
#include "lib_acl.hpp"
#include <string>
class http_servlet : public acl::HttpServlet
{
public:
http_servlet(void)
{
}
~http_servlet(void)
{
}
// HTTP GET 请求过程
virtual bool doGet(acl::HttpServletRequest& req, acl::HttpServletResponse& res)
{
return doPost(req, res);
}
// HTTP POST 请求过程
virtual bool doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res)
{
// 获得 session
const char* sid = req.getSession().getAttribute("sid");
if (sid == NULL || *sid == 0)
req.getSession().setAttribute("sid", "xxxxxx");
sid = req.getSession().getAttribute("sid");
// 取得浏览器 cookie
const char* cookie = req.getCookieValue("name");
// 取得请求参数
const char* param = req.getParameter("name");
// 创建 HTTP 响应头过程
// 添加 cookie
res.addCookie("name", "value");
// 以 acl_master 框架控制方式或单独服务运行时必须设置状态位
res.setStatus(200);
// 设置 Content-Type 字段
res.setContentType("text/html");
// 设置字符集
res.setCharacterEncoding("gb2312");
std::string buf;
create_html(&buf, sid, cookie, param); // 生成 HTML 页面
// 发送 http 响应头
if (res.sendHeader() == false)
return false;
// 发送 http 响应体
if (res.getOutputStream().write(buf.c_str(), buf.length()) == -1)
return false;
return true;
}
};
int main(void)
{
http_servlet servlet;
servlet.doRun("127.0.0.1:11211"); // 开始运行,并假设 memcached 监听于 127.0.0.1:11211
return 0;
}
由上面的例子可以看出,使用 acl::HttpServlet 类库及 ctemplate 模板库编写 WEB 应用还是比较简单的,这是一种典型的 MVC 的设计示例,要比传统的 CGI 编程简易不少而且功能更为强大。
下载:http://sourceforge.net/projects/acl/
svn:svn checkout svn://svn.code.sf.net/p/acl/code/trunk acl-code
github:https://github.com/acl-dev/acl/
QQ 群:242722074
国内镜像:http://git.oschina.net/zsxxsz/acl/tree/master
微博:http://weibo.com/zsxxsz/
用C++实现类似于JAVA HttpServlet 的编程接口
使用 acl_cpp 的 HttpServlet 类及服务器框架编写WEB服务器程序
更多文章...
模板引擎参考文章: