编程实战:自己编写HTTP服务器(系列7:用户功能接口)

初级代码游戏的专栏介绍与文章目录-CSDN博客

系列入口:编程实战:自己编写HTTP服务器(系列1:概述和应答)-CSDN博客

         本文介绍用户功能接口。

目录

一、概述

二、执行接口

三、接口设置

3.1 主要属性

3.2 CWebCommandParam

3.3 添加参数

3.4 生成form


一、概述

        作为通常的执行功能的接口,一般就是三个功能:初始化、执行、退出(清理)。

        本web服务器呢,因为要考虑浏览器界面,让用户能从浏览器上直接调用功能,所以还包括了生成用户界面的部分。

        整个接口的名称为CWebCommand,后面介绍的代码都是这个类的一部分。

二、执行接口

        执行接口很简单,只有三个函数:

        初始化和卸载很简单。执行接口则有三个参数:请求、应答和socket。

        请求和应答很容易理解,为什么要提供socket呢?因为如果页面比较大的话,可能需要提前输出内容,不让用户等得太着急。

        如果提前返回一部分应答,那么就无法再添加内容长度头标了,因为投标部分已经发送,不可能再更改,应答对象对此做了检查。

        如果用户功能很特殊,仅仅直接使用socket而不使用应答对象也是可以的(也就是说,完全可以当作一个普通socket连接来使用)。

        一个示例:

	class CWebCommand_SetDebug : public CWebCommand
	{
	public:
		CWebCommand_SetDebug()
		{
			clear();
			AddWebCommandParam("SetDebug", "SetDebug", "1:开启调试/0:关闭调试", "");
			SetWebCommand("SetDebug", "设置调试开关", "开启G_IS_DEBUG,注意,开启后产生海量日志");
		}

		virtual bool doWebFunction(CHttpRequest const * pRequest, CSocket & s, CHttpRespond * pRespond)
		{
			string param = pRequest->GetParam("SetDebug");

			if ("1" == param)
			{
				G_IS_DEBUG = true;
				pRespond->AppendBody("打开调试成功");
			}
			else if ("0" == param)
			{
				G_IS_DEBUG = false;
				pRespond->AppendBody("关闭调试成功");
			}
			else
			{
				pRespond->AppendBody("非法参数,超出限制");
			}
			return true;
		}
	};

        这个示例很简单,根据参数设置调试开关,完全没有使用socket。构造函数设置了自身的参数,后面详细介绍。初始化和卸载没有使用。

三、接口设置

3.1 主要属性

		bool isAdmin;//是否是内置页面
		bool notonhomepage;//是否不出现在首页
		bool hide;//是否隐藏,只能通过直接命令调用
		bool AutoRefresh;//是否允许自动刷新
		bool NotStdPage;//非标准页面,不生成标准数据,所有数据,包括应答头都由命令自己生成
		string command_id;//命令ID,也作为页面名称,但不包括后缀名
		string name;//显示名称
		string note;

		vector<CWebCommandParam > params;//命令参数

        前面几个bool的含义是很明显的,由框架来控制各种行为。后面ID、名称和说明也很显然。最后的CWebCommandParam是重点,决定了需要用户输入几个参数,这个类会自动生成HTML的form代码。

