在Windows,Mac,Linux中快速安装配置Node.js环境,并安装VSCode, 完成Web端恒生交易日接口的图形化展示...

编程课应该怎么制作?

编程的乐趣应来自实用主义,我大学本科第一门Java编程课,几乎劝退了所有同学,因为那些教学代码不实用且无趣,一点图形化的内容都没有,而实用的编程课应早早展现图形化的成果, 于是我选择开一门前后端齐头并进的全栈课程, 本课程将从零开始, 教授大量实用的图形化案例, 并给出完整源码.本文涉及到的代码完全开源在Github,地址: https://github.com/zhaoolee/it/tree/main/src/Class001

本文是基于 Node.js 和 JavaScript的全栈编程教程, 虽然Node.js 和 JavaScript都被人称为js, 编程语法也近似, 但两者的确是两门不同的语言;

JavaScript是前端编程语言, 运行在浏览器, 可以用来做各种网页特效, 数值运算, 以及数据请求, JavaScript的独特之处在于, 它没有竞争对手, 浏览器内可以运行的编程语言就它一个, 只要学前端, 就离不开Node.js;

Node.js 是后端编程语言, 也就是传统意义的编程语言, Node.js可以读取本地计算机的文件, 进行极为复杂的运算, 做机器学习, 深度学习, 与Python, C, C++, GoLang等语言算得上竞争对手, Node.js的特色是与JavaScript的语法极为相似, 学会了JavaScript的人, 再去学习Node.js, 会显得非常容易;

本门课程目标是培养一批会写码, 能整活儿的全栈工程师, 全栈工程师也可以被称作全干工程师, 技能丰富, 能独立完成产品的研发, 学完这门课程, 你也可以写出自己的小程序.

学编程, 需要让电脑可以运行代码, 想要运行代码,则需要安装编程语言的开发包

JavaScript代码可以在浏览器直接运行, 安装Chrome浏览器即可.

Chrome下载地址: https://google.cn/chrome

下载Chrome

Node.js 代码需要从官网下载开发包并安装

Node.js官网下载页面

https://nodejs.org/zh-cn/download/

  • Windows安装包

https://nodejs.org/dist/v16.13.0/node-v16.13.0-x64.msi

  • 通过以上链接, 下载安装包, 右键, 安装(也可以直接双击安装)
安装
  • NEXT
NEXT
  • 同意条款,下一步
同意条款_下一步
  • 保存默认安装位置, 下一步

默认安装位置为 C:\Program Files\nodejs\

下一步
  • 下一步
下一步
  • 下一步
下一步
  • 开始安装
安装
  • 允许更改
允许更改
  • 等待
等待
  • 完成
完成
  • 搜索PowerShell 并使用管理员身份打开
打开PowerShell
  • 输入 node -v , 如果能查看到Node.js的版本, 则说明安装成功了
安装成功

以上是Windows 安装Node.js的传统方案,现在微软官方推出了WSL (Windows Subsystem for Linux)方案,也就是在Windows里安装一个Linux子系统, 可以在Windows使用Linux中超好用的zsh工具(自动路径补全,自动命令提示,文本多彩高亮), 效果惊艳,强烈推荐! 当你用过了zsh, 你就再也无法忍受Windows超级难用的命令行工具了。

wsl

Windows安装 WSL教程 程序员福音!Win10下使用oh-my-zsh全攻略,让Win10开发更顺滑…

安装好WSL后, 按照本文Linux安装Node.js部分,直接安装Node.js即可,只需几行命令,方便又快捷。

另外说明一下,安装好Linux后,我们的程序可以直接在Linux中运行,Linux和Windows相当于两台机器,二者有独立的IP, 我们可以通过在Linux中运行 ifconfig | grep inet 来查看Linux的ip, 后文中默认的 localhost:3000, 也应该修改为 Linux的ip:3000

如果你想更多了解Linux命令,可以查看这个网站 Linux清单

macOS 安装Node.js

下载安装包: https://nodejs.org/dist/v16.13.0/node-v16.13.0.pkg

  • 打开安装包
