zxs 3 сар өмнө
parent
commit
c024ed791a

+ 14 - 4
generator/class_view.hpp

@@ -64,6 +64,10 @@ struct PropertyInfo {
 	 * @brief 字段索引
 	*/
 	bool			sql_key = false;
+	/**
+	 * @brief 二进制序列化
+	*/
+	bool			no_archive = false;
 };
 
 struct ParameterInfo {
@@ -793,6 +797,7 @@ private:
 					std::string SqlKey = "SqlKey";
 					std::string Excel = "Excel";
 					std::string NoExcel = "NoExcel";
+					std::string NoArchive = "NoArchive";
 
 					if (attribute.size() > Json.size() && attribute.substr(0, Json.size()) == Json) {
 						auto values = v3::utils::split(attribute, "\"");
@@ -843,7 +848,12 @@ private:
 							add.no_excel = true;
 						}
 					}
-
+					else if (attribute.size() > NoArchive.size() && attribute.substr(0, NoArchive.size()) == NoArchive) {
+						attribute = v3::utils::to_upper(attribute);
+						if (attribute.find("TRUE") != std::string::npos) {
+							add.no_archive = true;
+						}
+					}
 					prop = smatch.suffix();
 				}
 			}
@@ -1089,7 +1099,7 @@ private:
 		else if (code == "int") {
 			parameter.argument_type = "robotics::v3::mvc::argument_type::Int";
 		}
