C++ Web服务器 - 用户登录(三)

2023-11-17

newobj跨平台开发框架:https://github.com/Liuccysdgg/newobj

本片着重介绍 MYSQL连接池、HTTP静态文件响应、部分JS等。

效果演示

一、MYSQL连接池

如果每次业务请求进来时去创建mysql连接并处理,其中会每次消耗几十到几百毫秒的连接耗时,如果第一次连接后不将连接断开并在下一次需要获取连接时从池内获取,是不是可以减少连接消耗呢?

二、用户控制器

既然本章需要处理用户登录,那么就要考虑到权限问题 ---- 已登录 | 未登录

已登录用户会有几点操作:

① 退出登录

② 获取资料【性别、年龄】

③设置资料【性别、年龄】

未登录用户会有以下操作:

① 登录

现在结构及权限清晰,我们将开始构建代码,即需要 一个处理类、一个拦截器函数

1、处理类用来处理已登录用户的操作

2、拦截器函数用来拦截需要已登录用户才能操作的接口目录进行鉴权。

新建 src/user_ctl.h

#pragma once
#include "network/http/http_controller.h"
class user_ctl :public network::http::controller
{
public:
    // 登录
    network::http::response_type login();
    // 退出登录
    network::http::response_type outlogin();
    // 取个人资料
    network::http::response_type get_info();
};

新建 src/user_ctl.cpp

#include "user_ctl.h"
#include "util/json.h"
#include "mysql/mysql_plus.h"
#include "public/environment.h"
#include "define.h"
network::http::response_type user_ctl::get_info()
{
    
    auto session = request()->session("cppsession");
    newobj::json rep;
    rep["username"] = (*session)["username"].to<nstring>();
    rep["sex"] = (*session)["sex"].to<bool>();
    rep["age"] = (*session)["age"].to<int32>();
    response()->send(rep);
    return RT_OK;
}
network::http::response_type user_ctl::login()
{
    nstring username = request()->parser()->json()["username"].to<nstring>();
    nstring password = request()->parser()->json()["password"].to<nstring>();

    

    // 回复JSON
    newobj::json rep;
    // 查询是否已登录
    auto session = request()->session("cppsession");
    if((*session)["username"].to<nstring>().empty() == false){
        rep["result"] = true;
        rep["msg"] = "已登录";
        response()->send(rep);
        return RT_OK;
    }

    // 获取可自动释放的MYSQL连接
    conn_autofree<mysql_plus::conn> conn(MYSQL_POOL->get());

    auto ppst = conn->setsql("SELECT id,sex,age FROM users WHERE username = ? and password = ? LIMIT 1");
    ppst->set_string(1,username);
    ppst->set_string(2,password);
    auto result = ppst->query();
    if(result->row_count() == 0){
        // 没有记录,则账号密码错误
        rep["result"] = false;
        rep["msg"] = "账号或密码错误";
        response()->send(rep);
        return RT_OK;
    }
    result->next();
    // 找到记录,账号密码正确,登录成功
    //
    // 写入session
    (*session)["username"] = username;
    (*session)["age"] = result->get_int32("age");
    (*session)["sex"] = result->get_boolean("sex");


    rep["result"] = true;
    rep["msg"] = "登录成功";
    response()->send(rep);
    return RT_OK;
}
network::http::response_type user_ctl::outlogin()
{
    auto session = request()->session("cppsession");
    session->destory();

    response()->send((nstring)"已注销");
    return RT_OK;
}