打开安装包
  • 继续
继续
  • 继续
继续
  • 同意(只能同意,不同意就不让用)
同意
  • 继续
继续
  • 安装
安装
  • 验证身份,进行安装
验证身份
  • 安装成功, 关闭对话框
安装成功
  • 安装包建议留一份,重装可以用
保留
  • 打开终端
终端
安装成功
  • Linux 安装Node.js

Linux 做编程其实是最爽的,不用考虑Windows乱七八糟的路径问题,开源免费。

如果你追求颜值,比较推荐的Linux桌面发行版是Deepin,Deepin是一款国产Linux, 本地化做的很棒,Deepin镜像免费下载地址 https://www.deepin.org/zh/download/ 清华大学Deepin镜像源直接下载链接 https://mirrors.tuna.tsinghua.edu.cn/deepin-cd/20.2.4/deepin-desktop-community-20.2.4-amd64.iso

下载超快

在Linux安装Node.js的操作,我在Deepin上完成

  • 打开终端
打开终端

Linux安装Node.js仅需几行命令

cd /opt/
sudo wget https://nodejs.org/dist/v16.13.0/node-v16.13.0-linux-x64.tar.xz
sudo tar xvf node-v16.13.0-linux-x64.tar.xz
sudo echo "export NODE_HOME=/opt/node-v16.13.0-linux-x64" >> ~/.bashrc
sudo echo "export PATH=\$NODE_HOME/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
node -v
  • 获取安装包并解压安装包
获取安装包并解压安装包
安装成功

安装VSCode

VSCode是微软推出的一款代码编辑器,开源免费,功能强大,Windows, macOS, Linux均有对应的版本,且功能一致。

VSCode 官网: https://code.visualstudio.com/

VSCode下载

下载页面 https://code.visualstudio.com/Download

下载页面

下载VSCode 安装包后,双击安装即可。

  • 打开VSCode软件, 安装中文语言包
安装中文语言包

安装完成后,重启VSCode即可生效

中文生效

VSCode是一个神奇的软件,它不仅可以写代码,还可以搞各种其妙的小插件,比如可以输入 zhihu 搜索知乎插件并安装

知乎摸鱼

安装成功后,即可在写代码累的时候,刷刷知乎,放松一下(职业程序员摸鱼神器)

知乎

如果你是个追番达人,可以搜索插件 daily-anime, 安装成功后,使用Alt+L组合键,即可开始享用

追番神器

我们来写第一段代码

  • 在VSCode中新建文件
新建文件
  • 保存文件到桌面
保存文件到桌面
输入文件名并保存HelloWorld
  • 在HelloWorld.js 中加入以下代码
const http = require('http');

http.createServer(function (request, response) {

    // 发送 HTTP 头部 
    // HTTP 状态值: 200 : OK
    // 内容类型: 纯文本 text/plain
    // 编码类型: utf-8
    response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});

    // 返回内容
    let content = "来自互联网之神的祝福\n\n";

    // 循环十次,不断增加返回内容
    for(let i = 0; i < 10; i++){
        content = content + "Hello World==>" + i + "\n"
    }


    // 发送响应数据 "Hello World"
    response.end(content);

}).listen(8888);

// 终端打印如下信息
console.log('请用浏览器访问 http://127.0.0.1:8888/');
再次保存内容到桌面的文件
  • 新建终端
新建终端
  • 右键顶部的标签,左键点击复制路径
复制路径
  • 输入命令
输入命令
  • 按回车键, 运行程序
运行程序
  • 访问 http://127.0.0.1:8888
运行成功

Node.js 程序运行成功!

使用动态的数据源

一套完整的程序,可以分为客户端和服务端,客户端与服务端通过 API (Application Programming Interface,应用程序接口, 简称接口)进行数据交互,很多金融云服务商,会提供一些现成的 API 进行售卖,有些按时间付费,有些按使用(调用)次数付费,我们这里用恒生云交易日历API进行一波调用演示。

