四. 数据获取
1. 连接mongo DB和service
- 登录railway,通过CLI和浏览器登录都可。
- 在dashboard - project,点击
New
添加MongoDB。 - 在service里添加variables:输入mongoDB,自动显示有关变量,添加MONGO_URL。
附:railway自动添加username和password,无需手动创建。
2. 上传JSON数据
到MongoDB的网站,下载mongoDB工具。
使用import 把contact.json导入数据库
切换到Exercise Files目录:
cd "/mnt/c/Users/Auly/Desktop/backend/Web_Servers_and_APIs_using_C++/Ex_Files_Web_Servers_APIs_C_PlusPlus/Exercise Files/Ch 04/04_02"
在railway - bashboard - mongo 可查看MONGO_URL,即uri选项。
把contacts.json引入mongodb:
mongoimport --authenticationDatabase admin --uri='mongodb://mongo:**********@containers-us-west-175.railway.app:7978' --collection='contacts' --jsonArray ./contacts.json
3. 添加MongoDB的C++ 驱动
为了访问mongoDB,需要把MongoDB的C++ drivers添加到代码中。
在hello_crow下新建bbox,在它下面添加如下Dockerfile,内容如下。
FROM gcc:12.3
RUN apt-get -qq update
RUN apt-get -qq upgrade
RUN apt-get -qq install cmake
RUN apt-get install -y libboost-all-dev --no-install-recommends
RUN apt-get -qq install build-essential libtcmalloc-minimal4 && \
ln -s /usr/lib/libtcmalloc_minimal.so.4 /usr/lib/libtcmalloc_minimal.so
WORKDIR /usr/src
RUN git clone https://github.com/mongodb/mongo-c-driver.git \
&& cd mongo-c-driver && git checkout 1.23.2 \
&& mkdir cmake-build && cd cmake-build \
&& cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF .. \
&& make && make install && ldconfig /usr/local/lib
RUN git clone https://github.com/mongodb/mongo-cxx-driver.git \
--branch releases/stable --depth 1 \
&& cd mongo-cxx-driver/build && cmake \
-DBSONCXX_POLY_USE_MNMLSTC=1 \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DLIBMONGOC_DIR=/usr/lib/x86_64-linux-gnu \
-DLIBBSON_DIR=/usr/lib/x86_64-linux-gnu \
-DCMAKE_MODULE_PATH=/usr/src/mongo-cxx-driver-r3.7.0/cmake .. \
&& make EP_mnmlstc_core && make && make install && ldconfig /usr/local/lib
它和第1个Dockerfile相似,前1-9行创建C++开发环境;
WORKDIR
设置当前docker image的工作目录;
第1个RUN git
构建Mongo C驱动程序库,从github中获取源代码,用cmake构建make文件,构建并安装库,ldconfig告诉系统有关新库的消息;
第2个RUN git
构建Mongo C++驱动程序库,从github中获取源代码,执行cmake,选项传递包括-DBSONCXX_POLY_USE_MNMLSTC=1
:把C++14及以上的功能带到C++11,-DCMAKE_BUILD_TYPE=Release
:构建驱动程序的release版本,其余选项:构件中不同组件的位置。ldconfig告诉系统有关新库的消息。
在bbox目录下,构建image:
docker build --rm --squash --no-cache -t bbox:latest .
注:1. 在vpn下使用该命令,若不,显示:
#0 20.03 E: Failed to fetch http://deb.debian.org/debian/pool/main/b/build-essential/build-essential_12.9_amd64.deb 502 Bad Gateway [IP: 146.75.114.132 80]
#0 20.03 E: Failed to fetch http://deb.debian.org/debian/pool/main/g/google-perftools/libtcmalloc-minimal4_2.8.1-1_amd64.deb 502 Bad Gateway [IP: 146.75.114.132 80]
#0 20.03 E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
若显示如下错误:
#0 9.602 E: Failed to fetch http://deb.debian.org/debian/pool/main/g/google-perftools/libtcmalloc-minimal4_2.8.1-1_amd64.deb 502 Bad Gateway [IP: 146.75.114.132 80]
#0 9.602 E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
是网络连接问题,切换线路或重试即可。
2. 版本问题:
第1个git中,注意git check out
后面的版本与gcc匹配,改新。
#0 14.60 CMake Error at src/bsoncxx/CMakeLists.txt:113 (find_package):
#0 14.60 Could not find a configuration file for package "libbson-1.0" that is
#0 14.60 compatible with requested version "1.13.0".
#0 14.60
#0 14.60 The following configuration files were considered but not accepted:
#0 14.60
#0 14.60 /usr/local/lib/cmake/libbson-1.0/libbson-1.0-config.cmake, version: 1.10.1
第2个git中,注意-DCMAKE_MODULE_PATH=/usr/src/mongo-cxx-driver-r3.7.0/cmake ..
中的版本改新。
警告不能使用squash,若使用squash,网页localhost:8080/contacts显示空白页。
可在bbox里手动建目录,cppweb/hell_crow。
或使用
docker build -t bbox:latest .
4. 查询Mongo数据
切换到hello_crow目录下,修改CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(hello_crow)
set(CMAKE_CXX_STANDARD 11)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Boost COMPONENTS system filesystem REQUIRED)
find_package(Threads REQUIRED)
find_package(libmongocxx REQUIRED)
add_executable(hello_crow main.cpp)
target_include_directories(hello_crow PRIVATE ${Boost_INCLUDE_DIRS} ${LIBMONGOCXX_INCLUDE_DIRS})
target_link_libraries(hello_crow ${Boost_LIBRARIES} Threads::Threads ${LIBMONGOCXX_LIBRARIES})
修改main.cpp,增加相关MongoDB C++ driver的头文件,增加处理contacts数据的路由:
// **************add****************
#include <fstream>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <boost/filesystem.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/oid.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>
#include <mongocxx/instance.hpp>
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::basic::kvp;
using mongocxx::cursor;
// **************add****************
int main(int argc, char* argv[])
{
crow::SimpleApp app;
// *****************add*********************
mongocxx::instance inst{};
string mongoConnect=std::string(getenv("MONGO_URL"));
mongocxx::client conn{mongocxx::uri{mongoConnect}};
auto collection=conn["test"]["contacts"];
// ****************add***********************
// *********add****************
CROW_ROUTE(app, "/contacts")
([&collection]()
{
mongocxx::options::find opts;
opts.limit(10);
auto docs=collection.find({},opts);
std::ostringstream os;
for (auto&& doc :docs)
{
os<<bsoncxx::to_json(doc)<<endl;
}
return crow::response(os.str());
});
// ********add****************
CROW_ROUTE(app, "/")
([](const crow::request& req, crow::response& res)
{
sendHtml(res, "index");
});
}
* 注:因云平台的不同环境变量和数据库名称不同,main.cpp和docker命令随着改动。
在hello_crow目录下,修改里面的Dockerfile:
FROM bbox:latest
WORKDIR /usr/src/cppweb/hello_crow
COPY . .
WORKDIR /usr/src/cppweb/hello_crow/build
RUN cmake .
RUN make
CMD ["./hello_crow"]
在hello_crow目录下,构建image:
docker build -t hello_crow:latest .
打开端口:
docker run -p 8080:8080 -e PORT=8080 -e MONGO_URL="mongodb://mongo:3klH7rOKun3XOLnf3pHg@containers-us-west-175.railway.app:7978" hello_crow:latest
在浏览器输入:localhost880:contacts
,显示mongdb collections里的数据。
在main.cpp,在CROW_ROUTE(app, "/contacts")
增加跳过9行的选型:opts.skip(9)
,第10行变成了第1行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-teoLxgAR-1685891597146)(/images/contacts_skip(9)].jpg)
5. 在页面中增加动态数据
(1) 使用mustache渲染
使用crow里的mustacle模板。
修改main.cpp,把contacts页面改好看,变成bulma风格表格形式。增加mustache命名空间,增加getView子函数,修改contacts路由:
// *************add**************
using namespace crow::mustache;
// *************add**************
// *************add**************
string getView(const string& filename, context& x)
{
return load_unsafe(filename + ".html").render(x);
}
// *************add**************
int main(int argc, char* argv[])
{
crow::SimpleApp app;
// **************add******************
crow::mustache::set_global_base("../public/");
// **************add******************
// ************modify**********
CROW_ROUTE(app, "/contacts")
([&collection]()
{
mongocxx::options::find opts;
opts.skip(9);
opts.limit(10);
auto docs=collection.find({}, opts);
crow::json::wvalue dto;
vector<crow::json::rvalue> contacts;
contacts.reserve(10);
for (auto&& doc : docs)
{
contacts.push_back(json::load(bsoncxx::to_json(doc)));
}
dto["contacts"] = contacts;
return getView("contacts", dto);
});
// **********modify**********
CROW_ROUTE(app, "/")
([](const crow::request& req, crow::response& res)
{
sendHtml(res, "index");
});
}
*注:1. load
显示空白页的话,用load_unsafe
替代。
2. 设置全局tmplate文件的目录,否则mustache不起作用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4CpKA6Dr-1685891597148)(images/contacts_table.jpg)]
(2) email查询
在网页中可通过email查询。修改main.cpp:
增加namespace,增加contact/<email>路由处理程序
// **************add***************
using bsoncxx::builder::basic::make_document;
// **************add***************
// **************add***************
CROW_ROUTE(app, "/contact/<string>")
([&collection](string email)
{
auto doc=collection.find_one(make_document(kvp("email", email)));
return crow::response(bsoncxx::to_json(doc.value().view()));
});
// **************add***************
访问localhost:8080/contact/<email>
(注意不是contacts
)查询联系人的信息,显示:
6. 练习:用mongo 数据创建一个网页
- 在public下创建contact.html
- 用contact.html修改contact的路由
- 使用mustache渲染contact数据
- 页面使用bulma风格
访问localhost:8080/contact/<email>
(不是contacts
)查询某个人的信息,显示:
7. 解决方案
- 在public下创建contact.html
在contacts.html的基础上修改:删除表格部分,增加联系人的图片。
contact.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Contact</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">
</head>
<body>
<section class="section">
<div class="content">
<h1 class="title">Contact</h1>
{{#contact}}
<div>
<p>{{firstName}} {{lastName}}</p>
<p>{{email}}</p>
<p>{{phone}}</p>
<img src="{{photo}}" />
</div>
{{/contact}}
</div>
</section>
</body>
</html>
- 修改contact/<email>路由部分
CROW_ROUTE(app, "/contact/<string>")
([&collection](string email)
{
auto doc=collection.find_one(make_document(kvp("email", email)));
// crow::json::wvalue dto;
crow::mustache::context dto;
dto["contact"]=json::load(bsoncxx::to_json(doc.value().view())) ;
return getView("contact", dto);;
});
- 重新build hello_crow:latest image,打开端口。