Chinaunix

标题: 发布一个比较老旧的Web开发C++类库 [打印本页]

作者: pi1ot    时间: 2012-05-28 17:10
标题: 发布一个比较老旧的Web开发C++类库
本帖最后由 pi1ot 于 2012-06-05 12:33 编辑

发布一个比较老旧的Web开发C++类库

代码地址:
https://code.google.com/p/webapplib/
https://github.com/pi1ot/webapplib

简单说明:
WebAppLib是一系列主要用于类Unix操作系统环境下WEB开发的C++类库。设计目的是通过提供使用简单方便、相对独立的C++类和函数来简化CGI程序开发过程中的常见操作,提高开发效率。

背景介绍:
这个类库已经非常老旧了,是我03年到05年间开发维护的,05年之前曾应用于多个新浪项目,包括当时的论坛、聊天、用户库、CMS等,05年后随着新浪前端应用开发全面转向PHP,逐渐没人用了,现在大概只剩下少数历史比较悠久的项目还在继续使用吧。一开始是作为本人学习C++的练手项目开始的,后来用的人逐渐增多,其间陆陆续续升级了七八个版本,应该说大部分代码的稳定性已经经历过了考验,考虑到一点点个人感情因素,现在简单整理一下发布出来,没有任何使用上的限制,大概也不会有后续更新。这次发布之前做了一下整理,重构了一些类库和函数的命名,删除了很多已经证明并不需要的冗余接口。

建议:
现在Web开发的主流显然不是C++,不过如果你想学习或者了解一下CGI开发的细节,可以作为参考,或者如果你已经有一个以C++为主体代码的项目,需要一点简单的Web包装,又不想学习或者引入一门新的脚本语言,可以试试看这个WebAppLib

其他:
webapp::String 的实现,受当时知识水平的限制,为了能沿用 std::string 的全部接口,是 public 继承自std::string的,现在看来显然不是一个说得过去的方案,只是在那几年的使用场景中,似乎也没有发现有不稳定的情况,所以现在懒得去修改了,各位自行决定是否使用吧。
附说明,摘自《Effective C++》
条款14: 确定基类有虚析构函数:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。

类库和函数列表:
String继承并兼容与std::string的字符串类,增加了开发中常用的字符串处理函数
Cgi支持文件上传的CGI参数读取类
CookieHTTP Cookie设置与读取类
MysqlClientMySQL数据库连接类,MySQL连接处理C函数接口的C++封装
MysqlDataMySQL查询结果数据集类,MySQL查询结果数据提取C函数接口的C++封装
Template支持在模板中嵌入条件跳转、循环输出脚本的 HTML 模板类
HttpClientHTTP/1.1通信协议客户端类
DateTime日期时间运算、格式化输出类
TextFile固定分隔符文本文件读取解析类
ConfigFileINI格式配置文件解析类
FileSystem文件系统操作函数库
Encode字符串编码解码函数库
Utility系统调用与工具函数库