API 文档地址: https://www.hs.net/openplat-front/service/serviceDetail/983

请求参数

通过文档截图可知,我们必填的请求参数,有三个,分别是 证券市场代号secu_market开始日期 strat_date, 结束日期 end_date

如何通过API向后端程序发起请求?

我们用恒生云的API,就要先申请恒生云的调用权限,于是我申请了一个免费的试用

购买试用
key-secret

说明:恒生云入口 https://hs.net , 如果你也想申请 可以注册时用我的邀请码 FP3GUX , 如果不申请也没关系,我对已经请求的数据做了数据缓存,你运行我提供的程序包,即可获得数据,学习用足够了。

我们使用恒生云的接口,还需要, access_token, token_type 这两个参数,access_token, token_type相当于你的临时身份ID,而这个临时身份ID则需要使用恒生云提供的key和secret, 进行获取;以上规则在 https://www.hs.net/doc/100500_200550.html 里有详细的说明

文档

我这里提供通过key和secret获取Authorization的代码(key和secret两个字段我留空了,换成自己免费申请的即可)。

const https = require('https');
// key 和 secret 要通过注册恒生云获取
const key = "********";
const secret = "************";
// 获得 access_token 文档地址  https://www.hs.net/doc/100500_200550.html
const Authorization = "Basic " + Buffer.from(key+":"+secret).toString('base64');
console.log("==Authorization==>>", Authorization);
const postData = "grant_type=client_credentials";
const token_req = https.request({
    hostname: 'sandbox.hscloud.cn',
    path: '/oauth2/oauth2/token',
    method: "POST",
    headers : {
        'Authorization': Authorization,
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': postData.length
    },
},  (token_res)=>{
    token_res.on('data', (chunk) => {
        console.log(`BODY: ${chunk}`);
        const token_info = JSON.parse(chunk);
        const access_token = token_info["access_token"];
        const token_type = token_info["token_type"];
        console.log('token_info==>>', token_info);
        console.log('access_token==>>', access_token);
        console.log('token_type==>>', token_type);
    }
)})
token_req.write(postData);
token_req.end();
恒生
  • 有acccess_token, 和 token_type后,我们可以开始获取交易日接口的信息了
获取交易日

图中代码

const https = require('https');

const key = "5ac2e1ee-789e-4d6b-a52d-f533b99d6a36";
const secret = "***********";

// 查看代码前,请仔细阅读文档 文档地址 https://www.hs.net/wiki/api/983_gildataastock_v1_commontable_tadingday.html
const Authorization = "Basic " + Buffer.from(key + ":" + secret).toString('base64')
console.log("==Authorization==>>", Authorization);
const postData = "grant_type=client_credentials";
let token_req = https.request({
    hostname: 'sandbox.hscloud.cn',
    path: '/oauth2/oauth2/token',
    method: "POST",
    headers: {
        'Authorization': Authorization,
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': postData.length
    },
}, (token_res) => {
    token_res.on('data', (chunk) => {
        console.log(`BODY: ${chunk}`);
        const token_info = JSON.parse(chunk);
        const access_token = token_info["access_token"];
        const token_type = token_info["token_type"]
        // 开始请求
        //  secu_market=77 77代指美国纳斯达克证券交易所 , start_data=2018-01-01 代指开始时间为2018-01-01, end_date=2020-01-05代指结束时间为2020-01-05
        const tadingday_post_data = `secu_market=77&start_date=2018-01-01&end_date=2020-01-05`;
        const tadingday_authorization = token_type + " " + access_token;
        let tadingday_res_body = "";
        const tadingday_req = https.request({
            method: "POST",
            hostname: 'sandbox.hscloud.cn',
            path: '/gildataastock/v1/commontable/tadingday',
            headers: {
                "Authorization": tadingday_authorization,
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': tadingday_post_data.length
            }
        }, (tadingday_res) => {
            // 由于返回的数据量过于庞大, 服务器只能将数据分段返回给我们, 我们每次收到分段都会触发data事件, 于是我们将每次返回的数据累加起来
            tadingday_res.on('data', (res_data) => {
                tadingday_res_body = tadingday_res_body + res_data;
            })
            // 当程序触发 end事件时, 我们将已经获得的数据打印到终端上
            tadingday_res.on('end', ()=>{
                console.log(tadingday_res_body);
            })
        })
        tadingday_req.write(tadingday_post_data);
        tadingday_req.end();
    });
})
token_req.write(postData);
token_req.end();

