您的位置:首页 > 房产 > 家装 > 事业单位微信公众号怎么创建_凡客诚品官方网址_seo搜索优化招聘_国外网站排行

事业单位微信公众号怎么创建_凡客诚品官方网址_seo搜索优化招聘_国外网站排行

2025/7/7 18:26:54 来源:https://blog.csdn.net/2303_78095330/article/details/145859250  浏览:    关键词:事业单位微信公众号怎么创建_凡客诚品官方网址_seo搜索优化招聘_国外网站排行
事业单位微信公众号怎么创建_凡客诚品官方网址_seo搜索优化招聘_国外网站排行

目录

第一节:钥匙构建规则

        1-1.routing_key

        1-2.binding_key

第二节:代码实现

        2-1.routing_key的检查

        2-2.binding_key的检查

         2-3.routing_key和binding_key的匹配

第三节:单元测试

下期预告:


        Router在mqserver目录下实现

第一节:钥匙构建规则

        1-1.routing_key

        routing_key的规则是只含有字符'0'~'9'、小写字母、大写字母、'_'、'.'。

        其中'.'作为分隔符,进行匹配时,会以'.'为界限将routing_key分割成多个小块,同时省略空串。例如"news.music.pop"和"...news.music...pop"都会被分割成{"news","music","pop"}。

        1-2.binding_key

        binding_key的规则是只含有字符'0'~'9'、小写字母、大写字母、'_'、'.',外加'#'和'*'。

        其中'.'作为分隔符,作用和routing_key中一样。

        '#'和'*'都是通配符,"#"是万能通配符,它可以表示零个或多个单词,例如:

        "#"和"news.music.pop"就可以匹配成功;

        "#.music.pop"和"news.music.pop"也可以匹配成功;

        '*'是一般通配符,它只能表示零个或者一个单词。

        其次,通配符必须独立存在,例如:

        "news.#123.pop"和"news.*123.pop"都是不合法的。

        最后,'#'通配符的两边不能直接相邻其他通配符,例如:

        "##"、"#*"、"*#"都是不合法的。

第二节:代码实现

        首先做好前置工作:

#ifndef __M_ROUTE_H__
#define __M_ROUTE_H__#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"namespace zd
{class Router{};
};#endif

        2-1.routing_key的检查

        根据它的构建规则,遍历routing_key,发现非法字符就返回false:

            // 验证routing_key的合法性static bool isLegalRoutingkey(const std::string& routing_key){// 1.每个字符合法for(const auto& ch:routing_key){if((ch >= 'a' && ch <= 'z')||(ch >= 'A' && ch <= 'Z')||(ch >= '0' && ch <= '9')||(ch == '_' || ch == '.')){continue;}else{LOG("routing_key 检测到非法字符 %c",ch);return false;}}return true;}

        2-2.binding_key的检查

        也是先遍历检查是否含有非法字符。

        然后把它按照"."进行分割,遍历每个单词,检查通配符是否独立存在。

        最后再次遍历binding_key,遇到通配符'#'就检查它是否相邻了其他通配符。

            // 验证binding_key合法性static bool isLegalBindingkey(const std::string& binding_key){// 1.每个字符合法for(const auto& ch:binding_key){if((ch >= 'a' && ch <= 'z')||(ch >= 'A' && ch <= 'Z')||(ch >= '0' && ch <= '9')||(ch == '_' || ch == '.')||(ch == '*' || ch == '#')){continue;}else{LOG("binding_key 检测到非法字符 %c",ch);return false;}}// 2.*和#必须独立存在std::vector<std::string> sub_words;StrHelper::split(binding_key,".",sub_words);for(std::string& word:sub_words){if(word.size() > 1 && (word.find("#") != std::string::npos || word.find("*") != std::string::npos)){LOG("通配符的错误使用,通配符没有独立存在");return false;}}// 3.#两边不能有通配符for(int i = 1;i < sub_words.size();i++){if(sub_words[i] == "#" && sub_words[i-1] == "*"){LOG("通配符的错误使用,#前有*");return false;}if(sub_words[i] == "#" && sub_words[i-1] == "#"){LOG("通配符的错误使用,#前有#");return false;}if(sub_words[i] == "*" && sub_words[i-1] == "#"){LOG("通配符的错误使用,#后有*");return false;}}return true;}

         2-3.routing_key和binding_key的匹配

        如果交换机是直接模式,那么routing_key和binding_key相同才成功。

        如果交换机是广播模式,那么与交换机有绑定的队列都能匹配成功,与routing_key和binding_key的内容无关。

        如果交换机是主题模式,那么routing_key和binding_key需要按照一定的匹配规则,匹配正确才成功。

            static bool route(ExchangeType type,const std::string& routing_key,const std::string& binding_key){switch (type){// 直接:相同才合法case ExchangeType::DIRECT:return routing_key == binding_key;break;// 广播:有绑定就合法case ExchangeType::FANOUT:return true;break;// 主题:匹配成功才合法case ExchangeType::TOPIC:return Topic(routing_key,binding_key);break;default:LOG("非法的匹配模式");return false;}}

        其中主题模式的匹配规则比较复杂,把它实现成一个私有静态的TOPIC()接口。

        匹配思想:

        (1)不含有'#'通配符:

        使用二维数组,对两个钥匙分割好的单词进行一一配对,匹配成功的话就从左上角继承结果,失败就设置为0。

        最右下角保存的值就是结果。

        因为思想是从左上角继承,所以行和列都需要多一行,并把[0][0]位置设置成1,否则第一行的数据就需要特殊处理了:

        (2)若'#'在中间:

        两个钥匙配对应该是成功的,但是结果是false,说明遇到'#'通配符时,不仅要从左上角继承,还要从上面继承结果:

         

        (3)若#在最前面 

        上述匹配也应该是成功的,结果却相反,说明遇到'#'时,不仅要从左上、上面继承,还要从左边继承:

        (4)若#在最前面,且表示零个单词

 

        也是应该成功的匹配返回了一个false,所以如果#在最前面,还要把第一行的第零列的位置设置成true:

        搞清楚#的4种情况之后,就可以开始编写代码了:

        private:static bool Topic(const std::string& routing_key,const std::string& binding_key){std::vector<std::string> sub_r_words;std::vector<std::string> sub_b_words;StrHelper::split(routing_key,".",sub_r_words);StrHelper::split(binding_key,".",sub_b_words);size_t m = sub_r_words.size();size_t n = sub_b_words.size();std::vector<std::vector<bool>> dp(n+1,std::vector<bool>(m+1));dp[0][0] = true;// 如果binding_key以"#"作为起始if(sub_b_words.size() > 0 && sub_b_words[0] == "#")dp[1][0]=true;for(int i = 1;i <= n;i++) {for(int j = 1;j<=m;j++){// 遇到"#"通配符if(sub_b_words[i-1] == "#"){dp[i][j] = dp[i-1][j-1] || dp[i][j-1] || dp[i-1][j];continue;}if(sub_b_words[i-1] == "*" || sub_b_words[i-1] == sub_r_words[j-1]){dp[i][j] = dp[i-1][j-1];continue;}}}return dp[n][m];}

 

第三节:单元测试

        在mqtest下创建mq_route_test.cc。

        使用以下代码进行测试:

#include "../mqserver/mq_route.hpp"
#include <gtest/gtest.h>
#include <iostream>
#include <unordered_map>// 全局测试套件------------------------------------------------
// 自己初始化自己的环境,使不同单元测试之间解耦
class RouterTest :public testing::Environment
{
public:// 全部单元测试之前调用一次virtual void SetUp() override{// std::cout << "单元测试执行前的环境初始化" << std::endl;}   // 全部单元测试之后调用一次virtual void TearDown() override{// std::cout << "单元测试执行后的环境清理" << std::endl;}
}; // 单元测试
// 测试名称与类名称相同,则会先调用SetUp
TEST(RouterTest,RouterTest_test1_Test)
{// 测试routing_key合法性检测std::cout << "单元测试-1" << std::endl;ASSERT_EQ(zd::Router::isLegalRoutingkey("news.music.pop.."),true);ASSERT_EQ(zd::Router::isLegalRoutingkey("news.music....pop.."),true);ASSERT_EQ(zd::Router::isLegalRoutingkey("....news.music.pop.."),true);ASSERT_EQ(zd::Router::isLegalRoutingkey("news.music.pop..#"),false);ASSERT_EQ(zd::Router::isLegalRoutingkey("news.music.pop..@"),false);ASSERT_EQ(zd::Router::isLegalRoutingkey("news.music.pop..*"),false);
}TEST(RouterTest,RouterTest_test2_Test)
{// 测试binding_key合法性检测std::cout << "单元测试-2" << std::endl;ASSERT_EQ(zd::Router::isLegalBindingkey("news.music.pop.."),true);ASSERT_EQ(zd::Router::isLegalBindingkey("news.music....pop.."),true);ASSERT_EQ(zd::Router::isLegalBindingkey("....news.music.pop.."),true);ASSERT_EQ(zd::Router::isLegalBindingkey("news.music.pop..#"),true);ASSERT_EQ(zd::Router::isLegalBindingkey("news.*.*"),true);ASSERT_EQ(zd::Router::isLegalBindingkey("news.music.p&op"),false);ASSERT_EQ(zd::Router::isLegalBindingkey("news.#music.pop"),false);ASSERT_EQ(zd::Router::isLegalBindingkey("news.*music.pop"),false);ASSERT_EQ(zd::Router::isLegalBindingkey("news.##.music.pop"),false);ASSERT_EQ(zd::Router::isLegalBindingkey("news.#*.music.pop"),false);ASSERT_EQ(zd::Router::isLegalBindingkey("news.*#.music.pop"),false);
}TEST(RouterTest,RouterTest_test3_Test)
{// routing_key 和 binding_key 的匹配测试std::cout << "单元测试-3" << std::endl; ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","#"),true);ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","news.music.#"),true);ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","#.music.pop"),true);ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","#.pop"),true);ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","#.music.pep"),false);ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","nows.music.pop"),false);ASSERT_EQ(zd::Router::route(zd::ExchangeType::TOPIC,"news.music.pop","news.musics.pop"),false);ASSERT_EQ(zd::Router::route(zd::ExchangeType::DIRECT,"news.music.pop","#.pop"),false);ASSERT_EQ(zd::Router::route(zd::ExchangeType::DIRECT,"news.music.pop","news.music.pop"),true);
}
// 单元测试全部结束后调用TearDown// ----------------------------------------------------------
int main(int argc,char** argv)
{testing::InitGoogleTest(&argc,argv);testing::AddGlobalTestEnvironment(new RouterTest); // 注册Test的所有单元测试if(RUN_ALL_TESTS() != 0) // 运行所有单元测试{printf("单元测试失败!\n");}return 0;
}

        测试结果:

                ​​​​​​​        ​​​​​​​        

        没有报错且符合预期

下期预告:

        之后将实现服务器消费者模块的搭建,它的思路和消息管理模块类似,都是每个队列管理自己的消费者/订阅者,最后封装一个管理所有队列消费者的模块。 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com