-		else if (code == "__int64") {
+		else if (code == "std::uint64_t") {
 			parameter.argument_type = "robotics::v3::mvc::argument_type::Int64";
 		}
 		else if (code == "float") {
@@ -1116,7 +1126,7 @@ private:
 		else if (code == "std::vector<int>") {
 			parameter.argument_type = "robotics::v3::mvc::argument_type::VecInt";
 		}
-		else if (code == "std::vector<__int64>") {
+		else if (code == "std::vector<std::uint64_t>") {
 			parameter.argument_type = "robotics::v3::mvc::argument_type::VecInt64";
 		}
 		else if (code == "std::vector<float>") {
@@ -1326,7 +1336,7 @@ private:
 		if (code == "int") {
 			parameter.argument_type = "robotics::v3::soap::soap_argument_type::Int";
 		}
-		else if (code == "__int64") {
+		else if (code == "std::uint64_t") {
 			parameter.argument_type = "robotics::v3::soap::soap_argument_type::Int64";
 		}
 		else if (code == "float") {

BIN
lib/linux/logger/liblogger.so


BIN
lib/windows/logger/logger.dll


+ 1 - 1
logger/logger_impl.cpp

@@ -27,7 +27,7 @@ namespace robotics::v3 {
 		};
 		__thread_id__ th_id = thread_id;
 		if (save_.find(type) == save_.end()) {
-			printf("\033[40;%dm%s	[%s]	[%s#%s#%d#%d]	==>>\033[40;37m%s\n", color, time.c_str(), type.c_str(), file.c_str(), func.c_str(), line, th_id.iid, text.c_str());
+			std::cout << fmt::format("\033[{}m{}	[{}]	[{}#{}#{}#{}]	==>>\033[0m{}", color, time, type, file, func, line, th_id.iid, text) << std::endl;
 		}
 		else {
 			if (!std::filesystem::is_directory("log")) {

+ 1 - 1
robot/robotics/delegates.hpp

@@ -49,7 +49,7 @@ namespace robotics::v3 {
 		 */
 		template<typename _Fn, typename _Obj>
 		void bind(_Fn&& fn, _Obj&& obj) {
-			bind(std::bind_front(std::forward<_FnType>(fn), std::forward<_FnType>(obj)));
+			bind(std::bind_front(std::forward<_Fn>(fn), std::forward<_Obj>(obj)));
 		}
 		/**
 		 * @brief 调用

+ 1 - 1
robot/robotics/utils.hpp

@@ -41,7 +41,7 @@
 #endif
 
 #ifdef WINDOWS_BUILD
-#define SET_CONSOLE_UTF8 SetConsoleOutputCP(CP_UTF8)
+#define SET_CONSOLE_UTF8 system("chcp 65001")
 #elif LINUX_BUILD
 #define SET_CONSOLE_UTF8
 #endif

+ 1191 - 0
robot/robotics/web_service.hpp

@@ -0,0 +1,1191 @@
+/**
+*
+*  @file web_service.hpp
+*  @author zxw
+*  Copyright 2024, yjrobotics.  All rights reserved.
+*
+*  robotics
+*
+*/
+#pragma once
+//stl
+#include <iostream>
+//robotics
+#include <robotics/logger.hpp>
+#include <robotics/datetime.hpp>
+//asio
+#include <asio2/asio2.hpp>
+//rttr
+#include <rttr/registration>
+//boost
+#include <boost/foreach.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+namespace robotics::v3 {
+	class soap_reflect {
+	public:
+		static void get_object_value(rttr::instance obj, std::map<std::string, std::string>& values) {
+			auto propertys = obj.get_type().get_properties();
+			for (auto& property : propertys) {
+				std::string prop_name(property.get_name());
+				rttr::variant prop_value = property.get_value(obj);
+				rttr::type prop_type = property.get_type();
+				if (prop_type == rttr::type::get<int>()) {
+					values[prop_name] = std::to_string(prop_value.get_value<int>());
+				}
+				else if (prop_type == rttr::type::get<std::int64_t>()) {
+					values[prop_name] = std::to_string(prop_value.get_value<std::int64_t>());
+				}
+				else if (prop_type == rttr::type::get<float>()) {
+					values[prop_name] = format("%1$.2f", prop_value.get_value<float>());
+				}
+				else if (prop_type == rttr::type::get<double>()) {
+					values[prop_name] = format("%1$.2f", prop_value.get_value<double>());
+				}
+				else if (prop_type == rttr::type::get<long>()) {
+					values[prop_name] = std::to_string(prop_value.get_value<long>());
+				}
+				else if (prop_type == rttr::type::get<bool>()) {
+					values[prop_name] = prop_value.get_value<bool>() ? "true" : "false";
+				}
+				else if (prop_type == rttr::type::get<std::string>()) {
+					values[prop_name] = prop_value.get_value<std::string>();
+				}
+				else if (prop_type == rttr::type::get<v3::datetime>()) {
+					values[prop_name] = prop_value.get_value<v3::datetime>().to_string();
+				}
+				else if (prop_type == rttr::type::get<std::vector<int>>()) {
+					auto vecValue = prop_value.get_value<std::vector<int>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<std::int64_t>>()) {
+					auto vecValue = prop_value.get_value<std::vector<std::int64_t>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<float>>()) {
+					auto vecValue = prop_value.get_value<std::vector<float>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<double>>()) {
+					auto vecValue = prop_value.get_value<std::vector<double>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<long>>()) {
+					auto vecValue = prop_value.get_value<std::vector<long>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<bool>>()) {
+					auto vecValue = prop_value.get_value<std::vector<bool>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<std::string>>()) {
+					auto vecValue = prop_value.get_value<std::vector<std::string>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+				else if (prop_type == rttr::type::get<std::vector<v3::datetime>>()) {
+					auto vecValue = prop_value.get_value<std::vector<v3::datetime>>();
+					values[prop_name] = join(vecValue, ",");
+				}
+			}
+		}
+		static void set_object_value(rttr::instance obj, std::map<std::string, std::string>& values) {
+			rttr::instance obj1 = obj.get_type().get_raw_type().is_wrapper() ? obj.get_wrapped_instance() : obj;
+			const auto propertys = obj1.get_derived_type().get_properties();
+			for (auto& property : propertys) {
+				auto name = std::string(property.get_name());
+				auto type = property.get_type();
+				if (values.find(name) == values.end())
+					continue;
+				std::string value = values[name];
+				if (type == rttr::type::get<int>()) {
+					property.set_value(obj1, atoi(value.c_str()));
+				}
+				else if (type == rttr::type::get<std::int64_t>()) {
+					property.set_value(obj, std::int64_t(std::atoll(value.c_str())));
+				}
+				else if (type == rttr::type::get<float>()) {
+					property.set_value(obj, float(std::atof(value.c_str())));
+				}
+				else if (type == rttr::type::get<double>()) {
+					property.set_value(obj, double(std::atof(value.c_str())));
+				}
+				else if (type == rttr::type::get<long>()) {
+					property.set_value(obj, long(std::atol(value.c_str())));
+				}
+				else if (type == rttr::type::get<bool>()) {
+					if (value == "1" || value == "true" || value == "TRUE" || value == "True") {
+						property.set_value(obj, true);
+					}
+					else {
+						property.set_value(obj, false);
+					}
+				}
+				else if (type == rttr::type::get<std::string>()) {
+					property.set_value(obj, value);
+				}
+				else if (type == rttr::type::get<v3::datetime>()) {
+					property.set_value(obj, v3::datetime(value));
+				}
+				else if (type == rttr::type::get<std::vector<int>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<int> vecValue;
+					for (auto vecIt : vec) {
+						vecValue.push_back(std::atoi(vecIt.c_str()));
+					}
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<std::int64_t>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<std::int64_t> vecValue;
+					for (auto vecIt : vec) {
+						vecValue.push_back(std::atoll(vecIt.c_str()));
+					}
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<float>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<float> vecValue;
+					for (auto vecIt : vec) {
+						vecValue.push_back(std::atof(vecIt.c_str()));
+					}
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<double>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<double> vecValue;
+					for (auto vecIt : vec) {
+						vecValue.push_back(std::atof(vecIt.c_str()));
+					}
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<long>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<long> vecValue;
+					for (auto vecIt : vec) {
+						vecValue.push_back(std::atol(vecIt.c_str()));
+					}
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<bool>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<bool> vecValue;
+					for (auto vecIt : vec) {
+						vecValue.push_back(vecIt == "1" || vecIt == "true" || vecIt == "TRUE" || vecIt == "True");
+					}
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<std::string>>()) {
+					std::vector<std::string> vecValue = split(value, ",");
+					property.set_value(obj, vecValue);
+				}
+				else if (type == rttr::type::get<std::vector<v3::datetime>>()) {
+					std::vector<std::string> vec = split(value, ",");
+					std::vector<v3::datetime> vecValue;
+					for (auto &vecIt : vec) {
+						vecValue.push_back(v3::datetime(vecIt));
+					}
+					property.set_value(obj, vecValue);
+				}
+			}
+		}
+	};
+
+	struct soap_response {
+		soap_response(int value) :
+			value_(value) {
+		}
+		soap_response(std::int64_t value) :
+			value_(value) {
+		}
+		soap_response(float value) :
+			value_(value) {
+		}
+		soap_response(double value) :
+			value_(value) {
+		}
+		soap_response(long value) :
+			value_(value) {
+		}
+		soap_response(bool value) :
+			value_(value) {
+		}
+		soap_response(std::string const& value) :
+			value_(value) {
+		}
+		soap_response(v3::datetime const& value) :
+			value_(value) {
+		}
+		soap_response(const char* value) :
+			value_(value) {
+		}
+		soap_response(char* value) :
+			value_(value) {
+		}
+		rttr::variant get_value() {
+			return value_;
+		}
+		template<typename _Type>
+		soap_response(_Type const&value) :
+			value_(value) {
+		}
+	private:
+		rttr::variant value_;
+	};
+
+	struct xml_node_info {
+		std::string										node_name;		//当前节点名字
+		std::unordered_map<std::string, std::string>	xml_attr;		//当前节点的属性
+		std::vector<std::string>						list_sub_name;	//子节点名字
+		std::string										parent_name;	//父节点 记录了从根节点到上一个节点的名字,用"."隔开 
+		std::string										value;			//当前节点的值
+	};
+
+	class xml_manage {
+	public:
+		void set_xml(std::string xml) {
+			xml_ = xml;
+		}
+		std::vector<xml_node_info> get_xml_node() {
+			xml_parse();
+			return xml_node_list_;
+		}
+		std::string get_xml() {
+			return xml_;
+		}
+		void set_ptree(boost::property_tree::ptree xml) {
+			std::ostringstream os;
+			boost::property_tree::write_xml(os, xml);
+			xml_ = os.str();
+		}
+	private:
+		void xml_parse() {
+			xml_node_list_.clear();
+			std::istringstream s1(xml_);
+			boost::property_tree::ptree pt;
+			boost::property_tree::read_xml(s1, pt);
+			xml_parse(pt, xml_node_list_);
+		}
+		void xml_parse(const boost::property_tree::ptree& pxml, std::vector<xml_node_info>& listNode, std::string strNode = "") {
+			for (const auto& node : pxml) {
+				std::string  NodeKey = node.first.data(); //属性或者子节点
+				if (NodeKey == "<xmlattr>") {//判断是否是属性
+					continue; //属性已经在父节点中做了保存
+				}
+				xml_node_info xmlnode;
+				xmlnode.node_name = std::string(node.first.data()); //节点名
+				xmlnode.value = node.second.data(); //值
+				xmlnode.parent_name = strNode; //父节点是外面传入进来的
+				//获取该节点的属性
+				for (const auto& attr : node.second) {
+					std::string strAttr = attr.first.data();
+					if (std::string(strAttr) == "<xmlattr>") {//是属性
+						//获取属性的值
+						for (auto& att : attr.second) {
+							xmlnode.xml_attr[att.first.data()] = att.second.data();
+						}
+					}
+					else {//节点自身
+						xmlnode.list_sub_name.emplace_back(strAttr); //当前节点的子节点名字
+					}
+				}
+				listNode.emplace_back(xmlnode); //保存当前节点
+				if (!NodeKey.empty()) {//当前节点
+					xmlnode.xml_attr.clear();
+					//获取子节点信息 递归
+					std::string str_parent_name;
+					if (!xmlnode.parent_name.empty()) {
+						str_parent_name += xmlnode.parent_name + "." + xmlnode.node_name;
+					}
+					else {
+						str_parent_name = xmlnode.node_name;
+					}
+					//生成父节点 写入XML的时候需要知道父节点
+					xml_parse(node.second, listNode, str_parent_name); //递归遍历
+				}
+			}
+		}
+	private:
+		std::string xml_;
+		std::vector<xml_node_info> xml_node_list_;
+	};
+
+	enum class soap_version {
+		VER1_1,
+		VER1_2
+	};
+
+	struct soap_parameter {
+		std::string method_name;
+		std::map<std::string, rttr::variant> req_parameters;
+		std::map<std::string, bool> req_parameters_namespace;
+		rttr::variant resp_parameter;
+		std::string xmlns_xsi = "http://www.w3.org/2001/XMLSchema-instance";
+		std::string xmlns_xsd = "http://www.w3.org/2001/XMLSchema";
+		std::string xmlns_soap = "http://schemas.xmlsoap.org/soap/envelope/";
+		std::string xmlns_soap12 = "http://www.w3.org/2003/05/soap-envelope";
+		std::string namespace_name;
+		std::string soap_action;
+		soap_version version = soap_version::VER1_1;
+	};
+
+	class soap_err_parser {
+	public:
+		typedef boost::property_tree::ptree xmltree;
+		static std::string get_soap_err(std::string const&type, std::string const& msg, soap_version version = soap_version::VER1_1) {
+			xmltree body;
+			xmltree fault;
+			xmltree envelope;
+			xmltree fault_message;
+			fault_message.add("detail", "");
+			fault_message.add("faultcode", type);
+			fault_message.add("faultstring", msg);
+			fault.add_child("soap:Fault", fault_message);
+			body.add_child("soap:Body", fault);
+			envelope.add_child("soap:Envelope", body);
+			if (version == soap_version::VER1_1) {
+				envelope.add("soap:Envelope.<xmlattr>.xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
+			}
+			else {
+				envelope.add("soap:Envelope.<xmlattr>.xmlns:soap12", "http://www.w3.org/2003/05/soap-envelope");
+			}
+			envelope.add("soap:Envelope.<xmlattr>.xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+			envelope.add("soap:Envelope.<xmlattr>.xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
+			std::ostringstream os;
+			boost::property_tree::xml_writer_settings<std::string> settings =
+				boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
+			boost::property_tree::write_xml(os, envelope, settings);
+			return os.str();
+		}
+	};
+
+	class soap_server_resp_parser {
+	public:
+		typedef boost::property_tree::ptree xmltree;
+		std::string get_xml(soap_parameter parameter) {
+			add_value(parameter.method_name, parameter.resp_parameter);
+			method_response_.add_child(parameter.method_name + "Response", method_request_);
+			method_response_.add(parameter.method_name + "Response.<xmlattr>.xmlns", parameter.namespace_name);
+			body_.add_child("soap:Body", method_response_);
+			envelope_.add_child("soap:Envelope", body_);
+			if (parameter.version == soap_version::VER1_1) {
+				envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap", parameter.xmlns_soap);
+			}
+			else {
+				envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap12", parameter.xmlns_soap12);
+			}
+			envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsi", parameter.xmlns_xsi);
+			envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsd", parameter.xmlns_xsd);
+			std::ostringstream os;
+			boost::property_tree::xml_writer_settings<std::string> settings =
+				boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
+			boost::property_tree::write_xml(os, envelope_, settings);
+			return os.str();
+		}
+	private:
+		void add_value(std::string const&method_name, rttr::variant value) {
+			if (value.get_type() == rttr::type::get<int>()) {
+				method_request_.put(method_name + "Result", value.get_value<int>());
+			}
+			else if (value.get_type() == rttr::type::get<__int64>()) {
+				method_request_.put(method_name + "Result", value.get_value<__int64>());
+			}
+			else if (value.get_type() == rttr::type::get<float>()) {
+				method_request_.put(method_name + "Result", value.get_value<float>());
+			}
+			else if (value.get_type() == rttr::type::get<double>()) {
+				method_request_.put(method_name + "Result", value.get_value<double>());
+			}
+			else if (value.get_type() == rttr::type::get<long>()) {
+				method_request_.put(method_name + "Result", value.get_value<long>());
+			}
+			else if (value.get_type() == rttr::type::get<bool>()) {
+				method_request_.put(method_name + "Result", value.get_value<bool>() ? "True" : "False");
+			}
+			else if (value.get_type() == rttr::type::get<std::string>()) {
+				method_request_.put(method_name + "Result", value.get_value<std::string>());
+			}
+			else if (value.get_type() == rttr::type::get<const char*>()) {
+				method_request_.put(method_name + "Result", value.get_value<const char*>());
+			}
+			else if (value.get_type() == rttr::type::get<v3::DateTime>()) {
+				method_request_.put(method_name + "Result", value.get_value<v3::DateTime>().getFormatDateTime());
+			}
+			else {
+				std::map<std::string, std::string> property_values;
+				soap_reflect::get_object_value(value, property_values);
+				xmltree propertys;
+				for (auto& it : property_values) {
+					propertys.add(it.first, it.second);
+				}
+				method_request_.add_child(method_name + "Result", propertys);
+			}
+		}
+	private:
+		xmltree body_;
+		xmltree envelope_;
+		xmltree method_request_;
+		xmltree method_response_;
+	};
+
+	class soap_server_req_parser {
+	public:
+		typedef boost::property_tree::ptree xmltree;
+		soap_parameter soap_parser(std::string const&xml) {
+			xml_manage _xml;
+			_xml.set_xml(xml);
+			auto xml_nodes = _xml.get_xml_node();
+			return xml_parser(xml_nodes);
+		}
+	private:
+		soap_parameter xml_parser(std::vector<xml_node_info> const&nodes) {
+			std::string tem_name;
+			std::string soapenv;
+			std::string method_name;
+			std::string namespace_name;
+			std::map<std::string, rttr::variant> _parameter;
+			soap_parameter parameter;
+			std::string envelope = "Envelope";
+			//获取soapenv
+			for (auto& it : nodes) {
+				size_t size = it.node_name.size();
+				if (size > envelope.size() && it.node_name.substr(size - envelope.size(), envelope.size()) == envelope) {
+					soapenv = it.node_name.substr(0, size - envelope.size() - 1);
+					break;
+				}
+			}
+			//获取版本
+			for (auto& it : nodes) {
+				if (it.node_name == soapenv + ":Envelope") {
+					for (auto& attr : it.xml_attr) {
+						if (attr.second == parameter.xmlns_soap) {
+							parameter.version = soap_version::VER1_1;
+						}
+						else if (attr.second == parameter.xmlns_soap12) {
+							parameter.version = soap_version::VER1_2;
+						}
+					}
+				}
+			}
+			//获取命名空间1
+			for (auto& it : nodes) {
+				if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
+					for (auto& attr : it.xml_attr) {
+						if (attr.first == "xmlns") {
+							namespace_name = attr.second;
+							break;
+						}
+					}
+				}
+			}
+			//获取命名空间2
+			if (namespace_name.empty()) {
+				for (auto& it : nodes) {
+					if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
+						size_t size = it.node_name.size();
+						auto values = v3::split(it.node_name, ":");
+						if (values.size() == 2) {
+							for (auto& attr : nodes[0].xml_attr) {
+								if (attr.first == "xmlns:" + values[0]) {
+									namespace_name = attr.second;
+									break;
+								}
+							}
+						}
+					}
+				}
+			}
+			//获取方法名称
+			for (auto& it : nodes) {
+				if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
+					auto values = v3::split(it.node_name, ":");
+
+					if (values.size() == 2) {
+						tem_name = values[0];
+						method_name = values[1];
+					}
+					else {
+						method_name = values[0];
+					}
+
+					break;
+				}
+			}
+			//获取参数
+			for (auto& it : nodes) {
+				if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
+					(tem_name.empty() ? method_name : tem_name + ":" + method_name)) {
+
+					if (it.list_sub_name.size() == 0) {
+						auto values = v3::split(it.node_name, ":");
+
+						if (values.size() == 2) {
+							_parameter[values[1]] = it.value;
+						}
+						else {
+							_parameter[it.node_name] = it.value;
+						}
+					}
+					else {
+						std::string value = it.node_name;
+						std::map<std::string, std::string> tmpParameter;
+						for (auto& it1 : nodes) {
+							if (it1.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
+								(tem_name.empty() ? method_name + "." : tem_name + ":" + method_name + ".") + value) {
+
+								auto values = v3::split(it1.node_name, ":");
+								if (values.size() == 2) {
+									tmpParameter[values[1]] = it1.value;
+								}
+								else {
+									tmpParameter[it1.node_name] = it1.value;
+								}
+							}
+						}
+						auto values1 = v3::split(it.node_name, ":");
+						if (values1.size() == 2) {
+							_parameter[values1[1]] = tmpParameter;
+						}
+						else {
+							_parameter[it.node_name] = tmpParameter;
+						}
+					}
+				}
+			}
+			parameter.method_name = method_name;
+			parameter.namespace_name = namespace_name;
+			parameter.req_parameters = _parameter;
+			parameter.soap_action = namespace_name + method_name;
+			return parameter;
+		}
+	};
+
+	class soap_client_req_parser {
+	public:
+		typedef boost::property_tree::ptree xmltree;
+		std::string get_xml(soap_parameter const&parameter) {
+			add_value(parameter.method_name, parameter.req_parameters, parameter.req_parameters_namespace);
+			method_request_.add(parameter.method_name + ".<xmlattr>.xmlns", parameter.namespace_name);
+			body_.add_child("soap:Body", method_request_);
+			envelope_.add_child("soap:Envelope", body_);
+			if (parameter.version == soap_version::VER1_1) {
+				envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap", parameter.xmlns_soap);
+			}
+			else {
+				envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap12", parameter.xmlns_soap12);
+			}
+			envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsi", parameter.xmlns_xsi);
+			envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsd", parameter.xmlns_xsd);
+			std::ostringstream os;
+			boost::property_tree::xml_writer_settings<std::string> settings =
+				boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
+			boost::property_tree::write_xml(os, envelope_, settings);
+			return os.str();
+		}
+	private:
+		void add_value(std::string const&method_name, std::map<std::string, rttr::variant> const& values, std::map<std::string, bool> const& namespaces) {
+			xmltree parameters;
+			for (auto& value : values) {
+				if (value.second.get_type() == rttr::type::get<int>()) {
+					parameters.add(value.first, value.second.get_value<int>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<std::int64_t>()) {
+					parameters.add(value.first, value.second.get_value<std::int64_t>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<float>()) {
+					parameters.add(value.first, value.second.get_value<float>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<double>()) {
+					parameters.add(value.first, value.second.get_value<double>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<long>()) {
+					parameters.add(value.first, value.second.get_value<long>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<bool>()) {
+					parameters.add(value.first, value.second.get_value<bool>() ? "True" : "False");
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<std::string>()) {
+					parameters.add(value.first, value.second.get_value<std::string>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<const char*>()) {
+					parameters.add(value.first, value.second.get_value<const char*>());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else if (value.second.get_type() == rttr::type::get<v3::datetime>()) {
+					parameters.add(value.first, value.second.get_value<v3::datetime>().to_string());
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+				else {
+					std::map<std::string, std::string> property_values;
+					v3::soap_reflect::get_object_value(value.second, property_values);
+					xmltree propertys;
+					for (auto& it : property_values) {
+						propertys.add(it.first, it.second);
+					}
+					parameters.add_child(value.first, propertys);
+					if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
+						parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
+				}
+			}
+			method_request_.add_child(method_name, parameters);
+		}
+	private:
+		xmltree body_;
+		xmltree envelope_;
+		xmltree method_request_;
+	};
+
+	class soap_client_resp_parser {
+	public:
+		typedef boost::property_tree::ptree xmltree;
+		soap_parameter soap_parser(std::string const&xml) {
+			xml_manage _xml;
+			_xml.set_xml(xml);
+			auto xml_nodes = _xml.get_xml_node();
+			return xml_parser(xml_nodes);
+		}
+	private:
+		soap_parameter xml_parser(std::vector<xml_node_info> nodes) {
+			std::string tem_name;
+			std::string soapenv;
+			std::string method_name;
+			std::string namespace_name;
+			rttr::variant parameter_;
+			soap_parameter parameter;
+			std::string envelope = "Envelope";
+			std::string response = "Response";
+			for (auto& it : nodes) {
+				size_t size = it.node_name.size();
+				if (size > envelope.size() && it.node_name.substr(size - envelope.size(), envelope.size()) == envelope) {
+					soapenv = it.node_name.substr(0, size - envelope.size() - 1);
+					break;
+				}
+			}
+			//获取版本
+			for (auto& it : nodes) {
+				if (it.node_name == soapenv + ":Envelope") {
+					for (auto& attr : it.xml_attr) {
+						if (attr.second == parameter.xmlns_soap) {
+							parameter.version = soap_version::VER1_1;
+						}
+						else if (attr.second == parameter.xmlns_soap12) {
+							parameter.version = soap_version::VER1_2;
+						}
+					}
+				}
+			}
+			//获取命名空间1
+			for (auto& it : nodes) {
+				if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
+					size_t size = it.node_name.size();
+					if (size > response.size() && it.node_name.substr(size - response.size(), response.size()) == response) {
+						for (auto& attr : it.xml_attr) {
+							if (attr.first == "xmlns") {
+								namespace_name = attr.second;
+								break;
+							}
+						}
+					}
+				}
+			}
+			//获取命名空间2
+			if (namespace_name.empty()) {
+				for (auto& it : nodes) {
+					if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
+						size_t size = it.node_name.size();
+						if (size > response.size() && it.node_name.substr(size - response.size(), response.size()) == response) {
+							auto values = v3::split(it.node_name, ":");
+							if (values.size() == 2) {
+								for (auto& attr : it.xml_attr) {
+									if (attr.first == "xmlns:" + values[0]) {
+										namespace_name = attr.second;
+										break;
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+			//获取方法名称
+			for (auto& it : nodes) {
+				if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
+					size_t size = it.node_name.size();
+					if (size > response.size() && it.node_name.substr(size - response.size(), response.size()) == response) {
+						auto values = v3::split(it.node_name, ":");
+						if (values.size() == 2) {
+							tem_name = values[0];
+							method_name = values[1];
+						}
+						else {
+							method_name = values[0];
+						}
+						if (method_name.size() > response.size()) {
+							method_name.erase(method_name.size() - response.size(), response.size());
+						}
+						break;
+					}
+				}
+			}
+			//获取参数
+			for (auto& it : nodes) {
+				if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
+					(tem_name.empty() ? method_name + "Response" : tem_name + ":" + method_name + "Response") &&
+					it.node_name == (tem_name.empty() ? method_name + "Result" : tem_name + ":" + method_name + "Result")) {
+					if (it.list_sub_name.size() == 0) {
+						parameter_ = it.value;
+					}
+					else {
+						parameter_ = std::map<std::string, std::string>();
+					}
+				}
+				else if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
+					(tem_name.empty() ? method_name + "Response." : tem_name + ":" + method_name + "Response.") +
+					(tem_name.empty() ? method_name + "Result" : tem_name + ":" + method_name + "Result")) {
+					auto tmp_parameter = parameter_.get_value<std::map<std::string, std::string>>();
+					if (tem_name.empty()) {
+						tmp_parameter[it.node_name] = it.value;
+					}
+					else {
+						auto values = v3::split(it.node_name, ":");
+						if (values.size() == 2) {
+							tmp_parameter[values[1]] = it.value;
+						}
+						else {
+							tmp_parameter[it.node_name] = it.value;
+						}
+					}
+					parameter_ = tmp_parameter;
+				}
+				else if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
+					(tem_name.empty() ? method_name + "Response" : tem_name + ":" + method_name + "Response") &&
+					it.node_name == "return") {
+					if (it.list_sub_name.size() == 0) {
+						parameter_ = it.value;
+					}
+					else {
+						parameter_ = std::map<std::string, std::string>();
+					}
+				}
+				else if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
+					(tem_name.empty() ? method_name + "Response." : tem_name + ":" + method_name + "Response.return")) {
+					auto tmp_parameter = parameter_.get_value<std::map<std::string, std::string>>();
+					if (tem_name.empty()) {
+						tmp_parameter[it.node_name] = it.value;
+					}
+					else {
+						auto values = v3::split(it.node_name, ":");
+						if (values.size() == 2) {
+							tmp_parameter[values[1]] = it.value;
+						}
+						else {
+							tmp_parameter[it.node_name] = it.value;
+						}
+					}
+					parameter_ = tmp_parameter;
+				}
+			}
+			parameter.method_name = method_name;
+			parameter.namespace_name = namespace_name;
+			parameter.resp_parameter = parameter_;
+			parameter.soap_action = namespace_name + method_name;
+			return parameter;
+		}
+	};
+
+	enum class soap_argument_type {
+		Int = 1,
+		Int64,
+		Float,
+		Double,
+		Long,
+		Bool,
+		String,
+		DateTime
+	};
+
+	template<typename _Type>
+	struct soap_variant_value {
+		static _Type get_value(rttr::variant& value) {
+			_Type result;
+			auto map = value.get_value<std::map<std::string, std::string>>();
+			v3::soap_reflect::set_object_value(result, map);
+			return result;
+		}
+	};
+
+	template<>
+	struct soap_variant_value<int> {
+		static int get_value(rttr::variant& value) {
+			return std::atoi(value.get_value<std::string>().c_str());
+		}
+	};
+
+	template<>
+	struct soap_variant_value<std::int64_t> {
+		static std::int64_t get_value(rttr::variant& value) {
+			return std::atoll(value.get_value<std::string>().c_str());
+		}
+	};
+
+	template<>
+	struct soap_variant_value<float> {
+		static float get_value(rttr::variant& value) {
+			return std::atof(value.get_value<std::string>().c_str());
+		}
+	};
+
+	template<>
+	struct soap_variant_value<double> {
+		static double get_value(rttr::variant& value) {
+			return std::atof(value.get_value<std::string>().c_str());
+		}
+	};
+
+	template<>
+	struct soap_variant_value<long> {
+		static long get_value(rttr::variant& value) {
+			return std::atol(value.get_value<std::string>().c_str());
+		}
+	};
+
+	template<>
+	struct soap_variant_value<bool> {
+		static bool get_value(rttr::variant& value) {
+			std::string v = value.get_value<std::string>();
+			return v == "true" || v == "True" || v == "TRUE";
+		}
+	};
+
+	template<>
+	struct soap_variant_value<std::string> {
+		static std::string get_value(rttr::variant& value) {
+			return value.get_value<std::string>();
+		}
+	};
+
+	template<>
+	struct soap_variant_value<v3::datetime> {
+		static v3::datetime get_value(rttr::variant& value) {
+			return v3::datetime(value.get_value<std::string>());
+		}
+	};
+
+	class soap_action_argument {
+	public:
+		void parameter(rttr::type type, rttr::variant value) {
+			try {
+				if (rttr::type::get<std::string>() != value.get_type())
+					throw std::runtime_error("parameter error");
+
+				std::string data = value.get_value<std::string>();
+
+				switch (argument_type_) {
+				case soap_argument_type::Int: {
+					parameter_value_ = std::atoi(data.c_str());
+					return;
+				}
+				case soap_argument_type::Int64: {
+					parameter_value_ = std::atoll(data.c_str());
+					return;
+				}
+				case soap_argument_type::Float: {
+					parameter_value_ = std::atof(data.c_str());
+					return;
+				}
+				case soap_argument_type::Double: {
+					parameter_value_ = std::atof(data.c_str());
+					return;
+				}
+				case soap_argument_type::Long: {
+					parameter_value_ = std::atol(data.c_str());
+					return;
+				}
+				case soap_argument_type::Bool: {
+					std::string tmpValue(data);
+					parameter_value_ = tmpValue == "1" || tmpValue == "true" || tmpValue == "TRUE" || tmpValue == "True";
+					return;
+				}
+				case soap_argument_type::String: {
+					parameter_value_ = std::string(data);
+					return;
+				}
+				case soap_argument_type::DateTime: {
+					parameter_value_ = v3::DateTime(data);
+					return;
+				}
+				}
+			}
+			catch (...) {
+				throw std::runtime_error("parameter error");
+			}
+		}
+		std::string				parameter_name_;
+		rttr::variant			parameter_value_;
+		soap_argument_type		argument_type_ = soap_argument_type::String;
+	};
+
+	class soap_controller_action {
+	public:
+		void invoke(http::web_request& request, rttr::variant& variant, rttr::type controller_type, soap_parameter& soap_parameter) {
+			std::vector<rttr::method> find_method;
+			for (auto& it : controller_type.get_methods()) {
+				if (it.get_name() == action_name && it.get_parameter_infos().size() == arguments.size()) {
+					find_method.push_back(it);
+					break;
+				}
+			}
+			if (find_method.empty())
+				throw std::runtime_error("method does not exist");
+			std::vector<rttr::argument> parameters;
+			{
+				std::lock_guard<std::mutex> locker(mutex_);
+				for (auto& it : find_method[0].get_parameter_infos()) {
+					std::shared_ptr<soap_action_argument> item = arguments[it.get_index()];
+					if (soap_parameter.req_parameters.find(item->parameter_name_) == soap_parameter.req_parameters.end())
+						throw std::runtime_error("parameter error");
+					item->parameter(it.get_type(), soap_parameter.req_parameters[item->parameter_name_]);
+				}
+				for (auto& it : arguments) {
+					parameters.push_back(it->parameter_value_);
+				}
+			}
+			rttr::variant result = controller_type.invoke(action_name, variant, parameters);
+			soap_parameter.resp_parameter = result.get_value<soap_response>().getValue();
+		}
+		std::string											action_name;
+		std::vector<std::shared_ptr<soap_action_argument>>	arguments;
+	private:
+		std::mutex mutex_;
+	};
+
+	class soap_controller {
+	public:
+		soap_parameter invoke(http::web_request& request) {
+			soap_parameter soap_parameter = soap_server_req_parser().soap_parser(std::string(request.body().begin(), request.body().end()));
+
+			if (soap_parameter.namespace_name != namespace_name) {
+				throw std::runtime_error("namespace error");
+			}
+
+			if (version != soap_parameter.version) {
+				throw std::runtime_error("version error");
+			}
+
+			rttr::type type = rttr::type::get_by_name(controller_name);
+			if (!variant_.is_valid())
+				variant_ = type.create();
+
+			actions[soap_parameter.method_name]->invoke(request, variant_, type, soap_parameter);
+
+			return soap_parameter;
+		}
+		std::string														wsdl;
+		std::string														route;
+		std::string														namespace_name;
+		std::string														controller_name;
+		soap_version													version = soap_version::VER1_1;
+		std::map<std::string, std::shared_ptr<soap_controller_action>>	actions;
+	private:
+		rttr::variant	variant_;
+		std::string		response_value_;
+	};
+
+	class soap_ioc_controller {
+	public:
+		static void attach(std::shared_ptr<soap_controller> controller) {
+			if (controllers_.find(controller->route) == controllers_.end()) {
+				controllers_[controller->route] = controller;
+			}
+		}
+		static std::shared_ptr<soap_controller> resolve(std::string const&route) {
+			if (route.empty()) {
+				return nullptr;
+			}
+			if (controllers_.find(route) != controllers_.end()) {
+				return controllers_[route];
+			}
+			return nullptr;
+		}
+		static std::map<std::string, std::shared_ptr<soap_controller>> get_controllers() {
+			return controllers_;
+		}
+	private:
+		static std::map<std::string, std::shared_ptr<soap_controller>> controllers_;
+	};
+
+	class http_web_service {
+	public:
+		http_web_service() {
+			auto conrollers = soap_ioc_controller::get_controllers();
+			for (auto& it : conrollers) {
+				server_.bind<http::verb::post>("/" + it.first, &http_web_service::on_base_request, this);
+				server_.bind<http::verb::get>("/" + it.first, &http_web_service::on_base_wsdl, this);
+			}
+		}
+		/**
+		 * @brief 启动
+		 * @param host 
+		 * @param port 
+		 */
+		void start(std::string host = "0.0.0.0", int port = 80) {
+			_server->start(host, port);
+		}
+		/**
+		 * @brief 停止
+		 */
+		void stop() {
+			_server->stop();
+		}
+	protected:
+		virtual void on_request(http::web_request& req, http::web_response& rep) = 0;
+		virtual void on_wsdl(http::web_request& req, http::web_response& rep) = 0;
+	private:
+		/**
+		 * @brief 请求
+		 * @param session 
+		 * @param req 
+		 * @param rep 
+		 */
+		void on_base_request(std::shared_ptr<asio2::http_session>& session, http::web_request& req, http::web_response& rep) {
+			on_request(req, rep);
+		}
+		/**
+		 * @brief wsdl
+		 * @param session 
+		 * @param req 
+		 * @param rep 
+		 */
+		void on_base_wsdl(std::shared_ptr<asio2::http_session>& session, http::web_request& req, http::web_response& rep) {
+			on_wsdl(req, rep);
+		}
+	private:
+		asio2::http_server server_;
+	};
+
+	class https_web_service {
+	public:
+		https_web_service() {
+			auto conrollers = soap_ioc_controller::get_controllers();
+			for (auto& it : conrollers) {
+				server_.bind<http::verb::post>("/" + it.first, &https_web_service::on_base_request, this);
+				server_.bind<http::verb::get>("/" + it.first, &https_web_service::on_base_wsdl, this);
+			}
+		}
+		/**
+		 * @brief 启动
+		 * @param host
+		 * @param port
+		 */
+		void start(std::string host = "0.0.0.0", int port = 80) {
+			_server->start(host, port);
+		}
+		/**
+		 * @brief 停止
+		 */
+		void stop() {
+			_server->stop();
+		}
+		/**
+		 * @brief 证书
+		 * @param ca_cert_file 
+		 * @param private_cert_file 
+		 * @param private_key_file 
+		 * @param private_password 
+		 * @return 
+		 */
+		bool set_cert_file(std::string const&ca_cert_file, std::string const& private_cert_file, std::string const& private_key_file, std::string const& private_password) {
+			server_.set_cert_file(ca_cert_file, private_cert_file, private_key_file, private_password);
+			return (bool)asio2::get_last_error();
+		}
+	protected:
+		virtual void on_request(http::web_request& req, http::web_response& rep) = 0;
+		virtual void on_wsdl(http::web_request& req, http::web_response& rep) = 0;
+	private:
+		/**
+		 * @brief 请求
+		 * @param session
+		 * @param req
+		 * @param rep
+		 */
+		void on_base_request(std::shared_ptr<asio2::https_session>& session, http::web_request& req, http::web_response& rep) {
+			on_request(req, rep);
+		}
+		/**
+		 * @brief wsdl
+		 * @param session
+		 * @param req
+		 * @param rep
+		 */
+		void on_base_wsdl(std::shared_ptr<asio2::https_session>& session, http::web_request& req, http::web_response& rep) {
+			on_wsdl(req, rep);
+		}
+	private:
+		asio2::https_server server_;
+	};
+
+	template<typename _HttpBase>
+	class web_service_base : public _HttpBase {
+	public:
+		web_service_base() :
+			_HttpBase() {
+		}
+	private:
+		/**
+		 * @brief 
+		 * @param req 
+		 * @param rep 
+		 */
+		virtual void on_request(http::web_request& req, http::web_response& rep) override {
+			std::shared_ptr<soap_controller> controller = soap_ioc_controller::resolve(req.url().string().substr(1));
+			if (controller) {
+				std::string xml;
+				try {
+					soap_parameter soap_parameter = controller->invoke(req);
+					xml = soap_server_resp_parser().get_xml(soap_parameter);
+				}
+				catch (std::exception const&ec) {
+					xml = soap_err_parser::get_soap_err("soap::client", ec.what());
+					LOG_ERROR << ec;
+				}
+				rep.fill_text(xml, http::status::ok, "text/xml; charset=utf-8");
+				rep.chunked(true);
+			}
+		}
+		/**
+		 * @brief 
+		 * @param req 
+		 * @param rep 
+		 */
+		virtual void on_wsdl(http::web_request& req, http::web_response& rep) override {
+			std::shared_ptr<soap_controller> controller = soap_ioc_controller::resolve(req.url().string().substr(1));
+			if (controller) {
+				rep.fill_file(controller->wsdl);
+				rep.chunked(true);
+			}
+			else {
+				rep.fill_page(http::status::not_found);
+				rep.chunked(true);
+			}
+		}
+	};
+
+	template<typename _HttpBase>
+	using https_server = web_service_base<_HttpBase>;
+}