‹  返回课程

使用模板输出HTML

课文
阅读量:610
技术范畴
请理解文字课程中提到的MVC的思想。
课前导言
请理解文字课程中提到的MVC的思想。
使用模板输出HTML
通过大器框架、方便的向前端浏览器输出来自模板文件HTML

2.1 不良设计:在C++代码中,硬编码HTML

MVC: 模型 | Model、视图 | View、控制器 | Controller 是一种软件设计典范,它被广泛地、成熟地运用在长达20多年的Web系统编程。

 

MVC结构下最重要的设计思想,就一句话:基础数据(Model)、逻辑控制(Controller)和展现交互界面(View) 要分开一点。

在Web应用中,网页的内容,是典型的“View”的角色,重点负责“展现和交互”。通常它由控制器结合业务逻辑,将处理后的业务数据,“填充”到展现模板。

但是,早先的WEB刚到来人间,可没有这些理论,模型、视频、业务逻辑常常混合在一起。更有意思的是,在本地应用或C/S结构下的C 端,也就是“客户端”,C/C++程序都是直接上手,在屏幕上“画出”界面,技术很难,工作很累,但C/C++都干得不错。到了B/S结构,后端的C/C++程序不负责“画图”,只是生成字符串(HTML),然后交给浏览器“画出”界面(浏览器当然也是C/C++主力);后端的C/C++程序(当然,主要是程序员)却觉得生成一堆字符串太难了……于是退出Web编程。

时代变了,今天不管后台是什么编程语言,基本都不用为生成HTML而直接处理字符串;但有些事不知苦就不懂甜;因此今天我们先来忆苦思甜。

 

放心:完全是浅尝辄止,不会真苦到大家。

 

在上一节的基础上,我们这次希望向浏览器输出真正的HTML内容,HTML将直接在C++代码以字符串的形式存在:

#include "daqi/da4qi4.hpp"

using namespace da4qi4;

int main()
{
    auto svc = Server::Supply("127.0.0.1", 4098);

    svc->AddHandler(_GET_, "/", [](Context ctx)
    {
        ctx->Res().ReplyOk("<html><body><h1>Hello world</h1></body></html>");
        ctx->Pass();
    });

    svc->Run();
    return 0;
}

除了看起来乱了一些,确实也没有感觉到什么苦;但从些每次想修改一些展现格式(布局、字体、颜色等),都得修改C++代码,然后还得编译,而C++的编译速度比较慢;这倒是仅人心烦。

说到字符串,转义符算是一件仅程序员闹心的事,还好C++11有“Row String Literals”(原始字符串字面量),在这里我们可以用上。因为我们这次想让“Hello world”变成蓝色,而在HTML里,这通常需要用到双引号:

#include "daqi/da4qi4.hpp"

using namespace da4qi4;

int main()
{
    auto svc = Server::Supply("127.0.0.1", 4098);

    svc->AddHandler(_GET_, "/", [](Context ctx)
    {
        std::string html = R"(<html><body><h1 style="color:blue">Hello world</h1></body></html>)";
        ctx->Res().ReplyOk(html);
        ctx->Pass();
    });

    svc->Run();
    return 0;
}

字符串更长了……我已经开始烦了。

正经做法,就是将HTML相关的内容,独立写成文件,这样需要修改展现形式,多数情况只需要修改外部文件即可。在大器框架上,我们把程序运行时,主体不变,仅需修改业务数据内容的这种外部文件,称为“模板文件”。在本课中,由于几乎没有业务逻辑,所以模板文件中几乎没有业务数据,完全都事先可定下的内容。

 

2.2 引入 “应用/Application” 的概念

一个在线商城的软件系统,通常会有两大类用户:一类是顾客,一类是商城的后台管理者。顾客还是管理者需要使用的数据“模型 | Model”有很大的重叠。比如都需要知道商品名称 、价格、数量等。因此这两类用户可以使用同一套系统(Server)。但在系统内部,二者又有一定的划分;同时也可以为二者提供一些相对独立的配置。比如安全配置、比如界面风格等等。当采用模板机制时,二者通常也各自拥有一套模板。在大器框架中,这种划分可以通过不同“应用 | Application”实现