3.2 CWebCommandParam

        这个类相当的繁琐,其实就是HTML的基本的form内容,供C++程序员快速生成form表单,如果想要奇幻的效果,可以请前端给做一个css。

	//命令接口
	class CWebCommandParam
	{
	public:
		string id;//唯一标识
		string name;//显示名称
		string note;//说明

		bool isCheckBox;//是否是选择框
		bool isChecked;//是否选中

		string defaultvalue;//默认值
		bool isNotNull;//是否必填
		bool isSelectOnly;//是否只能在选项表选择
		bool isHide;//是否隐藏
		bool isPassword;//是否是密码输入
		bool isReadOnly;//是否只读
		long size;//宽度
		long rows;//行数,改值不为0则显示为textaera
		vector<pair<string, string > > optionvalue;//选项集合

		CWebCommandParam() { clear(); }
		void clear()
		{
			isCheckBox = isChecked = false;
			isNotNull = isSelectOnly = isHide = isPassword = isReadOnly = false;
			id = name = note = defaultvalue = "";
			size = rows = 0;
			optionvalue.clear();
		}
		void SetFormatInput(char const * _id, char const * _name, long _size, long _rows = 0, char const * _default = "", char const * _note = "")
		{
			clear();
			id = _id;
			name = _name;
			size = _size;
			rows = _rows;
			defaultvalue = _default;
			note = _note;
		}
		void SetFormatPasswd(char const * _id, char const * _name, long _size, char const * _default = "", char const * _note = "")
		{
			clear();
			isPassword = true;
			id = _id;
			name = _name;
			size = _size;
			defaultvalue = _default;
			note = _note;
		}
		void ReadOnly() { isReadOnly = true; }
		string toHtmlInputOnly(char const* value, char const* desc, bool canEdit)
		{
			CWebCommandParam tmp = *this;
			tmp.isReadOnly = !canEdit;
			return tmp._toHtmlInput(false, false, value, desc, false);
		}
		string toHtmlInput(bool smallinput = false, bool showParamId = false, string NewDefault = "")
		{
			return _toHtmlInput(smallinput, showParamId, NewDefault);
		}
		string _toHtmlInput(bool smallinput = false, bool showParamId = false, string NewDefault = "", char const* desc = NULL, bool showName = true)
		{
			char buf[10240];
			string type;
			string ret;
			CHTMLEncode encode;

			char namestr[256];
			if (showName)sprintf(namestr, "%s&nbsp;%s%s", encode(name).c_str(), encode(note).c_str(), (isNotNull ? "*" : ""));
			else strcpy(namestr, "");

			//从请求更新参数的值
			if (0 != NewDefault.size())
			{
				if (isCheckBox && "1" == NewDefault)isChecked = true;
				else defaultvalue = NewDefault;
			}

			if (isHide)
			{
				sprintf(buf, "<INPUT NAME=\"%s\" TYPE=\"HIDDEN\" VALUE=\"%s\">"
					, encode(id).c_str(), encode(defaultvalue).c_str());
				ret += buf;
				return ret;
			}

			if (showParamId)
			{
				ret = id + "&nbsp;:&nbsp;";
			}
			if (this->isCheckBox)
			{
				sprintf(buf, "<input type=\"checkbox\" %s name=\"%s\" value=\"1\"><CODE><NOBR>%s</NOBR></CODE>"
					, (this->isChecked ? "checked" : ""), this->id.c_str(), this->name.c_str());
				ret += buf;
			}
			else
			{
				if (isReadOnly && !isPassword)
				{
					string _desc;
					if (NULL == desc || 0 == strlen(desc))_desc = defaultvalue;
					else _desc = desc;
					sprintf(buf, "<CODE>%s</CODE><INPUT NAME=\"%s\" TYPE=\"HIDDEN\" VALUE=\"%s\"><CODE>%s</CODE>"
						, namestr, encode(id).c_str(), encode(defaultvalue).c_str(), encode(_desc).c_str());
					ret += buf;
				}
				else
				{
					if (rows != 0)
					{
						sprintf(buf, "<LABEL><CODE>%s</CODE><textarea %s warp=\"soft\" cols=\"%ld\" rows=\"%ld\" NAME=\"%s\" >%s</textarea></LABEL>"
							, namestr, (isReadOnly ? "READONLY" : ""), (smallinput ? 16 : size), (smallinput ? 1 : rows), encode(id).c_str(), encode(defaultvalue).c_str());
						ret += buf;
					}
					else
					{
						if (optionvalue.size() != 0)
						{
							sprintf(buf, "<LABEL><CODE>%s</CODE><select %s NAME=\"%s\" >"
								, namestr, (isReadOnly ? "READONLY" : ""), encode(id).c_str());
							ret += buf;
							for (string::size_type i = 0; i < optionvalue.size(); ++i)
							{
								sprintf(buf, "\n<option value=\"%s\" %s>%s%s%s%s</option>", encode(optionvalue[i].first).c_str(), (optionvalue[i].first == defaultvalue ? "selected" : ""), encode(optionvalue[i].second).c_str()
									, (showParamId ? "[" : ""), (showParamId ? optionvalue[i].first.c_str() : ""), (showParamId ? "]" : ""));
								ret += buf;
							}
							sprintf(buf, "</select></LABEL>");
							ret += buf;
						}
						else
						{
							if (this->isPassword)type = "PASSWORD";
							else type = "INPUT";

							sprintf(buf, "<LABEL><CODE>%s<INPUT %s TYPE=\"%s\" SIZE=\"%ld\" NAME=\"%s\" value=\"%s\"></INPUT></CODE></LABEL>"
								, namestr, (isReadOnly ? "READONLY" : ""), type.c_str(), (smallinput ? 16 : size), encode(id).c_str(), encode(defaultvalue).c_str());
							ret += buf;
						}
					}
				}
			}

			return ret;
		}
	};

        代码没什么奥秘,就是根据参数组合出HTML代码。