新建 www/index.html

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h1>账号:</h1>
        <input id="username" type="text" />
        <h1>密码:</h1>
        <input id="password" type="text" />
        <br>
        <input id="login" type="button" value="登录" />
        <input id="outlogin" type="button" value="注销" />
        
        <input id="get_info" type="button" value="获取资料" />
        <script src="jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                 $("#outlogin").click(function(){
        
                    $.ajax({
                        type: "get",
                        url: "/user/outlogin",
                        success: function(data, status) {
                            alert(data.msg)
                        }
                    })
                })
                $("#login").click(function(){
        
                    var data = {};
                    data.username = $("#username").val();
                    data.password = $("#password").val();
                    $.ajax({
                        type: "post",
                        url: "/user/login",
                        contentType: "application/json",
                        data: JSON.stringify(data),
                        dataType: "json",
                        success: function(data, status) {
                            alert(data.msg)
                        }
                    })
                })
                 $("#get_info").click(function(){
        
                    var data = {};
                    $.ajax({
                        type: "get",
                        url: "/user/get_info",
                        dataType: "json",
                        success: function(data, status) {
                            alert(JSON.stringify(data))
                        }
                    })
                })
            })
            
        </script>
    </body>
</html>

main.cpp

#include <iostream>
#include <regex>


#include "public/environment.h"
#include "util/system.h"
#include "util/time.h"

#include "network/http/http_client_plus.h"
#include "network/http/http_center.h"
#include "network/http/http_request.h"
#include "network/http/http_response.h"
#include "network/http/http_reqpack.h"
#include "network/http/http_router.h"
#include "network/http/http_interceptor.h"
#include "network/http/http_website.h"

#include "user_ctl.h"
#include <tuple>

#include "define.h"
#include "mysql/mysql_plus.h"
int main()
{   

    // 配置文件
    newobj::json config;
    config.parse_file("./res/config.json");

    /*初始化MYSQL连接池*/
    {
        mysql_plus::mysql_conn_info info;
        // JSON配置写入结构体
        info.charset = "utf8mb4";
        info.database = config["mysql"]["database"].to<nstring>();
        info.ipaddress = config["mysql"]["ipaddress"].to<nstring>();
        info.password = config["mysql"]["password"].to<nstring>();
        info.username = config["mysql"]["username"].to<nstring>();
        info.port = config["mysql"]["port"].to<uint32>();
        // 创建连接池指针
        mysql_plus::pool* pool = new mysql_plus::pool();
        if(pool->start(info,10/*连接最大数量*/) == false){
            newobj::log->fatal(pool->last_error());
            return 0;
        }
        // 设置为全局环境变量
        newobj::env->set<mysql_plus::pool>("mysql_pool",pool);
    }


    // 创建控制中心
    auto center = new network::http::center;
    center->create(config);

    // 通过域名获取 website 站点对象指针
    auto website = center->website("0.0.0.0");

    /************************ 添加控制器\拦截器\静态文件处理  **********************************/

    // 获取路由
    auto router = website->router();
    // 获取拦截器
    auto interceptor = router->interceptor();

    // 拦截所有 /user/ 目录下请求,该目录为管理器权限
    interceptor->add("/user/.*",[](network::http::reqpack* reqpack/*请求包*/)->bool{
        auto session = reqpack->request()->session("cppsession");
        std::cout<<session->session_id().c_str()<<std::endl;
        if(session->session_id().empty()){
            session->init("");
            reqpack->response()->headers()->emplace("Set-Cookie","cppsession="+session->session_id());
        }
        // 判断是否为登录请求,登录请求不用拦截。
        if(reqpack->filepath() == "/user/login"){
            return true;
        }
        if(reqpack->filepath() == "/user/outlogin"){
            return true;
        }
        if((*session)["username"].to<nstring>().empty()){
            reqpack->response()->send((nstring)"Please Login");
            // 未登录
            return false;
        }
        // 已登录
        return true;                                       
    });
    // 增加请求处理 (lamaba 方式)
    router->subscribe("/hello",network::http::GET,[](network::http::request* request,network::http::response* response){
        // 发送 文本
        response->send((nstring)"<h1>Hello!,This is newobj Web Server</h1>");
    });
    // 其它处理
    router->other([](network::http::request* request,network::http::response* response){
        auto filepath = request->filepath();
        if(filepath == "/")
            filepath = "/index.html";
        if(response->send_file(filepath) == false){
            response->send((nstring)"404",404,"Not Found");
        }
        return;
    });
    // 增加请求处理集 (对象方式)
    SUBSCRIBE(router,user_ctl,get_info,"/user/get_info",network::http::GET);
    SUBSCRIBE(router,user_ctl,outlogin,"/user/outlogin",network::http::GET);
    SUBSCRIBE(router,user_ctl,login,"/user/login",network::http::POST);


    // 启动控制中心
    if (center->start() == false)
    {
        newobj::log->fatal(center->last_error());
        return 0;
    }

    newobj::log->info("start success");


    
    while (true)
    {
        system::sleep_msec(1000);
    }
    return 0;
}