为了能更好的展示这些数据,我们可以为这些数据做个网页

最终效果

效果

我们写代码是为了实现功能,而Node.js的优质工具包非常多,我们可以用很少的代码,实现复杂的功能,为了更好的使用和管理工具包,我们需要新建一个工程。

我们在终端输入 node -v , 并回车,可以看到Node.js的版本;如果我们使用 npm -v 也可以看到 npm的版本

npm

npm是随同Node.js一起安装的包管理工具, npm 全称(node.js package manage), 我们使用 which node 和which npm 可以查看到, node和npm安装在同一个目录

相同目录

创建工程的第一步是给工程起个名字,为了避免出现乱七八糟的编码转换问题,工程和工程内的文件都使用英文字符命名

我们通过命令行创建一个名为tadingday的文件夹,并以此文件夹作为工程目录,进行初始化

mkdir tadingday
cd tadingday
npm init -y
依赖包

在开发过程中,我们需要用到两个软件包

nodemon:可以监听文件内容变化,当文件内容变化时,自动重新运行程序,提升开发效率

express: 大名鼎鼎的Node.js服务器工具包,支持通过中间件,为指定文件夹直接提供http服务,可以方便地解析前端请求参数,并返回数据。

安装nodemon和express

npm install nodemon -D
npm install express

在项目文件夹中运行以上两行代码,即可顺利安装 nodemon和express

安装成功

安装成功后,我们项目文件夹会多出文件 package-lock.json, 以及文件夹 node_modules,原有 package.json文件的内容也会改变;

package_json_and_node_modules

对于node_modules和package-lock.json, 我们知道它们存在的意义就好了,即使一不小心删除了,也能通过npm install, 重新安装回来。

而package.json则是非常重要的文件,我们需要理解其中的配置信息,并使用nodemon自定义一些指令

  • package.json重要字段解读
package-json重要字段解读

为了实现通过网页直接输入参数, 查询恒生的交易日数据,我们需要使用express, 将我们以前的Node.js脚本改写成,可以接受前端请求,返回相应数据的服务端程序;这个服务端程序不仅能将以前在终端打印的数据返回给浏览器,还需要将写好的网页返回给浏览器。

const https = require('https');
const express = require('express');

const app = express()

app.use(express.static('html'))
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded


const port = 3000;

const key = "*******";
const secret = "*******";

// 文档地址 https://www.hs.net/wiki/api/983_gildataastock_v1_commontable_tadingday.html
// 示例访问链接 http://localhost:3000/gildataastock/v1/commontable/tadingday?end_date=2021-03-01&start_date=2021-01-01&secu_market=77

async function get_token() {
    const tadingday_authorization = await new Promise((resolve, reject) => {
        const Authorization = "Basic " + Buffer.from(key + ":" + secret).toString('base64')
        console.log("==Authorization==>>", Authorization);
        const postData = "grant_type=client_credentials";
        let token_res_data = "";
        let token_req = https.request({
            hostname: 'sandbox.hscloud.cn',
            path: '/oauth2/oauth2/token',
            method: "POST",
            headers: {
                'Authorization': Authorization,
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': postData.length
            },
        }, (token_res) => {
            token_res.on('data', (chunk) => {
                token_res_data = token_res_data + chunk;
            });
            token_res.on('end', () => {

                console.log(`BODY: ${token_res_data}`);
                const token_info = JSON.parse(token_res_data);
                const access_token = token_info["access_token"];
                const token_type = token_info["token_type"]
                const tadingday_authorization = token_type + " " + access_token;
                console.log('==tadingday_authorization==>>', tadingday_authorization);
                resolve(tadingday_authorization);
            })
        })
        token_req.write(postData);
        token_req.end();
    })

    return tadingday_authorization;
}

