cinatra模板引擎使用

渲染一个简单的html模板

通过render_view这个接口 第一个参数是模板文件的相对路径 这样我们就可以给客户端返回一个html页面了

在当前模板中包含其他的模板文件
我们有一个test.html 和一个header.html 内容分别如下

服务器代码如下

这样我们就可以在业务中复用公用的模板文件 通过不同的数据去渲染想展示的内容

需要通过数据去渲染的页面
我们有一个data.html的文件 内容如下

如上使用 就能轻松的通过需要的数据渲染出一个页面

通常我们展示前端页面的时候都会需要对一个list的数据进行渲染 同样cinatra的模板也支持我们开发相关的业务
我们有一个list.html的文件,内容如下

我们可以在cinatra里面写上这么一个接口

是不是很轻松的就能完成我们的业务了

cinatra模板引擎同样支持if判断
我们有一个study.html的文件,内容如下

我们可以通过传递display=0或者1来看内容是否显示

以上列举了一些cinatra中常用的一些方法 更多的功能 大家可以在cinatra群里面一起交流学习

cinatra发布新版本

cinatra发布v0.04版本

这仍然是一个预发布版本,增加了一些有用的功能和改进了接口的易用性,欢迎大家试用!

modern c++做web开发给你飞一般的感觉!

最近改进的几个地方

cinatra本次改进增加了http缓存和更友好的html渲染接口:

示例

1.http缓存

这样就可以实现缓存了,这里设置的是全局缓存,即所有的http get请求都会缓存。

如果希望某些请求不缓存该怎么做呢?设置一个enable_cache参数即可:

这样就可以实现某个请求不缓存,除此之外的缓存。

2. 更友好的html渲染接口

如何实现函数参数过滤

需求

过滤传入的函数参数。假设传入了int, bool, double, bool, structA这几个参数,现在我需要把其中的bool参数去掉,只保留非bool的参数,因此输入的参数经过过滤之后就变成int, double, structA了。

如何实现这个需求,请大家把实现的代码发在文后,看看谁实现得最好,期待精妙的代码。

注意

评论的时候展示代码的话需要用一个代码格式,否则显示不正常,要类似于这样在代码外面套一个脚本:

pre class=”lang:c++ decode:true “

cinatra最新的改进

最近改进的几个地方