config.json

{
    "website":[
        {
            "host":[
                {
                    "host":"0.0.0.0:6699",
                    "ssl":false
                }
            ],
            "router":{
                "threadpool":{
                    "queuemax":10000,
                    "size":5
                }
            },
            "rootdir":"/home/ubuntu/project/webserver/www"

        }
    ],
    "mysql":{
        "ipaddress":"127.0.0.1",
        "password":"xeMjCwGLKsdwT6A7",
        "port":3306,
        "username":"blog",
        "database":"blog"
    }

}

最终效果如上,实现登录、获取信息、注销登录三部操作,屏幕前的你可以尝试补全更新资料功能哦~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ Web服务器 - 用户登录(三) 的相关文章

随机推荐

  • 04-Qt软件加入Log文件输出与终端彩色打印(包含行号)

    一 目的与需求 在开发qt应用程序中 经常使用打印调试软件 qt自己的qDebug 就满足了需求 但是当需要把一部分log记录到文件的时候qt就没有提供了 这个时候可以使用qDebug 的qInstallMsgHandler来指定打印回掉函
  • 软件测试第一阶段:web前端技术基础-16- linux系统安装软件,运用shell脚本等

    一丶yum安装 用yum安装软件分三步 第一步 准备一个软件源 软件源其实就是一个目录 在这个目录中有很多的rpm包 第二步 创建yum的配置文件 文件需要指向到软件源 第三步 用yum进行安装 卸载软件 第一步 配置软件源 1 首选将系统
  • Java基础知识-多态的实现机制

    面向对象设计具备三种特性 封装 继承 多态 多态是面对对象程序设计中代码重用的一个重要机制 它表示当同一个操作作用在不同的对象的时候 会出现不同的语义 从而会产生不同的结果 比如 同样是 操作 3 4用来实现整数的相加 而 3 4 却实现了
  • js取小数点后两位四种方法

    1 通过substring截取 function getnum var num 22 123456 var s num toString var result s substring 0 s indexOf 3 var result2 s
  • 安装Redis数据库

    Redis是一种内存缓存数据库 它可以帮助我们高效地缓存我们的数据 以下是Redis安装步骤 1 在Linux系统安装 安装Redis 在终端中输入以下命令 sudo apt get update sudo apt get upgrade
  • centos下禁用网卡IPv4或者IPv6

    Centos下禁用网卡的ipv4 直接删除网卡的ipv4地址 ip addr del 10 2 21 40 24 dev ens160 启用ip addr add 10 2 21 40 24 dev ens160 禁用ipv6功能 root
  • 讯飞星火,正式开放!

    今日起 讯飞星火认知大模型面向全民开放 在各大主流应用商店搜索 讯飞星火 App 或登录讯飞星火官网均可直接注册使用 专属申请通道 长按内测二维码 点击 申请注册 通过专属二维码 注册免费 秒通过 即刻上手免费体验 无需审核等待 还可以获得
  • 英特尔第十代处理器为什么不支持win7_为什么7代CPU不支持WIN7操作系统?

    说来说去还不是利益驱使 wintel联盟暗地里让客户淘汰旧的硬件旧的系统呗 区区几个驱动对英特尔来讲还不是手到擒来的事 近来市场上英特尔不是又推出了一种新的低端芯片组主板 基于22纳米打造的H310C 原生支持WIN7系统安装 这款芯片组根
  • 嵌入式(exec函数族和守护进程)

    exec 函数族 背景 fork创建进程之后 子进程和父进程执行相同的代码 但是在实际开发当中 我们希望父子进程执行不同的代码 作用 执行指定的程序 include
  • POJ 3259 Wormholes(最短路——Bellman-ford)

    A Wormholes While exploring his many farms Farmer John has discovered a number of amazing wormholes A wormhole is very p
  • Think in Java(一)

    把对象想象为 服务提供者 通常被隐藏的部分是对象内部脆弱的部分 组合和聚合 组合 使用现有的类合成新的 聚合 当组合是动态发生的时候 被称为聚合 组合经常被视为 has a 关系 例如汽车拥有引擎 在建立新类时 应该先考虑组合 因为它更加简
  • EXCEL 如何制作混合数据透视图柱形图添加折线图

    当我们制作了数据透视图 增长率什么的 需要在柱形图上增加折线图 如何做呢 工具 原料 EXCEL2007 方法 步骤 1 新建一个工作表 而后数据入局 制作一个带增长率的数据透视表 2 选中数据 而后在上方功能区找到插入菜单 在下拉选项了里
  • PM 和 PL 的区别

    工作之前只知道PM是项目经理 PL是 项目负责人 看过几本职场小说 据我理解 PM职能更多是在人事和外部资源调度方面 而PL更多在技术层面去领导下面的开发人员 小组有PL PM各一个 同事对待他们的方式给我的理解就是 PM要比PL大 工作汇
  • linux————zabbix搭建

    目录 一 zabbix的概述 二 构成 一 server 二 web页面 三 数据库 四 proxy 五 agent 三 zabbix监控对象 四 zabbix的常用术语 五 zabbix监控框架 一 zabbix client架构 二 z
  • 视频会议用户洞察白皮书

    导读 白皮书重点通过桌面研究和定量调研的方式 对疫情后视频会议行业发展现状 用户行为及需求偏好和用户付费意愿等内容展开研究 以期加深对视频会议行业及用户的了解 希望能为相关企业与资本市场提供参考意见与运营建议 关注公众号 互联互通社区 回复
  • 蓝桥杯国赛 C/C++ ABC组题解(第四届 ~ 第十二届)

    2020年第十一届蓝桥杯国赛 题号 类型 C A组 C B组 C C组 试题A 结果填空 合数个数 美丽的 2 美丽的 2 试题B 结果填空 含 2 天数 日期处理 扩散 BFS 合数个数 试题C 结果填空 本质上升序列 线性DP 阶乘约数
  • karma使用webpack的代码覆盖率测试

    前言 距离上一次博客有2个月了 倒不是没有可写东西就是提不起劲写 不说这些了这次写下我使用 karma webpack 中遇到的代码覆盖率问题 一 karma的使用 自个去搜吧 感觉讲这个的真的多 我就说一些建议 karma的测试框架改用m
  • LVGL 获取光标坐标位置

    为了方便获取物理按键输入的坐标 在仿真时直接开启打印坐标显示 获取自己想要的坐标 核心代码主要接口 indev proc press 打印光标位置 注意要先使能打印开关 LV LOG WARN pressed at x d y d proc
  • HTTP:断点续传原理图文分析

    起源 以前 用户不能使用现在这种高速的带宽访问互联网 当时 下载一个尺寸稍大的图片或文件就已经很吃力了 如果下载过程中遇到网络中断的情况 那就必须重头开始 一 获取部分内容 在HTTP 1 1中 为了解决上述问题 需要一种可恢复的机制 所谓
  • C++ Web服务器 - 用户登录(三)

    newobj跨平台开发框架 https github com Liuccysdgg newobj 本片着重介绍 MYSQL连接池 HTTP静态文件响应 部分JS等 效果演示 一 MYSQL连接池 如果每次业务请求进来时去创建mysql连接并