app.get('/gildataastock/v1/commontable/tadingday', async (req, res) => {

    const tadingday_authorization = await get_token();
    console.log('req==>>', req);
    const secu_market = req.query.secu_market;
    const start_date = req.query.start_date;
    const end_date = req.query.end_date;


    // 开始请求
    const tadingday_post_data = `secu_market=${secu_market}&start_date=${start_date}&end_date=${end_date}`;
    let tadingday_res_body = "";
    const tadingday_req = https.request({
        method: "POST",
        hostname: 'sandbox.hscloud.cn',
        path: '/gildataastock/v1/commontable/tadingday',
        headers: {
            "Authorization": tadingday_authorization,
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': tadingday_post_data.length
        }
    }, (tadingday_res) => {

        tadingday_res.on('data', (res_data) => {
            tadingday_res_body = tadingday_res_body + res_data;
        })

        tadingday_res.on('end', () => {
            console.log(`BODY: ${tadingday_res_body}`);
            tadingday_res_body = JSON.parse(tadingday_res_body);
            // console.log('=res_data==>>', tadingday_res_body)
            res.send(tadingday_res_body)
        })
    })
    console.log('tadingday_post_data===>>', tadingday_post_data)
    tadingday_req.write(tadingday_post_data);
    tadingday_req.end();
})

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

运行这个服务端程序后

我们可以通过访问

http://localhost:3000/gildataastock/v1/commontable/tadingday?end_date=2021-03-01&start_date=2021-01-01&secu_market=77

直接从浏览器获取数据

数据

这段代码里使用了express内置的static中间件,直接将html文件夹中的网页内容,作为服务端文件返回

image

我们访问 http://localhost:3000/tadingday/index.html 也就能自动获取tadingday文件夹中的index.html文件

index

index.html的网页内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="./static/bootstrap.min.css" rel="stylesheet">
    <script src="./static/jquery-3.6.0.min.js"></script>

    <title>交易日批量查询</title>
</head>
<body>

    <style>

        .content_info{

            display: inline-block;

            width: 100px;

            margin-bottom: 20px;
            color: #FFFFFF;
            text-align: center;
        }

        #content{
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap
        }


    </style>

    <script>


        let params = {
            start_date: "2021-06-01",
            end_date : "2021-09-01",
            secu_market : "71"
        }




        function change_start_date(start_date){

            console.log('start_date:', start_date);

            params.start_date = start_date;


        }


        function change_end_date(end_date){

            console.log('end_date:', end_date);

            params.end_date = end_date;

        }


        function change_secu_market(){

            let secu_market_select_dom = document.getElementById("secu_market_select");

            let selected_option_info = secu_market_select_dom.options[secu_market_select_dom.selectedIndex]

            params.secu_market = selected_option_info.value

        }

        // 检查参数

        function check(start_date, end_date, secu_market) {

            let check_pass = true;

            if(start_date.length === 0){

                check_pass = false;
                alert("请选择开始时间!");

            }


            if(check_pass && end_date.length === 0) {
                check_pass = false;
                alert("请选择结束时间!");

            }

            if(check_pass && start_date >= end_date) {

                alert("开始时间不得小于或等于结束时间,请重新选择!");
            }

            if(secu_market.length === 0) {

                alert("请选择类型!")
            }


            return check_pass

        }

        // 提交请求,获取数据
        function submit(){

            const check_pass = check(params.start_date, params.end_date, params.secu_market);


            if(check_pass === true){

                $.ajax({
                    url: `http://localhost:3000/gildataastock/v1/commontable/tadingday?start_date=${params.start_date}&end_date=${params.end_date}&secu_market=${params.secu_market}`,
                    type: "get",
                    success: (data, textStatus, jqXHR)=>{

                        console.log("data==>>", data);


                        let content_info = "";
                        
                        data["data"].map((value)=>{
                            const if_trading_day =  value["if_trading_day"];
                            const trading_date =  value["trading_date"];

                            const background_color = if_trading_day === "是" ? "#8DC43E": "#F16421";


                            content_info = content_info + `<div class="content_info" style='background-color: ${background_color};'>${trading_date}</div>`



                        })



                        $('#content').html(content_info);


                    }

                })

            }
            




        }

    </script>

    <div style="text-align: center; font-size: 30px;padding: 20px">交易日批量查询</div>

    <div style="display: flex;justify-content: space-between; margin: 0 20px;">
    

    <div>
        <span>开始日期</span>
        <input onchange="change_start_date(value)" type='date' value="2021-06-01"/>
    </div> 
    
    
    
    <div>
        <span>结束日期</span>
        <input onchange="change_end_date(value)" type='date' value="2021-09-01"/>
    </div> 
    
    
    <div>
        <span>选择类型</span> 
        <select class="form-select" default id="secu_market_select" onchange="change_secu_market()">
        <option value="71" selected>柜台交易市场</option>
        <option value="72">香港联交所</option>
        <option value="77">美国纳斯达克证券交易所</option>
        <option value="83">沪深证券交易所</option>
        <option value="89">银行间债券市场</option>
      </select> 
    </div>

    <button  class="btn btn-success" onclick="submit()">查询</button>