简单范例:
  1. /// \file example.cpp
  2. /// 代码示例文件,演示一个简单CGI流程

  3. #include <iostream>
  4. #include "webapplib.h"

  5. using namespace webapp;

  6. int main() {
  7.         /***************************************************************************
  8.         演示完整的CGI应用程序流程,模拟WEB查询动作       
  9.         1、读取CGI参数和Cookie数据(String、Cgi、Cookie)
  10.         2、使用读取到的参数调用权限检查接口(ConfigFile、HttpClient)
  11.         3、使用读取到的参数查询数据库(MysqlClient)
  12.         4、使用日志文件记录用户请求(FileSystem、Utility、Encode)
  13.         5、更新用户端Cookie(Cookie、DateTime)
  14.         6、显示HTML页面(Template)
  15.         ***************************************************************************/       

  16.         ////////////////////////////////////////////////////////////////////////////
  17.         // 1、读取CGI参数和Cookie数据(Cgi、Cookie)
  18.        
  19.         Cgi cgi;
  20.         Cookie cookie;
  21.         String username = cgi["username"];
  22.         String usercookie = cookie["usercookie"];
  23.        
  24.         /*提示 webapp::Cgi在读不到CGI环境变量时会运行在调试模式,提示输入CGI参数值*/
  25.        
  26.         ////////////////////////////////////////////////////////////////////////////
  27.         // 2、使用读取到的参数调用权限检查接口(ConfigFile、HttpClient)
  28.        
  29.         ConfigFile conf( "example.conf" );
  30.         String check_interface = conf["check_interface"];
  31.        
  32.         cout << "---------------------------------------------------------" << endl;
  33.         cout << "check user privilege from:" << check_interface << endl;
  34.        
  35.         HttpClient www;
  36.         www.request( check_interface + "?username=" + username );
  37.         if ( www.done() && www.content()=="CHECK_PASS" ) {
  38.                 cout << "check pass" << endl;
  39.         } else {
  40.                 cout << "check fail" << endl;
  41.         }
  42.        
  43.         ////////////////////////////////////////////////////////////////////////////
  44.         // 3、使用读取到的参数查询数据库(MysqlClient)
  45.         String value;
  46.         #ifndef _WEBAPPLIB_NOMYSQL

  47.         String sql;
  48.         sql.sprintf( "SELECT value FROM table WHERE user='%s'", escape_sql(username).c_str() );
  49.        
  50.         MysqlClient mysqlclient;
  51.         MysqlData mysqldata;

  52.         mysqlclient.connect( "example.mysql.com", "user", "pwd", "database" );
  53.         if ( mysqlclient.is_connected() ) {
  54.                 if ( mysqlclient.query(sql,mysqldata) ) {
  55.                         value = mysqldata( 0, "value" );
  56.                 } else {
  57.                         cout << mysqlclient.error() << endl;
  58.                 }
  59.         }

  60.         #endif //_WEBAPPLIB_NOMYSQL

  61.         ////////////////////////////////////////////////////////////////////////////
  62.         // 4、使用日志文件记录用户请求(FileSystem、Utility、Encode)
  63.        
  64.         String log_path = "/tmp/";
  65.         String log_file = log_path + "/logfile.txt";
  66.         if ( !file_exist(log_path) || !is_dir(log_path) ) {
  67.                 make_dir( log_path );
  68.         }

  69.         file_logger( log_file, "username:%s", username.c_str() );
  70.         file_logger( log_file, "usermd5:%s", md5_encode(username).c_str() );
  71.        
  72.         cout << "---------------------------------------------------------" << endl;
  73.         String file_content;
  74.         file_content.load_file( log_file );
  75.         cout << file_content << endl;

  76.         ////////////////////////////////////////////////////////////////////////////
  77.         // 5、更新用户端Cookie(Cookie、DateTime)
  78.        
  79.         DateTime now;
  80.         DateTime expires = now + ( TIME_ONE_DAY*3 ); // Cookie有效期为三天
  81.         cookie.set_cookie( "username", username, expires.gmt_datetime() );
  82.        
  83.         ////////////////////////////////////////////////////////////////////////////
  84.         // 6、显示HTML页面(Template)
  85.        
  86.         Template page("example.tmpl");
  87.         page.set( "username", username );
  88.         page.set( "value", value );
  89.        
  90.         // 显示查询结果
  91.         cout << "---------------------------------------------------------" << endl;
  92.         http_head();
  93.         page.print();
  94. }
复制代码
代码中使用的配置文件和模板文件
example.conf
  1. # comments
  2. check_interface = http://example.com/check
复制代码
example.tmpl
  1. welcome {{$username}}!
  2. you query result is here:
  3. {{$value}}
复制代码

作者: walleeee    时间: 2012-05-28 17:17
比wt如何?
作者: pi1ot    时间: 2012-05-28 17:30
刚搜了一下你说的wt,我感觉大概唯一能和它相提并论的就是...我的文档也是用doxygen生成的
作者: walleeee    时间: 2012-05-28 18:08
回复 3# pi1ot


你用doxygen?唔,这是一个好东西。
作者: AD8018    时间: 2012-05-28 19:32
刚看了下wt,写那库的人脑子不好!
非常的不好!

前端的GUI,用后端C++生成,简直化玉帛为糟糠。




作者: nizvoo    时间: 2012-05-28 21:26
代码相当工整啊。
作者: walleeee    时间: 2012-05-28 23:00
回复 5# AD8018


cgi一向就是这个逻辑。凑合吧。看起来还是不错。
作者: AD8018    时间: 2012-05-29 09:53
回复 7# walleeee

cgi妄图入侵html内部元素,从来没成功过。

在C/C++写成的浏览器的基础了,有了WEB界面,
程序员本应该享受用WEB实现界面的便捷性。
这个倒好,重新将WEB界面用cgi包装,还是C++的,说作者脑子进水不为过。

cgi用来当生成某文本的途径比较好,
再接上一点数据格式的支持,比如json之类,就足够好。


   
作者: aychxm    时间: 2012-05-29 10:00
不然怎么表现自己是牛人呢?!
作者: reiase    时间: 2012-05-29 10:41
回复 8# AD8018


相当同意你的说法

用html做界面本来就比用C++继承来继承去方便,写两行html就能够出来的界面,干嘛非跑去写C++类

不说别的,就CU论坛这个界面,拿那个wt写写看
作者: haitao    时间: 2012-05-29 10:48
我用delphi写isapi已经是够老土的了。。。。。。。
作者: pi1ot    时间: 2012-05-29 10:58
本帖最后由 pi1ot 于 2012-05-29 10:58 编辑

