C++基于多设计模式下的同步异步日志系统day3

C++基于多设计模式下的同步&异步日志系统day3

📟作者主页:慢热的陕西人

🌴专栏链接:C++基于多设计模式下的同步&异步日志系统

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

主要内容日志项目的输出格式化类的设计和日志落地(LogSink)类设计(简单工厂模式)

在这里插入图片描述

文章目录

  • C++基于多设计模式下的同步&异步日志系统day3
  • 1.代码设计
      • 1.1日志输出格式化类设计
      • 1.2日志落地(LogSink)类设计(简单工厂模式)

1.代码设计

1.1日志输出格式化类设计

⽇志格式化(Formatter)类主要负责格式化⽇志消息。其主要包含以下内容

  • pattern成员:保存⽇志输出的格式字符串。
    ◦ %d⽇期
    ◦ %T缩进
    ◦ %t线程id
    ◦ %p⽇志级别
    ◦ %c⽇志器名称
    ◦ %f⽂件名
    ◦ %l⾏号
    ◦ %m⽇志消息
    ◦ %n换⾏

  • std::vectorFormatItem::ptritems成员:⽤于按序保存格式化字符串对应的⼦格式化对象

FormatItem类主要负责⽇志消息⼦项的获取及格式化。其包含以下⼦类

  • MsgFormatItem:表⽰要从LogMsg中取出有效⽇志数据
  • LevelFormatItem:表⽰要从LogMsg中取出⽇志等级
  • NameFormatItem:表⽰要从LogMsg中取出⽇志器名称
  • ThreadFormatItem:表⽰要从LogMsg中取出线程ID
  • TimeFormatItem:表⽰要从LogMsg中取出时间戳并按照指定格式进⾏格式化
  • CFileFormatItem:表⽰要从LogMsg中取出源码所在⽂件名
  • CLineFormatItem:表⽰要从LogMsg中取出源码所在⾏号
  • TabFormatItem:表⽰⼀个制表符缩进
  • NLineFormatItem:表⽰⼀个换⾏
  • OtherFormatItem:表⽰⾮格式化的原始字符串

⽰例:“[%d{%H:%M:%S}]%m%n”

pattern = "[%d{%H:%M:%S}] %m%n"
items = {
{OtherFormatItem(), "["},
{TimeFormatItem(), "%H:%M:%S"},
{OtherFormatItem(), "]"},
{MsgFormatItem (), ""},
{NLineFormatItem (), ""}
}
LogMsg msg = {
size_t _line = 22;
size_t _ctime = 12345678;
std::thread::id _tid = 0x12345678;
std::string _name = "logger";
std::string _file = "main.cpp";
std::string _payload = "创建套接字失败";
LogLevel::value _level = ERROR;
};

格式化的过程其实就是按次序从Msg中取出需要的数据进⾏字符串的连接的过程。
最终组织出来的格式化消息:“[22:32:54]创建套接字失败\n”

代码实现:

#ifndef __M_FMT_H__
#define __M_FMT_H__


#include"message.hpp"
#include<time.h>
#include<vector>
#include<cassert>
#include<sstream>


namespace xupt
{
    //抽象格式化子类基类
    class FormatItem
    {
        public:
            using ptr = std::shared_ptr<FormatItem>;
            virtual void format(std::ostream& out, const LogMsg &msg) = 0; 
    };