</div>

<div id="content"></div>
    
</body>
</html>

这段html里还使用了 jQuery 和BootStrap这两个经典前端包,内容放在static文件夹中

static

static 可以从github下载,地址 https://github.com/zhaoolee/it/tree/main/src/Class001/tadingday/html/tadingday/static

新建一个SQLite本地数据库,将请求数据保存到数据库中

首先,我们需要安装一个Node.js操作sqlite的依赖包 better-sqlite3

npm i better-sqlite3
  • 在项目根目录新建一个文件夹db
  • 通过better-sqlite3新建数据库并创建数据表

    // 初始化数据库
    const db = require('better-sqlite3')(path.join(__dirname, "..", "data", "tadingday.sqlite"));
    // 新建数据表
    //  secu_market: 证券市场  if_trading_day:是否交易日 if_week_end:是否周末 if_month_end:是否月末  if_quarter_end:是否季末   if_year_end:是否年末 trading_date:交易日期
    db.exec(`
        CREATE TABLE IF NOT EXISTS tadingday_info (
            secu_market VARCHAR(50),
            if_trading_day VARCHAR(10),
            if_week_end VARCHAR(10), 
            if_month_end VARCHAR(10), 
            if_quarter_end VARCHAR(10),  
            if_year_end VARCHAR(10), 
            trading_date VARCHAR(16), 
            request_secu_market VARCHAR(16),
            PRIMARY KEY(request_secu_market, trading_date)
        );
    `);
创建数据库

安装一个sqlite数据查看插件Sqlite Viewer

sqlite Viewer

安装插件Sqlite Viewer后可以查看数据库,数据表

查看数据库数据表

在数据库中,一行数据被称作一条记录, 每一列的列名被称作字段

使用Sql往数据库插入记录的语法

INSERT INTO table_name (字段名1,字段名2,字段名3,...) VALUES (字段名1对应的值,字段名2对应的值,字段名3对应的值,...);

代码思路:当请求获得数据时,调用sava_data函数, 将请求获得的数据,存储到本地sqlite数据库中

// 往本地数据库插入数据
const insert_tadingday_info = db.prepare(`INSERT INTO tadingday_info (
    secu_market,
    if_trading_day,
    if_week_end, 
    if_month_end, 
    if_quarter_end,  
    if_year_end, 
    trading_date,
    request_secu_market
) values (
    @secu_market,
    @if_trading_day,
    @if_week_end, 
    @if_month_end, 
    @if_quarter_end,  
    @if_year_end, 
    @trading_date,
    @request_secu_market
);`);


// 返回给前端后,存储到数据库

