拒做PB Boy!教你巧用 Protobuf 反射来优化代码( 四 )

通过上面的代码,如果需要在 proto 中增加字段,不再需要修改原来的代码 。
3.2 将字段校验规则放置在 Proto 中后台服务接收到前端传来的字段后,会对字段进行校验,比如必填校验,长度校验,正则校验,xss 校验等,这些规则我们常常会硬编码在代码中 。但是随着后台字段的增加,校验规则代码会变得越来越多,越来越难维护 。如果我们把字段的定义和校验规则和定义放在一起,这样是不是更好的维护?
示例 proto 如下:
syntax = "proto2";package student;import "google/protobuf/descriptor.proto";message FieldRule{    optional uint32 length_min = 1; // 字段最小长度    optional uint32 id         = 2; // 字段映射id}extend google.protobuf.FieldOptions{    optional FieldRule field_rule = 50000;}message Student{    optional string name   =1 [(field_rule).length_min = 5, (field_rule).id = 1];    optional string email = 2 [(field_rule).length_min = 10, (field_rule).id = 2];}然后我们自己实现 xss 校验,必填校验,长度校验,选项校验等代码 。
示例校验最小长度代码如下:
#include <IOStream>#include "student.pb.h"#include <google/protobuf/descriptor.h>#include <google/protobuf/message.h>using namespace std;using namespace student;using namespace google::protobuf;bool minLengthCheck(const std::string &strValue, const uint32_t &dwLenthMin) {    return strValue.size() < dwLenthMin;}int allCheck(const google::protobuf::Message &oMessage){    const auto *poReflect = oMessage.GetReflection();    vector<const FieldDescriptor *> vecFD;    poReflect->ListFields(oMessage, &vecFD);    for (const auto &poFiled : vecFD) {        const auto &oFieldRule = poFiled->options().GetExtension(student::field_rule);        if (poFiled->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_STRING && !poFiled->is_repeated()) {            // 类型是string并且选项非重复的才会校验字段长度类型            const std::string strValue = poReflect->GetString(oMessage, poFiled);            const std::string strName = poFiled->name();            if (oFieldRule.has_length_min()) {                // 有才进行校验,没有则不进行校验                if (minLengthCheck(strValue, oFieldRule.length_min())) {                    cout << "the length of " << strName << " is lower than " << oFieldRule.length_min()<<endl;                } else {                    cout << "check min lenth pass"<<endl;                }            }        }    }    return 0;}int main() {    Student oStudent1;    oStudent1.set_name("xiao");    Student oStudent2;    oStudent2.set_name("xiaowei");    allCheck(oStudent1);    allCheck(oStudent2);    return 0;}如上,如果需要校验最大长度,必填,xss 校验,只需要使用工厂模式,扩展代码即可 。


推荐阅读