这里向各位介绍的webapplib,没有wt那么大的野心,在html输出上,只是提供了一个类似于其他**p语言中常见的支持if条件判断和for循环输出的模板,具体可看手册 help.chm的 webapp::Template 部分,多谢,范例如下:

条件:
  1. {{#IF $value}}
  2.     HTML Codes ...
  3. {{#ELSIF .$table_value > 0}}
  4.     HTML Codes ...
  5. {{#ELSIF %DATE}}
  6.     HTML Codes ...
  7. {{#ELSIF some_string!=%BLANK}}
  8.     HTML Codes ...
  9. {{#ELSIF AND($v1==1,$v2<=2,$v3>=2)}}
  10.     HTML Codes ...
  11. {{#ELSIF OR(.$subv1==.$subv2,0!=0)}}
  12.     HTML Codes ...
  13. {{#ENDIF}}
复制代码
循环:
  1. {{#FOR $staff_table}}
  2.     COMPANY: {{.$company}},
  3.     DEPARTMENT: {{.$department}},
  4.     NAME: {{.$name}},
  5.     ID: {{.$id}},
  6.     AGE: {{.$age}};
  7. {{#ENDFOR}}
复制代码

作者: walleeee    时间: 2012-05-29 14:34
回复 8# AD8018


不是侵入,而是html这种是2端生成,一端是server,一段是client,client一般就是web browser,server可以是cgi,也可以是静态,什么都可以。现在client端的生成一般是js来做,google dark不晓得如何了。c/c++前面听说google chrome有native sdk支持了,可以跑客户端c++代码,没试验过。另外也有人尝试把python做到client里面去,不晓得如何了。
其实算:
源码->server制作->client制作->展示
这么个过程
server制作和client制作2个步骤有些部分是重合,可以此消彼长来替代,比如有时候就需要把一些计算放到client去,来减少server的压力。

cgi并非只是c++这些,cgi代表了服务器端代码。php其实也是一个cgi。
只能说c/c++做这些并非擅长,比如内存管理的问题。

webqq我看有些模块就cgi做的。cgi和生成文件有什么关系?生成提供给client的代码难道不算是生成文件?json和是不是cgi有什么关系?json不就一个数据格式描述,和你用不用cgi有什么关系?你cgi难道不可以构造发送json?

我觉得你是不是把js和cgi搞混了?也就是client和server搞混了?
作者: walleeee    时间: 2012-05-29 14:39
回复 10# reiase


莫放屁,你根本不懂。

你根本没Cgi的概念。
作者: aychxm    时间: 2012-05-29 14:54
walleeee 发表于 2012-05-29 14:34
回复 8# AD8018

cgi并非只是c++这些,cgi代表了服务器端代码。php其实也是一个cgi。
只能说c/c++做这些并非擅长,比如内存管理的问题。


我的理解,c似乎比php更擅长内存管理!你这里我不太明白,请指教
作者: AD8018    时间: 2012-05-29 15:15
walleeee 发表于 2012-05-29 14:34
回复 8# AD8018


还是拿代码说话吧,wt的例子

  1. WPushButton *button
  2.     = new WPushButton("Greet me.", root());              // create a button
  3. button->clicked().connect(this, &HelloApplication::greet);

  4. void HelloApplication::greet()
  5. {
  6.   greeting_->setText("Hello there, " + nameEdit_->text());
  7. }

复制代码
对于熟悉HTML的人来说,用CGI printf出这样的HTML,是再方便不过的事情。
  1. printf("<button onclick='greet()'>Greet me.</button>");
复制代码
wt很明显的,将HTML的内部细节和C++搞到一起了,这个是所谓侵入。
这样做,好处是有一点,隐藏了远程过程调用的细节。
HelloApplication::greet()可以调用服务器端的代码,再将结果返回给客户端。

坏处就太明显了,HTML和C++强度耦合,
想做debug,想改下界面、想兼容某新的浏览器、想应用更新的HTML技术增进显示效果,都要出人命的。
另外还增加学习成本,要学习这些C++ Widget的class,不划算。

json和cgi没关系,只是举个例子















作者: walleeee    时间: 2012-05-29 15:30
回复 15# aychxm


    滚,你不明白关我什么是
作者: walleeee    时间: 2012-05-29 15:37
回复 16# AD8018


你那个也是cgi。

问题是你觉得两个代码有什么可比性?

前面那个有更多的控制性,而后面那个就只能是一个普通文本,那不如直接html,你又何必来print?

cgi这些有交互功能。这些都被你忽视了。

如果我要把btn显示为时间,你是不是也要写额外代码?当然,可能会看起来比wt那个简单,问题是有本质区别么?

你错了,正好是cgi才好做跨浏览器,多平台支持,你那个根本不行。

当然,我早就说了c/c++本来做这个就不是强项,而php等等都是更好的选择。

作者: ecjtubaowp    时间: 2012-05-29 21:12
顶楼主,楼主的东西是好东西。
作者: reiase    时间: 2012-06-05 09:26
回复 18# walleeee

CGI跟交互没半毛钱关系
作者: AD8018    时间: 2012-06-05 09:58
CGI何来printf?答案很简单,CGI本质上就是“写标准输出”,
web server将CGI的标准输出转成客户端浏览器收到的数据。CGI的本质就这么点。
  CGI -> web server将CGI的标准输出的数据,发到客户端
  静态HTML -> web server将HTML文件的内容,发到客户端

所以我写printf,C版的兄弟应能看得明白。
如果不明白,你要学习HTTP协议、socket、dup/dup2、fork、execv等函数的用法。

wt我倒看到它的精华了,就是远程过程调用。但是我实在无法认同这种强耦合的做法。
作者: pi1ot    时间: 2012-06-05 11:53
各位对CGI内部机理有任何疑惑请移步
https://code.google.com/p/webapplib/source/browse/trunk/waCgi.cpp
或者
https://github.com/pi1ot/webapplib/blob/master/waCgi.cpp
多谢

作者: reiase    时间: 2012-06-05 12:29
回复 21# AD8018


其实wt的做法很好理解,无非就是给GUI库换一个后端而已。GUI控件库的后端分两块,一块处理渲染,一块处理事件
比如GTK有基于canvas的图形后端,把Gtk的GtkBuilder文件想办法从xml转换成html就可以在浏览器里显示;Qt有X11、win32等多种事件的后端,加入一个基于websocket的后端就可以模拟事件啊,回调啊

wt可能会适用于某些特别的场景吧,但是不看好。
作者: pi1ot    时间: 2012-06-05 12:34
本帖最后由 pi1ot 于 2012-06-05 12:36 编辑
reiase 发表于 2012-06-05 12:29
回复 21# AD8018


明说吧,我干了十年门户网站了,真没见过这么干的。
企业网站我不知道。
貌似google一js库有后端“遥控”前端生成代码的功能,我不了解。
作者: reiase    时间: 2012-06-05 12:43
回复 24# pi1ot


google有,从java转js。传说gmail用过。貌似ms也有把.Net界面显示在浏览器里的技术。
我觉得wt这种东西可能在erp上能够用吧。不过专门搞Web的不喜欢,不搞Web的倒可能挺崇拜
作者: AD8018    时间: 2012-06-05 13:55
估计除了他自己,没人喜欢这么干。
典型的OIOIC类型的项目。

作者: walleeee    时间: 2012-06-05 17:56
回复 20# reiase


笑死我了

不根本不懂,你甚至连http都不懂。
作者: reiase    时间: 2012-06-06 07:30
回复 27# walleeee


    HTTP我不懂,不过小的HTTP Server我写过几个,包括支持CGI调用的
作者: AD8018    时间: 2012-06-06 10:11
reiase 看来跟我是一个套路过来的。
我写过HTTP server,做过网页。

现在客户端javascript如此的强大,wt已经没有市场了。
在不太遥远的N年前,XMLHttpRequest没普及的年代,要实现动态网页,不是那么容易。
各个浏览器做法也不同,例如IE可以动态载入js,Netscape支持server-push,
也有用一个frame藏一个长连接的做法。
反正,很难做,稳定性也很难达标。
那时候HTML的兼容度也很差。
wt在N年前这样包装,又如能将动态过程的调用做好,是会非常令人向往的。

今时不同往日了。



作者: reiase    时间: 2012-06-06 10:29
回复 29# AD8018

兼职不如专职唉,碰到专门做Web的,人家可能对CGI怎么工作不了解,不过Web后端前端框架是一套一套的。
你我的经验,也就把http当作一种RPC来用用。

我觉得Wt是“反动”的。
现在Web开发,职能越来越分化。以前分前台后台,现在前台要分美工和程序,后台要分业务和框架。
搅在一起嘛,怎么分工合作,怎么优化。

不过Wt会有市场的,毕竟有些MFC程序员偶尔也跑出来写写Web程序。
作者: walleeee    时间: 2012-06-08 22:09
回复 29# AD8018


。。。cgi和客户端没什么关系吧。。。只是要说有关系也能从侧面说的通。
javascript和Cgi根本不是干一回事情的,可能你误解我说的交互,我的意思是client/server交互,而不是js的人机交互,比如做个什么效果什么的。

wt没市场一点不奇怪,c++本身就不是设计来干这些事情的,逆天意而已。


作者: walleeee    时间: 2012-06-08 22:11
回复 30# reiase


    哈哈哈,一个笑话




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2