文章目录
需求分析:
编写一个博客系统,提供一个浏览器页面, 能够让管理员在后台管理我们的博客(增删改查);能够让用户对自己的博客进行管理,查看别人的博客。
项目的概要设计:
后台的业务处理,后台的数据管理,前端页面展示操作
博客服务器
- 对博客的增删改查管理能力
- 对标签的增删查改能力
博客客户端
- 博客标题列表页面
- 博客内容展示页面
- 博客管理页面
- 博客内容编辑页面
关于数据存储和交互
- 服务器存储 markdown 格式的数据
- 前端通过 editor.md 这个工具将markdown的文档内容提交给服务器, 或者解析服务器返回的 markdown 作为前端页面内容
采用MVC框架实现
用一种业务逻辑、数据、界面显示分离的方法组织代码。
项目的详细设计:从各个框架的模块出发
数据管理模块:进行数据管理
使用mysql数据库进行数据的管理
业务逻辑模块:完成业务处理
向用户提供页面进行数据的操作(博客/标签/用户的增删改查)
数据库模块设计
使用mysql数据库进行数据的管理
表的设计
用户表:table_uesr
博客标签表:table_tag
博客表:table_blog
数据管理模块:封装访问接口。
将数据的校验以及数据库的访问操作封装起来。
数据库编写
CREATE DATABASE IF NOT EXISTS blog_system charset=utf8 collate utf8_general_ci;
use blog_system;
drop table if exists table_tag;
create table table_tag(
tag_id int primary key auto_increment,
tag_name varchar(30) unique
);
drop table if exists table_user;
create table table_user(
user_id int primary key auto_increment,
user_name varchar(30) unique
);
drop table if exists table_blog;
create table table_blog(
blog_id int primary key auto_increment,
user_id int,
tag_id int,
title varchar(255),
content text,
ctime datetime,
foreign key (user_id) references table_user(user_id),
foreign key (tag_id) references table_tag(tag_id)
);
代码编写
将json字符串转化为json对象,进而进行校验,实现数据传递
libjsoncpp库实现字符串与json对象的数格式据交换:
Json::Value — json数据对象
Json::Read ---- json字符串到json对象的解析— json反序列化
Json::Writer —从json对象到json字符串的组织— json序列化
TagTable
class table_tag
{
public:
table_tag(MYSQL *mysql)
:_mysql(mysql)
{}
bool Insert(const Json::Value &tag);
bool Delete(int tag_id);
bool UpDate(int tag_id, const Json::Value &tag);
bool GetAll(Json::Value &tags);
bool GetOne(int tag_id, Json::Value &tag);
private:
MYSQL *_mysql;
};
UserTable
class table_user
{
public:
table_user(MYSQL *mysql)
:_mysql(mysql)
{}
bool Insert(const Json::Value &user);
bool Delete(int user_id);
bool UpDate(int user_id, const Json::Value &user);
bool GetAll(Json::Value &users);
bool GetOne(int user_id, Json::Value &user);
private:
MYSQL *_mysql;
};
BlogTable
class table_blog
{
public:
table_blog(MYSQL *mysql)
:_mysql(mysql)
{}
bool Insert(const Json::Value &blog);
bool Delete(int blog_id);
bool UpDate(int blog_id, const Json::Value &blog);
bool GetAll(Json::Value &blogs);
bool GetOne(int blog_id, Json::Value &blog);
bool GetTag(int tag_id, Json::Value &blogs);
bool GetUser(int user_id, Json::Value &blogs);
private:
MYSQL *_mysql;
};
操作流程
使用C语言mysql的API接口实现mysq|数据库的访问:实际上就是编写一个mysq|客户端
1.初始化mysq|句柄
MYSQL *mysql_init(MYSQL *mysql)
2.连接mysq|服务器
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
MYSQL *mysql_ real connect(MYSQL *mysq|, const char *host, const char *user, const char *passwd, const char *db,unsigned int port, const char *unix_ socket, unsigned long client flag);
mysql:初始化完毕的句柄;
host:连接的mysq|服务器IP
user: mysq|数据库的用户名
passwd:数据库密码
db:连接数据库的同时可以选择使用的数据库名称;
port:连接的mysq|服务器端口-默认0表示3306
unix_ socket: 套接字文件,通常置NULL;
client_ flag: 客户端标志,通常置0;
返回值:成功返回句柄首地址,失败返回NULL;
3.设置客户端的字符编码集
int mysql_set_character_set(MYSQL *mysql, const char *csname)
零成功。如果发生错误,则为非零值。
4.语句执行(增删改查)
int mysql_query(MYSQL *mysql, const char *stmt_str)
零成功。如果发生错误,则为非零值。
5.增删改–只要知道执行结果如何就能判断成功与否;对于查询执行成功,还得去获取数据
查询: 1. 获取结果集。2. 遍历结果集获取各条数据。3. 释放结果集
MYSQL_RES *mysql_store_result(MYSQL *mysql) 获取结果集 uint64_t
mysql_num_rows(MYSQL_RES *result)返回结果集中的行数。 unsigned int
mysql_num_fields(MYSQL_RES *result)返回结果集中的列数。 void
mysql_free_result(MYSQL_RES *result)释放结果集 MYSQL_ROW
mysql_fetch_row(MYSQL_RES *result)检索结果集的下一行
6.关闭数据库
void mysql_close(MYSQL *mysql)
业务逻辑模块设计
向用户提供页面进行数据的操作(博客/标签/用户的增删改查)
整体设计
用户通过浏览器获取博客首页
——涉及的就是前端客户端与后台服务器之间的数据交互—网络通信
数据的交互接口:
客户端发送什么样的请求,服务端应该给与什么样的响应—采用HTTP协议进行通信
通信接口的设计:
采用Restful风格的接口设计–基于HTTP协议,使用json的一种数据格式风格
Restful通信接口规范:
请求方法: POST–新增 / GET–获取/ DELETE–删除/ PUT–修改
正文: json序列化的数据格式—独立于语言,简洁、清晰、可视化
json序列化和反序列化使用库实现: libjsoncpp
用户:增删改查
标签:增删改查
博客:增删改查
Json串的解析以及组织
Json::Value — json对象
Json::Reader – -实现json字符串解析的对象bool Json::Reader:parse(std:string,Json::Value)
Json::FastWriter —实现json对象到json字符串的组织std:string Json::FastWriter::write(son::Value)
httplib中如何获取查询字符串
req.params -> /path?key= val&key=val… .
bool httplib::Request::has_ param(char *key) —判断有没有某个key的查询字符串
stl::string httplb::Request.:get_param_val(char *key) — 通过key获取value
httplib中如何获取资源路径中的id
/path/(\d+) -> req.matches[1]
httplib中如何添加正文
httplib::Response::set_ content(stl:string body, std:string type)
接口设计
用户的增删改查接口设计:
增添用户:
POST /user HTTP/1.1\r\n
Content-Type: application/json\r\n
Content-Length: \r\n
\r\n
{ " name'":" zhangwenchao" }
成功响应
HTTP/1.1 200 OK\r\n
Content-Length:
\r\n
{
"result":"ok"
"reason":
}
失败响应
HTTP/1.1 400 Bad Request\r\n
Content-Length: \r\n
\r\n
{
"result":"failed",
"reason":"format error"
}
删除用户:
DELETE /user/user_ id HTTP/1.1\r\n
Content-Length: 0\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
修改用户:
PUT /user/user_id HTTP/1.1\r\n
Content-Length:
Content-Type:
\r\n
{ "name":"newname" }
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
获取所有用户:
GET /user HTTP/1.1\r\n
Content-Length: 0\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: \r\n
\r\n
{
[ {"id":1, "name":"zhangsan"},
{"id":2, "name":"lisi"} ]
}
获取单个用户:
GET /user/user_id HTTP/1.1\r\n
Content-Length: 0\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: \r\n
\r\n
{
{"id":1, "name":"zhangsan"}
}
标签的增删改查接口设计
添加标签:
POST /tag HTTP/1.1\r\n
Content-Length:
Content Type: \r\n
\r\n
{"name": "C++"}
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
\r\n
删除标签
DELETE /tag/tag_id HTTP/1.1\r\n
Content-Length: 0\r\n
Content- Type: \r\n
\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
\r\n
修改标签
PUT /tag/tag_id HTTP/1.1
Content-Length: \r\n
Content-Type: \r\n
\r\n
{"name" : "Java"}
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
\r\n
获取所有标签:
GET /tag HTTP/1.1\r\n
Content-Length: 0\r\n
\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: \r\n
\r\n
{
[{"id":1, "name'":"C++"},
{"id":2, "name":" Java"}]
}
获取单个标签:
GET /tag/tag_id HTTP/1.1\rn
Content-Length: 0\r\n
\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: \r\n
\r\n
{"id'":1, "name":"C++"}
博客信息通信接口的设计:
添加博客:
POST /blog HTTP/1.1\r\n
Content-Length: \r\n
Content-Type: \r\n
\r\n
{"tag_id": 1, "user. id": 1, "title":"精彩", "content": "非常精彩"}
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
\r\n
删除博客:
DELETE /blog/blog_id HTTP/1.1\r\n
Content-Length: 0\r\n
\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
\r\n
修改博客:
PUT /blog/blog_id HTTP/1.1\r\n
Content-Length: 0\r\n\r\n
{"tag_ id": 1, "user. id": 1, "title":" 精彩", "content": "内容非常精彩"}
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n
\r\n
获取所有博客:
GET /blog HTTP/1.1\rn
Content-Length: 0\r\n\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n\r\n
{[
{"tag_ id": 1, "user_ id": 1, "title":"精彩", "content": "内容非常精彩" },
{"tag_ id": 1, "user. id": 1, "title":" 精彩", "content": "内容非常精彩"}
]}
获取指定标签类型的所有博客(GET方法没有正文,所以提交的数据不能放在正文中)
GET /blog?tag_id=1 HTTP/1.1\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n\r\n
{[
{"tag_ id": 1, "user_ id": 1, "title":"精彩", "content": "内容非常精彩" },
{"tag_ id": 1, "user. id": 1, "title":" 精彩", "content": "内容非常精彩"}
]}
获取指定用户的所有博客
GET /blog?user_ id=1 HTTP/1.1\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n\r\n
{[
{"tag_ id": 1, "user_ id": 1, "title":"精彩", "content": "内容非常精彩" },
{"tag_ id": 1, "user. id": 1, "title":" 精彩", "content": "内容非常精彩"}
]}
获取指定博客
GET /blog/blog_ id HTTP/1.1\r\n
响应
HTTP/1.1 200 OK\r\n
Content-Length: 0\r\n\r\n
{
{"tag_ id": 1, "user. id": 1, "title":" 精彩", "content": "内容非常精彩"}
}
搭建环境:
库的安装
sudo yum -y install epel-release
sudo yum install jsoncpp-devel
gcc升级:
sudo yum install centos-release-scl-rh centos-release-scl
sudo yum install devtoolset-4-gcc devtoolset-4-gcc-c++
source /opt/rh/devtoolset-4/enable
服务端搭建完毕之后
虚拟机:需要虚拟机关闭防火墙,我们的主机才能通过浏览器访问
systemctl stop firewalld --关闭防火墙服务—下次登录依然需要重新关闭
systemctl disable firewalld --停用防火墙服务—下次登录就不需要重新关闭