今天我们要演示的,无关“一套服务多套应用”,仅仅是模板文件的存放位置。需要用到模板,当然需要知道模板文件存放在哪里?在大器框架中,此类配置需要通过“Application”对象实现(而不是Server)。

 

前面的所有例子中,都没有“Application ”的身影,这里因为对于简单的示例,大器框架允许我们无需手工创建应,Server会帮我创建一个应用,称为“默认应用 | DefaultApplication”。通过Server对象,可以得到这个默认应用:

auto app = svc->DefaultApp();

然后,通过app设置模板文件所在的根目录,为方便演示,直接使用绝对路径(实际项目其实也推荐使用绝对路径,只是会由外面配置读入路径的位置)。假设这个路径是“/home/tom/daqi_demo/view”(请确保该目录一定要事先存在,大器框架不会尝试自作主张创建目录),设置代码为:

app->SetTemplateRoot("/home/tom/daqi_demo/view/");

app 还有一个方法,是设置Web Server的临时路径,叫“SetTemporaryRoot()”,不要搞混二者。

知道模板文件所在路径后,再调用下面的方法,该app就会尝试从指定的路径下读出并预处理(编译为字节码)模板文件。

app->InitTemplates();

得到默认App,并且告诉它模板文件在哪里,而后由它读取并预处理其下模板文件的Server端主函数代码如下:

#include "daqi/da4qi4.hpp"

using namespace da4qi4;

int main()
{
    auto svc = Server::Supply("127.0.0.1", 4098);
    auto app = svc->DefaultApp(); //取得由Server自动创建的默认应用
    app->SetTemplateRoot("/home/tom/daqi_demo/view/");
    app->InitTemplates();
    svc->Run();
}

不过,像视频课程所演示的,我们需要在模板目录下,至少放一个模板文件,并且命名为“ index.daqi.HTML” (注意大小写);内容为:

<!DOCTYPE html>
<html lang="zh">
<head>
    <title>首页</title>
    <meta content="text/html; charset=UTF-8">
</head>
<body>
    <p>欢迎来到我的主页</p>
</body>
</html>

一切准备就緒,编译、运行程序,在浏览器地址栏内输入“http://127.0.0.1:4098/”,应可以看到一句(段)话:“欢迎来到我的主页”。如果嫌它字太小,同样可以将“<p>欢迎来到我的主页</p>”改为“<h1>欢迎来到我的主页</h1>”。这次不用改C++代码,只需重启C++写的Web Server程序即可。未来我们很快会学习如何通过一行代码调用,实现模板文件更改后(但没有改到业务数据或相关逻辑),无需重启Web Server。

 

2.3 理解“基于约定”的路由匹配

最后一段C++代码中,我们从第一节课就熟悉的“AddHandler(...)”调用临时消失了;但不管需不需要调用“AddHandler()”,我们都将广泛地使用“基于约定”的路由匹配。简单地说,就是这么一个过程:身为Web Server程序的大器框架,可以读出当前浏览器(前端)前来请求的URL是什么,假设扣除前面的服务网址,那么,凡是“xxx/yyy/zzz”的请求,大器框架就会前往模板文件目录,查找其下 “xxx/yyy/”的子文件夹内,是否存在名为“zzz.daqi.HTML”的模板文件。如果有,就直接用后者加以响应——这个过程是自动的,除非我们手工写代码处理某些例外。如果请求止于某个“/”,则有另一个约定:改为访问其下“index.daqi.HTML”的模板。

至于“AddHandler(...)”,只是临时消失。因为如果接到所有请求,都只是找到一个模板文件然后返回一成不变的模板文件,那这个网站就无需开发,事先准备好所有文件即可了——对每次请求,都完全无需更改内容就可以返回的文件,不叫模板文件,叫“静态文件”。典型的如网站的图片文件。静态文件不是这节课的演示内容。

 

大器框架支持不写任何代码,直接写好并部署好模板文件就可以访问这一功能,这里一个在实际业务中非常不常用,但在开发、调试、测试、乃至项目管理中,都能给我们带来极大的方便的功能。它源于实际一线开发的真实需求与经验。

 

下节课,我们就需要演示,在收到用户请求后,如何返回一个结过动态修改的模板内容;那时候,AddHandler(...) 将会回归。

 

课后补充
模板机制,将所有Web Server后台语言,从围着HTML生成的字符串处理工作中解放出来。你理解了吗?