tadingday_res.on('end', () => {
    console.log(`BODY: ${tadingday_res_body}`);
    tadingday_res_body = JSON.parse(tadingday_res_body);
    res.send(tadingday_res_body)

    // 存入数据库

    tadingday_res_body["data"].map((value) => {
        value['request_secu_market'] = secu_market
        sava_data(value)
    })

})
            
// 使用sqlite数据库存储请求来的数据

function sava_data(tadingday_info_atom) {
    const { secu_market, if_trading_day, if_week_end, if_month_end, if_quarter_end, if_year_end, trading_date, request_secu_market } = tadingday_info_atom;
    try {        
        insert_tadingday_info.run(
            {
                "secu_market": secu_market, 
                "if_trading_day": if_trading_day, 
                "if_week_end": if_week_end, 
                "if_month_end": if_month_end, 
                "if_quarter_end": if_quarter_end, 
                "if_year_end": if_year_end, 
                "trading_date": trading_date, 
                "request_secu_market": request_secu_market
            }
        );
    } catch (e) {
        // console.log(e);
    }

}

在数据源失效时,查询本地数据库获取数据

使用Sql往从数据库获取记录的语法

SELECT  字段名(如果选择所有字段则使用星号\*)  FROM 表名 WHERE 条件;

SQL代码思路:

选择交易日期trading_date字段 小于结束时间end_date 并且 大于开始时间start_date 并且 证券市场代号request_secu_market 等于特定的值

select * from tadingday_info 
    WHERE 
    trading_date >= @start_date AND 
    trading_date <= @end_date AND 
    request_secu_market = @request_secu_market;`

完整代码

// 从本地数据库取数据
const select_tadingday_info = db.prepare(`select * from tadingday_info 
    WHERE 
    trading_date >= @start_date AND 
    trading_date <= @end_date AND 
    request_secu_market = @request_secu_market;`
);

// 从本地数据库获取数据
function select_data(value) {
    const { start_date, end_date, request_secu_market } = value;

    console.log("==从本地数据库取数据==")

    try {

        const result_data = select_tadingday_info.all(
            {
                "start_date": start_date, 
                "end_date": end_date, 
                "request_secu_market": request_secu_market
            }
        );
        console.log('=result_data=>>', result_data);
        return result_data
    } catch (e) {
        // console.log(e);
    }

}

运行完整工程代码

运行方法

git clone https://github.com/zhaoolee/it.git --depth=1
cd it/src/Class001/tadingday
npm install
npm run dev004

启动项目的小工具包

启动项目使用了4个小工具包

nodemon的作用是监听特定文件夹,文件内容的变化,当文件产生变化时(保存文件可触发),重新启动项目,让刚刚编写的代码生效。

opener的作用是在浏览器启动新标签页,打开特定url的网页

concurrently 的作用是同时运行多个指令,我们运行004-tadingday-server-and-sqlite.js 文件时,会产生阻塞;而concurrently可以让我们同时运行004-tadingday-server-and-sqlite.js文件和 opener打开特定页面的指令。

wait-on 是一个判断条件的包,我们启用后台服务程序会监听3000端口;但后台服务启动需要一些时间,如果3000端口还未被绑定时,浏览器就已经开始请求,那就会出现请求失败,而wait-on包可以帮我们做一个判断,当3000端口被使用的时候,再使用浏览器打开特定页面,这样就不会出现打开浏览器白屏的情况

"scripts": {
"dev004": "concurrently  'nodemon ./src/004-tadingday-server-and-sqlite.js --watch ./' 'wait-on tcp:3000 && opener http://localhost:3000/tadingday'"
  }

package.json中scripts的语法小技巧:

scripts 的指令可以非常灵活的自定义,都是键值对的形式,键为dev004, 后面的一长串就是值, 这个值需要使用整体引号包裹,如果内部出现子指令,则需要通过单引号包裹。

&& 符号代表了先后关系,前面一个指令执行完成了,后面的指令才会执行。

本文永久更新地址(欢迎来读留言,写评论):

https://www.v2fy.com/p/2021-10-27-node_js-1635325734000

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值