3.3 添加参数

        为了简化代码,提供了几个快速添加参数的函数:

		void AddWebCommandParam(char const * _id, char const * _name, char const * _note, char const * _default, bool isPassword = false, bool isNotNull = false, long size = 16, long rows = 0, vector<pair<string, string > > * _optionvalue = NULL)
		{
			CWebCommandParam tmp;
			tmp.id = _id;
			tmp.name = _name;
			tmp.note = _note;
			tmp.defaultvalue = _default;
			tmp.isPassword = isPassword;
			tmp.isNotNull = isNotNull;
			tmp.size = size;
			tmp.rows = rows;
			if (NULL != _optionvalue)tmp.optionvalue = *_optionvalue;
			else tmp.optionvalue.clear();
			this->params.push_back(tmp);
		}
		void AddWebCommandParamCheckBox(char const * _id, char const * _name, char const * _note, bool isChecked)
		{
			CWebCommandParam tmp;
			tmp.id = _id;
			tmp.name = _name;
			tmp.note = _note;
			tmp.isCheckBox = true;
			tmp.isChecked = isChecked;
			this->params.push_back(tmp);
		}

3.4 生成form

        由于某种原因生成form被分为两部分,一部分包含form开始和参数,另一部分包含提交和结束:

		string toHtmlFormInput(bool smallinput, bool showParamId, CHttpRequest const * pRequest)
		{
			string str;

			if (command_id.size() != 0)
			{
				str += "<FORM name=\"" + GetFormName() + "\" target=\"_self\" ACTION=\"";
				str += command_id;
				str += ".asp\" METHOD=\"GET\" >\r\n";
			}
			else
			{
				str += "<FORM name=\"" + GetFormName() + "\" target=\"_self\" METHOD=\"GET\" >\r\n";
			}

			//添加命令ID
			str += "<input type=\"hidden\" name=\"___COMMAND_ID___\" value=\"";
			str += command_id;
			str += "\"></input>";
			//添加每个参数
			if (0 != params.size())
			{
				for (vector<CWebCommandParam >::size_type i = 0; i < params.size(); ++i)
				{
					str += params[i].toHtmlInput(smallinput, showParamId, pRequest->GetParam(params[i].id));
					str += "<BR>\r\n";
				}
			}
			else
			{
				str += "&nbsp;";
			}
			return str;
		}
		string toHtmlFormSubmit(bool disable, bool both)
		{
			char buf[1024];

			if (disable)
			{
				sprintf(buf, "<BR>不可用\r\n</FORM>\r\n");
			}
			else
			{
				if (both)
				{
					sprintf(buf, "<INPUT TYPE=SUBMIT VALUE=\"%s\" onclick=\"document.%s.target='_self'\">"
						"<INPUT TYPE=SUBMIT VALUE=\"%s(新窗口)\" onclick=\"document.%s.target='_blank'\">\r\n</FORM>\r\n"
						, name.c_str(), GetFormName().c_str(), name.c_str(), GetFormName().c_str());
				}
				else
				{
					sprintf(buf, "<BR><INPUT TYPE=SUBMIT VALUE=\"%s\" onclick=\"document.%s.target='_blank'\">\r\n</FORM>\r\n"
						, name.c_str(), GetFormName().c_str());
				}
			}

			return buf;
		}

        这两个函数连起来就是一个完整的form表单。

(这里是结束,但不是整个系列的结束)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值