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

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"
    }

}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种高效的编程语言,而Web服务器是一个常见的网络应用程序。在Web服务器开发中,C语言可以被用来开发高性能的程序。实际上,许多流行的Web服务器,如Apache和Nginx,都是用C语言编写的。因此,Web服务器开发实战项目可以用C语言进行实现。 在Web服务器开发实践项目中,C语言可以被用来处理网络协议、管理线程、提高服务器性能以及开发插件。这些功能对于一个高效的Web服务器来说非常重要。 网络协议处理是Web服务器的一项核心功能。服务器需要能够识别不同的协议,如HTTP、FTP、SMTP等,并能够为客户端提供相应的服务。使用C语言可以提高服务器的处理速度和效率。 Web服务器需要能够同时处理多个客户端请求。线程是实现服务器并发处理的重要手段。使用C语言可以在服务器中实现线程,从而实现高并发的客户端请求处理。 提高服务器性能是Web服务器开发的另一个重要方面。C语言可以通过优化算法、使用高效的数据结构和编写高效的代码来提高服务器性能。 插件的开发是实现Web服务器灵活性的另一种方法。使用C语言可以编写高性能的插件,从而为服务器添加各种功能模块。 总之,C语言是Web服务器开发实战项目中不可或缺的一部分。使用C语言能够让开发者实现高效、高性能的Web服务器,从而满足不同场景下的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值