首页 > 其他分享 >业务处理模块

业务处理模块

时间:2023-09-05 22:01:39浏览次数:26  
标签:info 文件 string 处理 业务 server std 模块 rsp

//业务处理模块 #ifndef SERVICE_H #define SERVICE_H #include "data.hpp" #include "httplib.h" extern nmzcloud::DataManager* _data;//因为也会访问数据管理类 namespace nmzcloud{ class Service{ private: int _server_port; std::string _server_ip; std::string _download_prefix;//下载前缀路径 httplib::Server _server; private: //业务处理接口 //上传业务处理接口 static void Upload(const httplib::Request &req,httplib::Response &rsp) { //文件上传是一个post请求的upload才可以 //文件数据在正文中,是一个分区存储(正文并不全是文件数据) auto ret = req.has_file("file");//判断有没有这个上传的文件区域 if(ret == false) { rsp.status = 400;//设置状态码为400 return; } const auto& file = req.get_file_value("file");//如果有的话获取文件数据 //里面就包含了文件名称和正文数据 // file.filename;//文件名称 file.content;//文件数据 //此时需要在备份目录下创建这个文件把数据写入进去 std::string back_dir = Config::GetInstance()->GetBackDir();//获取备份目录 std::string realpath = back_dir + FileUtil(file.filename).FileName();//文件的实际存储路径 FileUtil fu(realpath);//将文件的实际路径给进去 fu.SetContent(file.content);//将数据写入文件中 BackupInfo info; info.NewBackupInfo(realpath);//组织备份的文件信息 _data->Insert(info);//向数据管理模块添加备份的文件信息 return ; } //实现一个接口将时间戳转换成时间格式的字符串 static std::string TimeToStr(time_t t) { std::string tmp = std::ctime(&t); return tmp; } //展示页面获取处理接口 static void ListShow(const httplib::Request &req,httplib::Response &rsp) { //展示页面的获取就是获取一个html页面,html页面前面已经搞好了 // 最终要组织的就是拥有所有文件信息的html文件数据,最终把这个数据响应给客户端就可以了。 // 所以在处理这个展示页面的时候,我们有两个过程 // 1、获取所有的文件备份信息 // 服务器一运行就从原来备份的持久化存储文件中加载数据 std::vector<BackupInfo> array; _data->GetAll(&array);//获取到所有的信息 // 2、根据所有备份信息组织成一个html文件数据 // html中要根据不同的文件进行不同的改变 std::stringstream ss;//使用字符串流 ss << "<html><head><title>DownLoad</title></head>"; ss << "<body>DownLoad<table>"; for(auto & a: array) { //根据每一个不同的文件组织中间的数据 ss << "<tr>"; //url链接随着资源的不同而不同 //html中不区分单引号和双引号,所以改成单引号//进来之后我们要写入我们的url链接了 std::string filename = FileUtil(a.real_path).FileName();//只要文件名 ss << "<td> <a rel="nofollow" href = '" << a.url << "'>" << filename << "</a></td>"; ss << "<td align = 'right'>" << TimeToStr(a.mtime) << "</td>";//a.mtime是一个时间戳并不是格式时间 ss << "<td align = 'right'>" << a.fsize/1024 << "K</td>"; //文件大小,以K为单位 ss << "</tr>"; } ss<< "</table></body></html>";//结尾 rsp.body = ss.str(); //设置头信息 rsp.set_header("Content-Type","text/html"); rsp.status = 200; return ; } //下载处理接口 //先生成一个GetETag,获取文件的ETag,传递一个文件的路径进来 static std::string GetETag(const BackupInfo &info) { //ETag:filename-fsize-mtime FileUtil fu(info.real_path); std::string etag = fu.FileName(); etag += "-"; etag += std::to_string(info.fsize); etag += "-"; etag += std::to_string(info.mtime); return etag; } static void Download(const httplib::Request &req,httplib::Response &rsp) { // 1、获取客户端请求的资源路径path---其实就是req里面的path // 2、根据req资源路径,获取文件备份信息 BackupInfo info; _data->GetOneByURL(req.path,&info); // 3、判断文件是否被压缩,如果被压缩要先解压缩 if(info.pack_flag == true) { FileUtil fu(info.pack_path); fu.UnCompress(info.real_path); // 删除压缩包,修改文件信息(此时已经没有被压缩) info.pack_flag = false; fu.Remove(); info.pack_flag = false; _data->Update(info);//修改 }

        //判断是否存在某个头部字段,如果有就是断点续传,如果没有就不是断点续传
        bool retrans = false;//用于标记当前是否是断点续传
        //如果没有If-Range字段则是正常下载,或者如果有这个字段,但是他的值与当前文件的etag不一致
        // 则也必须重新返回全部数据,为新的文件下载
        std::string old_etag;//就是原来我们下载的那个etag的值,到时候请求的时候会把etag的值给我们放到
        // 请求的If-range里面去,我们就可以把他取出来
        if(req.has_header("If-Range"))
        {
            old_etag = req.get_header_value("If-Range");
            //有If-Range字段且这个字段的值与请求文件的最新etag一致则符合断点续传的要求
            if(old_etag == GetETag(info))
            {
                retrans = true;
            }
        }
        // 4、读取文件数据,放入rsp.body中
        FileUtil fu(info.real_path);
        //如果retrans==false则是正常的文件下载
        if(retrans == false){
            fu.GetContent(&rsp.body);
            // 5、设置响应头部字段:ETag,Accept-Ranges:bytes
            rsp.set_header("Accept-Ranges","bytes");
            rsp.set_header("ETag",GetETag(info));
            rsp.set_header("Content-Type","application/octet-stream");//表示想要的正文是一个二进制数据流,常用于文件下载
            rsp.status = 200;
        }
        else{
            //此时就表示是一个断点续传,我们就要取出range字段了解请求区间的范围然后去读取指定区间的一个数据
            // 但是我们不需要这样做了,因为当初设计这个项目的时候,我们的httplib里面已经支持了断点续传的响应
            // httplib里面已经进行了解析,判断解析了之后有没有range头部字段,内部请求的区间范围是什么
            // 所以我们目前要做的就是读取文件数据到rsp.body中去
            fu.GetContent(&rsp.body);
            rsp.set_header("Accept-Ranges","bytes");
            rsp.set_header("ETag",GetETag(info));
            rsp.set_header("Content-Type","application/octet-stream");//表示想要的正文是一个二进制数据流,常用于文件下载
            rsp.status = 206;//其实我们不用给,httplib里都已经操作了
        }
    }