    //派生格式化子类项---消息,等级,时间,文件名,行号,线程ID,日志器名,制表符,换行,其他
    class MsgFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << msg._payload;
            }
    };

    class LevelFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << LogLevel::toString(msg._level);
            }
    };

    class TimeFormatItem : public FormatItem
    {
        public:
            TimeFormatItem(const std::string &fmt = "%H:%M:%S"):_time_fmt(fmt){}
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                struct tm t;
                localtime_r(&msg._ctime, &t);
                char tmp[128];
                strftime(tmp, 127, _time_fmt.c_str(), &t);
                out << tmp;
            }
        private:
            std::string _time_fmt;
    };    

    class FileFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << msg._file;
            }
    };   

    class LineFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << msg._line;
            }
    };   

    class ThreadFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << msg._tid;
            }
    };   

    class LoggerFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << msg._logger;
            }
    };  

    class TabFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << "\t";
            }
    };    

    class NewLineFormatItem : public FormatItem
    {
        public:
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << "\n";
            }
    };   

    class OtherFormatItem : public FormatItem
    {
        public:
            OtherFormatItem(const std::string str):_str(str){}
            virtual void format(std:: ostream& out, const LogMsg &msg)
            {
                out << _str;
            }
        private:
            std::string _str;
    };   



    class Formatter
    {
        public:
            Formatter(const std::string & pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
            :_pattern(pattern)
            {
                assert(parsePattern()); //如果解析失败直接跳断言
            }

            //对msg进行格式化
            void format(std::ostream& out ,const  LogMsg & Msg)
            {
                for(auto& item : _items)
                {
                    item->format(out, Msg);
                }
            }
            std::string format(const LogMsg & Msg)
            {
                std::stringstream ss;
                format(ss, Msg);
                return ss.str();
            }
        private:
            //对格式化规则字符串进行解析
            bool parsePattern()
            {
                //1.对格式化规则字符串进行解析
                //abcd[%d{%H:%M:%S}][%p]%T%m%n
                std::vector<std::pair<std::string, std::string>> fmt_order;
                size_t pos = 0;

                std::string key, val;                
                while(pos < _pattern.size())
                {
                    //1.处理原始字符串,如果不是%,那么就是原始字符
                    if(_pattern[pos] != '%')
                    {
                        val.push_back(_pattern[pos++]);
                        continue;
                    }
                    //%的情况
                    //1.双%的情况
                    if(pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                    {
                        val.push_back('%'); pos += 2; continue;
                    }

                    //能走到这里,代表%后是一个格式化字符串,这时候代表原始字符串处理完毕
                    if(val.empty() == false)
                    {
                        fmt_order.push_back(std::make_pair("", val));
                        val.clear();
                    }

                    //2.%后是格式化字符的情况
                    pos += 1;//这一步之后,pos指向格式化字符位置
                    if(pos == _pattern.size())
                    {
                        std::cout << "%后没有对应的格式化字符" << std::endl;
                        return false;
                    }

                    key = _pattern[pos];
                    //2.{}的情况
                    pos += 1;
                    if(_pattern[pos] == '{')
                    {
                        pos += 1; //这时候pos指向子规则的起始位置
                        while(pos < _pattern.size() && _pattern[pos] != '}')
                        {
                            val.push_back(_pattern[pos++]);
                        }

                        //走到了末尾跳出了循环,则代表没有遇到},代表格式是错误的
                        if(pos == _pattern.size())  //没有找到}
                        {
                            std::cout << "子规则{}匹配失败" << std::endl;
                            return false;
                        }
                        pos += 1;
                    }
                    fmt_order.push_back(std::make_pair(key, val));
                    key.clear();
                    val.clear();
                }
                //2.根据解析得到的数据初始化子项数组成员
                for(auto &it : fmt_order)
                {
                    _items.push_back(createItem(it.first,it.second));
                }

                return true;
            }
        
            //根据不同的格式化字符创建不同的格式化子项对象
            FormatItem::ptr createItem(const std::string & key, const std::string &val)
            {
               if(key == "d") return std::make_shared<TimeFormatItem>(val);
               if(key == "t") return std::make_shared<ThreadFormatItem>();
               if(key == "c") return std::make_shared<LoggerFormatItem>();
               if(key == "f") return std::make_shared<FileFormatItem>();
               if(key == "l") return std::make_shared<LineFormatItem>();
               if(key == "p") return std::make_shared<LevelFormatItem>();
               if(key == "T") return std::make_shared<TabFormatItem>();
               if(key == "m") return std::make_shared<MsgFormatItem>();
               if(key == "n") return std::make_shared<NewLineFormatItem>();
               if(key.empty()) return std::make_shared<OtherFormatItem>(val);

               std::cout << "没有对应的格式化字符串:%" << key << std::endl;
               abort();
               return FormatItem::ptr();
            }
        private:
            std::string _pattern; //格式化规则字符串
            std::vector<FormatItem::ptr> _items; 
    };


}


#endif

1.2日志落地(LogSink)类设计(简单工厂模式)

⽇志落地类主要负责落地⽇志消息到⽬的地

它主要包括以下内容:

  • Formatter⽇志格式化器:主要是负责格式化⽇志消息。
  • mutex互斥锁:保证多线程⽇志落地过程中的线程安全,避免出现交叉输出的情况。这个类⽀持可扩展,其成员函数log设置为纯虚函数,当我们需要增加⼀个log输出⽬标,可以增加⼀个类继承⾃该类并重写log⽅法实现具体的落地⽇志逻辑。

目前实现了三个不同方向上的日志落地:

  • 标准输出:StdoutSink

  • 固定文件:FileSink

  • 滚动文件:RollSinkBySize

    ◦ 滚动⽇志⽂件输出的必要性:

    ​ • 由于机器磁盘空间有限,我们不可能⼀直⽆限地向⼀个⽂件中增加数据

    ​ • 如果⼀个⽇志⽂件体积太⼤,⼀⽅⾯是不好打开,另⼀⽅⾯是即时打开了由于包含数据巨⼤,也不利于查找我们需要的信息

    ​ • 所以实际开发中会对单个⽇志⽂件的⼤⼩也会做⼀些控制,即当⼤⼩超过某个⼤⼩时(如1GB),我们就重新创建⼀个新的⽇志⽂件来滚动写⽇志。对于那些过期的⽇志,⼤部分企业内部都有专⻔的运维⼈员去定时清理过期的⽇志,或者设置系统定时任务,定时清理过期⽇志

    ◦ ⽇志⽂件的滚动思想:

    ⽇志⽂件滚动的条件有两个:⽂件⼤⼩和时间。我们可以选择:

    • ⽇志⽂件在⼤于1GB的时候会更换新的⽂件
    • 每天定点滚动⼀个⽇志⽂件

    本项⽬基于⽂件⼤⼩的判断滚动⽣成新的⽂件

    /*  
        日志落地模块的实现
        1.抽象落地基类
        2.派生落地子类(根据不同的落地方向)
        3.使用工厂模式进行使用和生产的分离
    */
    
    #ifndef __M_SIK_H__
    #define __M_SIK_H__
    
    
    #include"util.hpp"
    #include<memory>
    #include<fstream>
    #include<cassert>
    #include<sstream>
    
    
    
    namespace xupt 
    {
        class LogSink
        {
            public:
                using ptr = std::shared_ptr<LogSink>;
                LogSink() {}
                virtual ~LogSink() {}
                virtual void log(const char* data, size_t len) = 0; 
        };  
    
        //落地方向:标准输出
        class StdoutSink : public LogSink
        {
            public:
                virtual void log(const char* data, size_t len)
                {
                    std::cout.write(data, len);
                }
        };
        //落地方向:指定文件
        class FileSink : public LogSink
        {
            public:
                FileSink(const std::string &pathname):_pathname(pathname)
                {
                    //1.创建日志文件所在的目录
                    util::File::CreateDirectory(util::File::path(_pathname));
                    //2.创建并打开日志文件
                    _ofs.open(_pathname, std::ios::binary | std::ios::app); //以二进制追加的方式写入
                    //断言以下是否打开成功
                    assert(_ofs.is_open());
                }
                //写入到文件
                virtual void log(const char* data, size_t len)
                {
                    _ofs.write(data, len);
                    assert(_ofs.good());
                }
            private:
                std::string _pathname;
                std::ofstream _ofs;
        };
        //落地方向:滚动文件(以大小进行滚动)
        class RollSinkBySize : public LogSink
        {
            public:
                //构造函数,传入文件名,文件大小,并管理文件输出句柄
                RollSinkBySize(const std::string &basename, size_t max_size):
                _basename(basename), _max_size(max_size),_cur_size(0),_name_count(0)
                {
                    std::string pathname = createNewFile();
                    //1.创建日志文件所在的目录                
                    util::File::CreateDirectory(util::File::path(pathname));
                    //2.创建并打开日志文件
                    _ofs.open(pathname, std::ios::binary | std::ios::app); //以二进制追加的方式写入
                    //断言以下是否打开成功
                    assert(_ofs.is_open());                    
                }
                //将日志消息写入到文件,写入前判断文件大小,超过了最大大小,就要切换文件
                virtual void log(const char* data, size_t len)
                {
                    if(_cur_size >= _max_size)
                    {
                        //先关闭之前的文件
                        _ofs.close();
                        //创建新的文件
                        std::string pathname = createNewFile();
                        _ofs.open(pathname,std::ios::binary | std::ios::app);
                        //断言以下是否打开成功
                        assert(_ofs.is_open()); 
                        //置零当前文件大小
                        _cur_size = 0;
                    }
                    //写入?没有更改_cur_size
                    _ofs.write(data, len);
                    //断言以下是否成功写入
                    assert(_ofs.good());   
                    _cur_size += len;            
                }
    
            private:
                //当文件大小达到限制的时候,用于切换文件使用(创建新的文件名,并不能创建文件)    
                std::string createNewFile()
                {
                    //获取系统时间
                    time_t t = util::Date::now();
                    struct tm lt;
                    localtime_r(&t, &lt);
                    //创建一个字符串流
                    std::stringstream filename;
                    filename << _basename;
                    filename << lt.tm_year + 1900;
                    filename << lt.tm_mon + 1;
                    filename << lt.tm_mday;
                    filename << lt.tm_hour;
                    filename << lt.tm_min;
                    filename << lt.tm_sec;
                    filename << "-";
                    filename << _name_count++;
                    filename << ".log";
    
                    return filename.str();
                }
            private:
                size_t _name_count ; //用于区别文件名的
                std::string _basename; //存储日志信息的文件, 命名规则我们一般是加一个固定的头,尾部用时间来区分
                std::ofstream _ofs; //维护一个我们的文件输出句柄
                size_t _max_size;     //单个文件的最大大小
                size_t _cur_size;    //当前文件的大小,算是一个优化,这样我们就不用去频繁查看文件属性,从而降低效率
        };
    
    /*
        拓展一个以时间作为文件滚动切换类型的日志落地模块
    */  
        class RollSinkByTime : public LogSink
        {
            public:
                enum class TimeGap
                {
                    GAP_SECOND,
                    GAP_MINUTE,
                    GAP_HOUR,
                    GAP_DAY,
                };
            
            public:
                RollSinkByTime(const std::string &basename, TimeGap gap_type):_basename(basename)
                {
                    switch(gap_type) 
                    {
                        case TimeGap::GAP_SECOND : _gap_size = 1; break;
                        case TimeGap::GAP_MINUTE : _gap_size = 60; break;
                        case TimeGap::GAP_HOUR : _gap_size = 3600; break;
                        case TimeGap::GAP_DAY : _gap_size = 3600 * 24; break;
                    }
                    
                    _cur_gap = _gap_size == 1 ? util::Date::now() : util::Date::now() % _gap_size;  //初始化当前的时间片
                    util::File::CreateDirectory(util::File::path(_basename)); //1.创建日志文件所在的目录      
                    std::string filename = createNewFile();  //2.创建文件名,并且打开文件
                    _ofs.open(filename,std::ios::binary | std::ios::app);
                    assert(_ofs.is_open());                 
    
                }
                //写入到文件,判断当前的时间段,是否是当前文件的时间段,不是则切换文件
                virtual void log(const char* data, size_t len)
                {
                    //获取系统时间
                    time_t cur = util::Date::now();                
    
                    if(cur % _gap_size != _cur_gap)
                    {
                        _ofs.close();
                        std::string filename = createNewFile();  
                        _ofs.open(filename,std::ios::binary | std::ios::app);
                        assert(_ofs.is_open());                                      
                    }
                    //写入文件
                    _ofs.write(data, len);
                    assert(_ofs.good());
                }
    
            private:
                //当时间片达到限制的时候,用于切换文件使用,(创建新的文件名,并不能创建文件)   
                std::string createNewFile()
                {
                    //获取系统时间
                    time_t t = util::Date::now();
                    struct tm lt;
                    localtime_r(&t, &lt);
                    //创建一个字符串流
                    std::stringstream filename;
                    filename << _basename;
                    filename << lt.tm_year + 1900;
                    filename << lt.tm_mon + 1;
                    filename << lt.tm_mday;
                    filename << lt.tm_hour;
                    filename << lt.tm_min;
                    filename << lt.tm_sec;
                    filename << "-";
                    filename << ".log";
    
                    return filename.str();
                }
            private:
                std::string _basename;
                std::ofstream _ofs;
                size_t _cur_gap;
                size_t _gap_size;
        };
    
        class SinkFactory
        {
            public:
                template<typename SinkType, typename ...Args>
                static LogSink::ptr create(Args && ...args) //右值引用,保持原来类型的属性,用于后来的完美转发
                {
                    return std::make_shared<SinkType>(std::forward<Args>(args)...);
                }
        };
    }
    
    
    
    #endif
    

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/424882.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C习题002:澡堂洗澡

问题 输入样例 在这里给出一组输入。例如&#xff1a; 2 5 1 3 3 2 3 3 输出样例 在这里给出相应的输出。例如&#xff1a; No代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB 代码 #include<stdio.h> int main() {int N,W,s,t,p;int arr_s[…

投影和定义投影的区别

Arcmap中关于投影的工具有四个&#xff0c;分别是定义投影、投影、投影栅格、批量投影。这四个工具既有相同之处也有不同之处&#xff0c;下面我将一一介绍。 ①定义投影&#xff1a;Arcmap中关于定义投影工具是这样描述的&#xff1a;“所有地理数据集均具有一个用于显示、测…

小白必看的Python函数讲解

定义函数 我们通过斐波那契数列来理解定义函数 >>> def fib(n): # 将斐波那契数列打印到 n ... """将斐波那契数列打印到 n""" ... a, b 0, 1 ... while a < n: ... print(a, end ) ... a, b b, …

【Linux安装软件命令及vim、gcc使用说明】

安装软件命令 Linux安装软件的命令首先要进入管理员权限 首先在终端输入sudo su切换到管理员界面 输入对应的密码&#xff0c;注意这里的密码不会显示出来&#xff0c;输完密码之后回车即可。当出现root就代表已经是管理员界面了。 如果相应退出管理员界面输入exit即可。 注…

出现这6点症状,不要拖延,不然植物神经紊乱会找到你!

植物神经紊乱&#xff0c;是一种由于自主神经系统失衡引起的疾病。自主神经系统主要负责调节人体内脏器官的功能&#xff0c;包括心脏、血管、消化系统等&#xff0c;一旦失衡将导致一系列不适症状。植物神经紊乱的主要原因包括长期的焦虑、压力、过度疲劳、情绪波动、生活节奏…

从零开始的二进制漏洞挖掘(1)路由器漏洞挖掘(去实战版)

前言 路由器的洞大部分都是栈溢出&#xff0c;如果想要了解一些相关的知识&#xff0c;可以去看我的pwn和二进制安全虚拟机Protostar靶场系列文章&#xff0c;传送门&#xff1a; https://blog.csdn.net/qq_45894840/category_12002228.html?spm1001.2014.3001.5482ghidra安…

2024全新手机软件下载应用排行、平台和最新发布网站,采用响应式织梦模板

这是一款简洁蓝色的手机软件下载应用排行、平台和最新发布网站&#xff0c;采用响应式织梦模板。 主要包括主页、APP列表页、APP详情介绍页、新闻资讯列表、新闻详情页、关于我们等模块页面。 地 址 &#xff1a; runruncode.com/php/19703.html 软件程序演示图&#xff1a;…

领域驱动设计(Domain-Driven Design DDD)——战略设计1

一、概述 随着系统的增长&#xff0c;它会越来越复杂&#xff0c;当我们无法通过分析对象来理解系统的时候&#xff0c;就需要掌握一些操纵和理解大模型的技术了。 最负雄心的企业欲实现一个涵盖所有业务、紧密集成的系统。因大型公司的业务模型巨大且复杂&#xff0c;很难把它…

Elasticsearch:如何创建搜索引擎

作者&#xff1a;Jessica Taylor 搜索引擎是生活中我们认为理所当然的事情之一。 每当我们寻找某些东西时&#xff0c;我们都会将一个单词或短语放入搜索引擎&#xff0c;就像魔术一样&#xff0c;它会为我们提供一个匹配结果列表。 现在可能感觉不那么神奇了&#xff0c;因为这…

【CSS】(标准流部分)易忘知识点汇总

一、元素 块元素 常见的块元素&#xff1a; <h1>~<h6>、<p>、<div>、<ul>、<ol>、<li>行内元素 常见的行内元素&#xff1a; <a>、<strong>、<b>、<em>、<i>、<del>、<s>、<ins&…

卷积神经网络CNN

图像基础知识 图像是由像素点组成的&#xff0c;每个像素点的取值范围为 : [0, 255] 。像素值越接近于 0 &#xff0c;颜色越暗&#xff0c;接近于黑色&#xff1b;像素值越接 近于255 &#xff0c;颜色越亮&#xff0c;接近于白色。 在深度学习中&#xff0c;我们使用的图像…

图神经网络实战——图论基础

图神经网络实战——图论基础 0. 前言1. 图属性1.1 有向图和无向图1.2 加权图和非加权图1.3 连通图和非连通图1.4 其它图类型 2. 图概念2.1 基本对象2.2 图的度量指标2.2 邻接矩阵表示法 3. 图算法3.1 广度优先搜索3.2 深度优先搜索 小结系列链接 0. 前言 图论 (Graph theory) …

@Transactional--开启事物后换源报错

一、问题出现的场景 系统架构设计、每个企业一个企业库、通过数据源切在平台库、和企业库之间动态切换完成业务操作。 二、跨库事物失效的原因 1、SpringTransactional不支持跨数据源事物&#xff0c;Spring 事物控制是基于数据库链接进行的&#xff0c;当数据源切换后&#x…

Python算法题集_单词搜索

Python算法题集_单词搜索 题22&#xff1a;单词搜索1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【原始矩阵状态回溯】2) 改进版一【字典检测原始矩阵状态回溯】3) 改进版二【矩阵状态回溯】 4. 最优算法5. 相关资源 本文为Python算法题集之一…

【Datawhale组队学习:Sora原理与技术实战】Attention

Attention Attention 注意力&#xff0c;从两个不同的主体开始。 论文&#xff1a;https://arxiv.org/pdf/1703.03906.pdf seq2seq代码仓&#xff1a;https://github.com/google/seq2seq 计算方法&#xff1a; 加性Attention&#xff0c;如&#xff08;Bahdanau attention&…

electron-release-server部署electron自动更新服务器记录

目录 一、前言 环境 二、步骤 1、下载上传electron-release-server到服务器 2、宝塔新建node项目网站 3、安装依赖 ①npm install ②安装并配置postgres数据库 ③修改项目配置文件 ④启动项目 ⑤修改postgres的认证方式 ⑥Cannot find where you keep your Bower p…

Sqli-labs靶场第12关详解[Sqli-labs-less-12]

Sqli-labs-Less-12 #手工注入 post传参了 根据题目看&#xff0c;像一个登录页面&#xff0c;尝试使用布尔型盲注测试能否登录网站 1. Username输入a a" 测试是否会有报错&#xff0c;burp抓包 报错&#xff1a;syntax to use near "a"") and passw…

【风格迁移】pix2pixHD:高分辨率图像生成

pix2pixHD&#xff1a;高分辨率图像生成 提出背景问题1: 如何提高生成图像的照片级真实感和分辨率&#xff1f;问题2: 如何利用实例级别的对象语义信息进一步提高图像质量&#xff1f;问题3: 如何实现图像合成的多模态性&#xff0c;允许交互式对象编辑&#xff1f; pix2pixHD …

Vue3中Vuex状态管理库学习笔记

1.什么是状态管理 在开发中&#xff0c;我们会的应用程序需要处理各种各样的数据&#xff0c;这些数据需要保存在我们应用程序的某个位置&#xff0c;对于这些数据的管理我们就称之为状态管理。 在之前我们如何管理自己的状态呢&#xff1f; 在Vue开发中&#xff0c;我们使用…

02、MongoDB -- MongoDB 的安全配置(创建用户、设置用户权限、启动安全控制、操作数据库命令演示、mongodb 的帮助系统介绍)

目录 MongoDB 的安全配置演示前准备&#xff1a;启动 mongodb 服务器 和 客户端 &#xff1a;1、启动单机模式的 mongodb 服务器2、启动 mongodb 的客户端 MongoDB 的安全配置启动演示用到的 mongodb 服务器 和 客户端启动单机模式的 mongodb 服务器&#xff1a;启动 mongodb 的…