C++网站开发MVC框架TreeFrog Framework教程——5.控制器

控制器是整个web程序的核心类,它接收来自浏览器的请求,以模型对象为中心调用对应的业务逻辑代码,然后根据处理结果结合模板生成最终的视图层HTML代码,最后作为响应返回给浏览器。

1.动作

所谓动作,就是根据请求的URL调用的某个与之对应的控制器成员函数。我们可以在控制器头文件中的public slots中声明动作,其他地方声明的任何函数都将不会被视为动作。动作可以接收最多10个参数,这些参数的类型一般为QString

class T_CONTROLLER_EXPORT FooController : public ApplicationController
{
    Q_OBJECT
     :
public slots:   //这里开始就是动作的定义
    void bar(); 
    void baz(const QString &str);
     :

2.动作与URL的匹配

请求的URL和实际调用的动作之间的匹配规则如下:

/控制器名称/动作名称/动作参数1/动作参数2/…

因为动作最多只能接收10个参数,所以如果真的需要传输10个以上的参数,可以考虑使用URL参数或者POST数据,下面会介绍相关的用法。
下面就是若干个匹配的例子:

 /blog/show        →  show();
 /blog/show/2      →  show(QString("2"));
 /blog/show/foo/5  →  show(QString("foo"), QString("5")); 

如果省略了动作名,那么默认会匹配index这个动作,也就是说会像下面这样:

/blog   →  index();

如果根据URL找不到对应的动作,那么将会返回500状态码(服务器内部错误)给浏览器。

3.动作的标准处理流程

  1. 请求解析
  2. session或者cookie中提取数据
  3. 处理好上传的文件
  4. 调用逻辑层(业务逻辑)
  5. 根据处理结果把数据传给视图层
  6. 把最终生成的HTML代码作为响应返回给浏览器

其中,需要特别留意的是不能把大量的业务逻辑代码放在控制器,这样会控制器显得臃肿复杂,况且TreeFrog为我们提供了十分方便好用的模型层,我们应该把主要的业务逻辑代码放到那里运行。

总之,记住这么一条铁律:控制器的代码要少而清晰。

4.请求对象

TreeFrog中,HTTP请求被封装为THttpRequest对象,我们可以通过调用控制器的httpRequest()方法来获得它,然后再提取出我们想要的数据。

const THttpRequest & TActionController::httpRequest () const;

5.从请求对象中获取数据

连同HTTP请求一起传过来的数据一般有以下几种:

  1. POST数据:一般是整个表单的数据被POST过来
  2. URL参数:一般位于整个URL的最后,格式类似于:?键名1=值1&键名2=值2...
  3. 动作参数:也是位于整个URL的最后,前面提到过,格式类似于:/动作名称/动作参数1/动作参数2/…

5.1.获取POST数据

假设浏览器前端有如下的文本框,并且它的内容连同HTTP请求一起发送到后台:

<input type="text" name="title" />

那么我们可以这样获得它的内容:

QString val = httpRequest().formItemValue("title")

如果你觉得通过反复调上面的函数拿到一个个POST数据十分麻烦的话,可以像下面这样编写网页:

<input type="text" name="blog[title]" />
<input type="text" name="blog[body]" />

然后在控制器中,可以拿到存储参数键值对的哈希表,然后再逐一取出数据:

QVariantMap blog = httpRequest().formItems("blog");
QVariant t = blog["title"];
QVariant b = blog["body"];

5.2.获取URL参数

如果浏览器端发送过来的请求URL如下:

http://example.com/blog/index?mode=normal

如果我们想取得mode的值,那么可以通过下面的方法:

QString val = httpRequest().queryItemValue("mode");

顺带一提,如果想把POST数据和URL参数不加区别地统一获取,可以使用parameter()或者allParameters()方法。

6.往视图层传输数据

如果要往视图层传输数据,可以通过宏定义texport(变量名)或者T_EXPORT(变量名)来声明。这些数据变量只要是可以通过类型转换为QVariant都可以,比如intQStringQListQHash或者自定义的模型类。用法如下:

QString foo = "Hello world";
texport(foo);

//或者

int bar;
bar = …
texport(bar);

注意:texport的参数必须为变量,不能是Hello world或者100等字面量。
在这之后,视图就可以通过声明tfetch(变量类型,变量名),然后使用该变量。

7.往视图层传输类对象

首先要在这个自定义类的头文件的末尾增加下面的宏定义:

Q_DECLARE_METATYPE(自定义类的名称)

一般的QT类是不需要加上Q_DECLARE_METATYPE宏定义的,但是对于QListQHash等模板类却是例外。这种情况下,可以在helpers/applicationhelper.h文件的末尾加上类似于下面的代码:

Q_DECLARE_METATYPE(QList<float>)

如果Q_DECLARE_METATYPE宏定义里面有逗号(比如QHash<Foo, Bar>),那么将会造成编译错误。这种情况下,可以考虑使用typedef关键字。

typedef QHash<Foo, Bar> BarHash;
Q_DECLARE_METATYPE(BarHash)

8.生成视图

在执行完业务逻辑之后,就差不多可以生成HTML代码响应请求了。例如对于BlogControllershow动作,当我们调用render()方法时,就会根据views/blog/show.xxx模板文件生成最终的HTML页面(后缀名与当前使用的模板系统相对应)

bool render(const QString &action = QString(), const QString &layout = QString());

如果想使用别的模板文件,可以通过renderaction参数来改变。

9.render方法的layout参数

对于绝大多数的web程序,各个页面的头部(导航)、尾部(友情链接)基本都是相同的,只不过是网页的中间内容有所不同而已。所以layout就是指这些各个页面可以共用的模板,它们一般存放在views/layouts目录下。

10.关于模板文件的命名

  • ERB系统:xxx.erb
  • Otama系统:xxx.htmlxxx.otm(xxx是默认匹配的动作名称)

11.直接返回字符串作为响应

这种情况下,可以使用renderText()方法:

renderText("Hello world");

12.重定向

将本身属于自己的请求移交别的URL处理,可以使用redirect()方法。

//重定向到www.example.org
redirect(QUrl("www.example.org"));

或者移交给其他动作执行,写法如下:

//重定向到Blog控制器的index动作
redirect( url("blog", "index") );

如果和重定向的目标动作同属于一个控制器之下,可以省略控制器名

//重定向到同一个控制器的show动作
redirect( urla("show") );

13.往重定向目标发送消息

TreeFrog框架中,可以往重定向目标发送消息,具体做法就是调用tflash或者T_FLASH方法。

//设置foo为flash对象
QString foo = "successfully";
tflash( foo );

上面发送过去的foo变量被称为flash对象(消息),此后,重定向目标的视图层可以把它当做导出数据来使用。

14.staticInitialize方法

如果想在程序启动的时候执行一段代码(比如:预先从数据库中读取初始数据),可以在ApplicationControllerstaticInitialize方法里面写:

void ApplicationController::staticInitialize()
{
    // do something..
}

15.控制器的生命周期

控制器的实例会在,动作被执行之前被生成,动作执行之后就被销毁。因此,对于每一个HTTP请求都会生成并销毁一个控制器实例。因此持有一个控制器的引用或者指针是很不明智的做法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值