public:
    //构造函数
    Service()
    {
        //_server直接实例化完毕,不需要进行初始化
        //而剩下的成员变量中的数据是从配置文件中获取到的
        nmzcloud::Config* config = Config::GetInstance();//获取句柄
        _server_port = config->GetServerPort();
        _server_ip = config->GetServerIp();
        _download_prefix = config->GetDownloadPrefix();
        //我们还要考虑文件的备份目录,如果文件备份目录不存在肯定是要进行创建的
    }
    //运行模块
    bool RunModule()
    {
        //搭建服务器
        //注册一个映射关系,哪一个请求方法的什么请求应该用哪一个函数处理先提前注册告知我们的server
        // 收到请求进行调用处理
        _server.Post("/upload",Upload);//Post请求的upload则表示文件资源的上传
        _server.Get("/listshow",ListShow);//文件列表请求
        _server.Get("/",ListShow);//文件列表请求
       //第一个参数是文件名,那么这个文件名到底是什么呢?所以这时候就用到了正则表达式的规则匹配,只要能够
    //    去匹配一个字符串就行了,不管后面是什么样的文件名,所以后面加上括号,捕捉这个数据
        std::string download_url = _download_prefix + "(.*)";
       _server.Get(download_url,Download);//文件下载请求,.*表示匹配任意一个字符任意次
       _server.listen(_server_ip.c_str(),_server_port);
        return true;
    }
};

} #endif

标签:info,文件,string,处理,业务,server,std,模块,rsp
From: https://blog.51cto.com/u_15562309/7380300