cinatra本次改进主要侧重于易用性和灵活性,主要增加了下面几项功能:

  1. response时自动添加对应的mime type
  2. 支持中文
  3. 内置小的静态资源获取
  4. 支持pathinfo/*

示例

1.response时设置mime type

2.中文

3.pathinfo

4.静态资源获取

purecpp社区寻求赞助和捐赠

purecpp社区的朋友们:

非常感谢大家对purecpp社区的热爱和支持,你们的支持对于purecpp社区很重要,对于modern c++很重要。

近来频繁出现了社区网站挂掉的情况,主要原因是在云主机有限的配置下资源占用过大导致的。由于社区现在是基于wordpress(php)改造的,所以性能和并发量非常有限,因此我计划将社区网站从php更换为c++的feather,feather的性能是php的数十倍,相信社区更换为feather之后,在相同资源的情况下,能够在很长一段时间内满足使用需求。

除了更换社区框架之外还需要对云主机进行升级,需要购买新的云主机,因此需要大家赞助或捐赠,金额不限,只要能维持社区网站的正常运行即可。捐赠者名单和金额也将在社区定期公布,当然如果你不希望公布自己的捐赠信息可以在捐赠的时候注明一下。

捐赠方式:微信和支付宝
微信:
weixin

支付宝:
zfb

Feather–一个快速开发的web服务器框架

Feather是一个适合快速开发的modern c++ web框架,Feather的目标是让使用者以最小的精力和成本来开发一个web网站。

现在很多web框架都非常庞大,学习成本高,而Feather正是为了解决这些问题的,它就像它的名字feather那样轻盈,所有的一切都是为了让用户非常方便又快速地开发而不是陷入到框架的细节当中。

一个好的框架应该是能让用户轻松实现自己的想法而不是成为框架的奴隶。如果你希望轻松快速地开发一个web网站,而无需花费大量的精力去学习框架细节的话,那么Feather非常适合你!

Feather是什么?

Feather作为一个快速开发框架,它的目标是让web开发变得简单。它主要有下面几个特点:

  1. 简洁易用
  2. 高性能,modern c++(c++17)开发
  3. header only
  4. 跨平台
  5. 支持编译期反射
  6. 支持AOP

Feather框架的核心包括:
1. 一个易用的http库,支持http1.x, https, websocket
2. 一个功能强大的html模版引擎
3. 一个可扩展的ORM库,支持多种数据库(mysql,postgresql,sqlite)
4. 一个可扩展序列化库,支持多种格式(json, xml)

Feather的架构

下面是Feather的架构图:

Feather的架构图

Feather内部的四个核心组件是松耦合的,Feather只是把它们像搭积木一样搭在一起。

  1. http组件: cinatra
  2. ORM组件: ormpp
  3. 序列化组件: iguana
  4. html 模版: inja

Feather的使用

以一个简单的例子展示如何使用Feather,比如显示文章列表,几乎每个网站都有这个功能。

获取文章列表的功能很简单,它底层数据部分是一个文章表,业务逻辑层是获取这些列表,然后做html渲染。对外接口部分是一个http服务,前端后端交互的数据格式为json。为了简单起见就不考虑缓存之类的。

那么要实现这个文章列表功能用Feather怎么做呢?可以按照这些步骤去开发:

  1. 提供获取文章列表的http接口;
  2. 通过ORM提供数据库访问功能;
  3. 编写业务逻辑,根据用户请求获取文章列表并通过html模版做渲染;

接下来看看这些步骤具体是怎么做的。

获取文章列表的http接口

其中login接口是这样的:

接下来就可以测试这个http服务接口了,客户端只要发送一个http请求即可。比如发送一个这样的请求

http://127.0.0.1/get_article_list

服务器会自动路由到article_controller::get_article_list函数中,如果请求不对则会返回http错误给客户端。当服务器收到这样的请求之后就表明服务器提供的这个http服务是可用的。

接下来需要编写数据库部分的代码,由于有了ORM,所以你可以很方便地编写数据库部分的代码了,同样很简单。

通过ORM提供数据库访问功能

登录业务涉及到一个用户表,因此我们需要创建这个表,不过在创建数据库之前先确定你选用什么数据库,Feather的ORM支持mysql, postgresql和sqlite三种数据库,假设我们的数据库是mysql。我们可以通过下面的代码来创建一个用户表。

1.创建文章表

dao.create_table< article >将会在testdb数据库中自动创建一个article表,其中id字段是自增长的。

2.编写获取文章列表的逻辑(包含访问数据库)

访问数据库,序列化为json返回给客户端。

详细的例子你可以看github上的代码

Demo示例

我们用Feather开发了一个社区网站,地址在这里:http://120.78.135.113:8080/

Feather社区

致谢

Feather社区网站由我和网友XMH共同开发完成(花了两天的业余时间),XMH也是cinatra的忠实用户,不但贡献了很多代码,还提供了很多宝贵的建议,在此表示衷心的感谢!

XMH是一名热爱编程的程序猿,平时从事c++,web,移动端等开发。从事过游戏后台和APP开发。也是个忠实的mordern c++粉丝,追随着cpp的发展,喜欢通过元编程做一些小工具。热爱开源社区,也是开源项目feather的使用者,希望feather能为更多的开发者所使用,社区发展越来越好。

希望有更多人能加入进来把Feather完善得更好。

联系我们

purecpp@163.com

http://purecpp.org/

https://github.com/qicosmos/feather

推荐下本人的无栈协程库librf

https://github.com/tearshark/librf

librf

librf – 协程库

librf是一个基于C++ Coroutines提案 ‘Stackless Resumable Functions’编写的非对称stackless协程库。

目前仅支持:
Windows (使用2017编译)(由于使用了SFINAE导致不再支持VS2015)

librf有以下特点:

  • 1.基于C++17提案’Stackless Resumable Functions’编写的非对称stackless协程库,可以以同步的方式编写简单的代码,同时获得异步的性能
  • 2.理论上支持海量协程, 创建100万个协程只需使用物理内存
  • 3.提供协程锁(mutex), 定时器, channel等特性, 帮助用户更加容易地编写程序
  • 4.可以很好的跟asio,libuv等库结合,能跟现有的callback范式的异步/延迟代码很好的结合
  • 5.目前还处于实验状态,不对今后正式的C++ Coroutines支持有任何正式的承诺

  • 如果你发现了任何bug、有好的建议、或使用上有不明之处,可以提交到issue,也可以直接联系作者:
    email: tearshark@163.net QQ交流群: 296561497

  • doc目录下有作者搜集的一些关于C++协程的资料

  • tutorial目录下有针对每个特性的范例代码,让用户可以循序渐进的了解librf库的特性

一个更好的自动注册工厂

在几年前我介绍过一种C++11实现的自动注册工厂,这是工厂模式的一种优雅的实现。在这里我们需要明确一个概念就是工厂模式,它是如何优雅地解决一个产品族的创建问题。所谓产品族就是一个继承体系的产品,比如有一个产品Message,它是一个基类,有很多Message是从它派生而来的,比如有Message1,Message2,Message3…等很多产品。

这些产品的创建依赖于某个key,类似于这样:

这是一个典型的工厂方法,这种写法在产品不多的时候是没问题的,但是如果产品越来越多的时候,switch-case就会越来越长,导致难以维护。另外还存在一个问题,有的产品不是无参数的构造函数,如果有些产品依赖了不同的参数,那么这个工厂方法是无法满足需求的。

之前介绍的自动注册工厂解决了switch-case膨胀的问题,但是对于需要参数的产品的创建没有解决得很好,需要进一步改进。改进的办法是把参数作为factory的模板参数,这样就可以解决有参数需求的问题了。

下面是具体实现:

这是一个Messgae产品族的工厂类,有了这个类之后我们就可以很方便地创建各种产品了。下面是测试例子:

Message产品族有4类产品,有的是无参的,有的是多个参数的产品,现在都可以统一创建了,直接输入key和构造参数即可,这个key可以自行修改为int或者枚举变量。

需要注意的是msg4,因为它注册的时候提供了一个function,让function提供创建功能,以满足更灵活地需求。

有了这样一个工厂类之后我们就可以很好地解决产品族创建的问题了。你还可以基于此把它改成一个抽象工厂类,但我觉得你应该慎重考虑一下是否有必要,一般情况下工厂模式就够了,不需要引入更多的复杂性。

tensorflow variant源码分析

tensorflow variant基本语义

通过分析tf.variant的源码可以知道它其实是一个any语义,即这个类型可以被任意类型赋值,它的主要目的就是做彻底的类型擦除。

这个名字取得有迷惑性,它和标准库和boost库中的variant语义是不一样的,而是和c++17中的std::any对应的。

tf.variant用法

可以从tf的测试代码中知道它的基本用法,用法很简单:

从这个测试代码中可以看到tf.variant和std::any/boost.any用法是差不多的。

tf.variant内部有一个unique_ptr指针, 默认为nullptr,所以没有赋值的时候总是返回nullptr。

Int(42)赋值给variant之后,就可以通过get(x)来获得Int指针了,接着就可以得到其实际的Int值了;因为这个Variant是any语义,所以任意类型比如Tensor也可以复制给它,取值方法也是类似的,先取T指针,接着调用value得到初始值。

注意,这里的get中类型必须和赋值时候的类型一致,不一致的时候会返回nullptr(除了void,传void时会返回void*指针);

any和variant比较

之前介绍过vairant,知道它也是用来做类型擦除的,不过variant擦除的类型是有限个的,必须要事先指定,它只能实现部分的类型擦除。

而any也是实现类型擦除的,它可以代表任何类型,不需要像variant那样需要事先确定擦除的类型,看起来更方便更强大了。

事实上这个any并不是变得更强大了,它虽然能彻底擦除类型,但是,在取值的时候需要知道准确的类型,这反倒不如variant方便了,variant在取值的时候通过一个visitor是不需要知道具体类型的。

二者的本质区别是类型擦除方式不一样,variant是通过栈上的一个定长内存块去保存赋值对象的,variant中所有的类型共用这块buffer,而any是通过派生,在堆内存上创建一个实际的对象,并且每次赋值都会析构之前的对象,重新在堆内存上重新创建一个新对象。

所以从性能上说variant的效率是高于any的,二者效率大约相差4倍左右。 附一个测试代码:

所以能用variant就不用any,除非真的需要擦除所有的类型,或者是为了追求代码更简单不太在意性能的时候可以用any,大部分情况下用variant擦除部分类型就可以满足需求了。

any的一个典型应用场景就是http服务器中的session,这个session是保存用户在服务器端的数据的,这个数据类型可能是字符串,数值,或者用户自定义的对象,在这种情况下无法定义一个variant,这时候用any是合适的。

tf.variant的实现

tf.variant的实现思路

tf.variant的实现思路实际上就是any的实现思路,any对象内部有一个内部基类的unique_ptr,这个基类有一个带模版参数的派生类。

这个派生模版类是泛型的,用它代表所有类型。

当给any对象赋值的时候,我们就创建这个派生类对象,这个对象保存了实际的类型。

在后面取值的时候我们就可以将这个基类向下转型为某个具体的派生类对象了,这时需要判断当前保存的对象类型和传入的类型是否一致,不一致则返回nullptr。

any

tf.variant的源码实现

1.内部定义一个抽象类和一个派生模版类

2.定义一个成员变量,内部接口类的指针–std::unique_ptr< ValueInterface > value_;

3.赋值时创建派生类对象

赋值的时候对赋值类型做了限定,必须为非Variant的,并且有拷贝构造函的类型,因为any内部会重新创建这个对象,之后赋值给基类指针value_,同时实现了类型擦除。

4.取值

取值的时候会判断是否初始化以及类型是否匹配,满足条件就转成实际的类型,否则返回nullptr。

这个代码的实现还是比较简单的,就是实现了一个基本的any语义,还有一些自己扩展的部分,比如encode和decode之类的。

总结

tf.variant本质上就是一个any,用来做类型擦除,像c#,java中的object那样代表一个通用类型。

在tensorflow中很多时候是作为一个函数参数,有些这样代码:

目前还没进一步分析tf的代码,我猜测这样做的目的可能是为了统一的接口以及灵活性,接口可以保持通用不变,具体实现将因具体类型不同而各有不同,方便扩展。