相关文章

  • 【SAP系统迁移】后续处理
      在数据库还原-systemcopy/DBrefresh之后SAP内的一些设定会保留旧系统的设定这些设定是否需要更改,则要根据情况去判断。 下面整理了一些可能会用得到的T-code:1.SE06、STMS(传输系统需要重新设定,注意CTC等参数)2.SICK、SM28(没有错误即可)3.SCC4、SE03(某些修改可能需......
  • C++中模块(DLL)对外暴露接口的几种方式
    函数导出:通过在函数前面加上导出修饰符(如__declspec(dllexport))来导出函数。优点是简单易用,缺点是无法避免函数名冲突,且需要手动导出每个函数。.def文件:通过定义一个.def文件,在其中指定要导出的函数名和入口点。优点是可以一次性导出多个函数,缺点是需要额外的.def文件,且与代码分......
  • 错误处理
    错误处理 axios.get('/user/12345').catch(function(error){if(error.response){//请求成功发出且服务器也响应了状态码,但状态代码超出了2xx的范围console.log(error.response.data);console.log(error.response.status);console.l......
  • 深入解析 MyBatis 中的 <foreach> 标签:优雅处理批量操作与动态 SQL
    在当今的Java应用程序开发中,数据库操作是一个不可或缺的部分。MyBatis作为一款颇受欢迎的持久层框架,为我们提供了一种优雅而高效的方式来管理数据库操作。在MyBatis的众多特性中,<foreach>标签无疑是一个强大的工具,它使得在SQL语句中进行动态循环迭代变得轻而易举。本文将带您深入探......
  • MySQL数据高阶处理技巧:掌握先排序后分组的智慧
    在MySQL数据库的数据探索旅程中,排序和分组是不可或缺的工具。然而,当你面对大量数据、重复值等情况时,常规的处理方法可能显得不够灵活。本文将为你揭示一个精妙的技巧:如何在MySQL中先排序,后分组,从而获取每个类型的最新数据,助你轻松驾驭复杂的数据处理任务。问题背景:先排序,后分组拥有......
  • 金蝶云星空创建带分录的业务单据模板(协同开发云)
     业务对象的创建方式有新建、复制、继承三种:新建:基于空白对象创建,不受任何约束,灵活度高,元素、菜单都需要自行添加。常用于动态表单、移动业务的开发。复制:原对象复制出新的业务对象,对原对象与新对象的改动不会相互影响。常用于动态表单、移动业务的开发。继承:继承原对象的元......
  • [编程基础] Python内置模块collections使用笔记
    collections是Python标准库中的一个内置模块,它提供了一些额外的数据结构类型,用于增强Python基础类型如列表(list)、元组(tuple)和字典(dict)等。以下是对collections模块中主要数据结构类的概述:namedtuple:命名元组,创建一个带有名称的tuple,并且可以通过名称访问元素。deque:双端队列,可......
  • 批处理实现局域网连接打印机
     以下代码仅适用于连接其他主机上的打印机,需要知道主机的IP地址,用户名或者密码。为了方便可以共享的时候设置为空密码(策略设置那里要打开允许空密码登陆)这样就不用添加网络凭据了 @echooff::获取管理员身份%1mshtavbscript:CreateObject("Shell.Application").ShellE......
  • Python学习 -- Math模块和Random模块
    math模块提供了许多数学函数,用于执行各种数学运算。以下是一些常用的math函数以及相应的示例代码:math.sqrt(x):计算平方根。importmathx=25square_root=math.sqrt(x)print(f"√{x}={square_root}")math.pow(x,y):计算x的y次方。importmathx=2y=3result......
  • O2OA(翱途)平台新版本流程平台新增退回功能、新增关联文档功能、新增业务数据变更记录
    尊敬的O2OA(翱途)平台合作伙伴、用户以及亲爱的开发小伙伴们,平台V8.1版本已正式发布。此次,为了更好的服务于业务场景,我们根据在项目中遇到的一些实际问题,重点也对流程平台和流程引擎做了细节上的优化,本篇将重点介绍流程平台中优化的一些细节,大家一起来看看。 ​ O2OA(翱途......