当前位置: 首页 > news >正文

【NodeMCU实时天气时钟温湿度项目 6】解析天气信息JSON数据并显示在 TFT 屏幕上(心知天气版)

        今天是第六专题,主要内容是:导入ArduinoJson功能库,借助该库解析从【心知天气】官网返回的JSON数据,并显示在 TFT 屏幕上。

        如您需要了解其它专题的内容,请点击下面的链接。
        第一专题内容,请参考:连接点亮SPI-TFT屏幕和UI布局设计
        第二专题内容,请参考:WIFI模式设置及连接
        第三专题内容,请参考:连接SHT30传感器,获取并显示当前环境温湿度数据(I2C)
        第四专题内容,请参考:通过NTPClient库获取实时网络时间并显示在TFT屏幕上
        第五专题内容,请参考:获取关于城市天气实况和天气预报的JSON信息(心知天气版)

一、【心知天气】官网JSON数据特点

        1、通过API返回的JSON数据,是未经压缩的明文JSON数据,可以直接使用ArduinoJson功能库解析需要的数值,JSON数据解析过程简单方便。
        2、天气实况数据。付费用户可获取全部数据;免费用户只返回天气现象文字、天气现象代码和气温 3 项数据,可供使用的数据比较少。数据更新频率,国内城市在 15 分钟左右,国际城市在 20 分钟左右。
        3、天气预报数据。可获取指定城市未来最多 15 天每天的白天和夜间预报。一般每天更新 3-4 次。付费用户可获取全部数据,免费用户只返回 3 天天气预报,可供使用的数据比较少。
        说明:如果仅作程序调试使用,可申请开通试用版,能通过API获取全部数据,试用期14天。

       

二、添加ArduinoJson库

        1、ArduinoJson库。是为 Arduino 和 IOT(Internet Of Things,物联网)开的 C++ JSON库,使用简单、高效,通用性强,在Github具备很高的活跃度。支持JSON数据的序列化、反序列化(或称序列化还原、解析)、MessagePack、流数据、过滤以及其他功能。官网链接,Github站点。
        2、添加库方法。打开 PlatformIO 界面,选择 Libraries 图标,在搜索栏内输入 ArduinoJson,在查询结果中选择ArduinoJson by Benoit Blanchon库,,添加到项目中。

        3、使用方法。解析JSON天气信息数据的程序代码,我们一般借助ArduinoJson官网提供的工具助手(Assistant),先生成基本代码,然后根据项目需要进行取舍,或进行格式转换后,再复制到项目中。本文第三部分我们进行示例说明。

        4、重要文档。关于安装库,建构和解析JSON,官方示例,API参考,FAQ等有关信息,请查阅官网 documentation 的内容。

三、解析JSON数据方法步骤 

        这是从【心知天气】官网通过API请求返回的原始JSON数据。

// 这是从【心知天气】官网通过API请求返回的原始JSON数据
{"results":[{"location":{"id":"WWE0TGW4PX6N","name":"济南","country":"CN","path":"济南,济南,山东,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"晴","code":"0","temperature":"28","feels_like":"27","pressure":"989","humidity":"31","visibility":"26.6","wind_direction":"南","wind_direction_degree":"201","wind_speed":"30.0","wind_scale":"5","clouds":"15","dew_point":""},"last_update":"2024-05-10T11:07:41+08:00"}]}

        在这部分,我们以【心知天气】返回的JSON数据为例,来说明生成解析代码的方法。
        1、打开ArduinoJson官网。点选页面上方菜单栏 [Assistant],显示以下界面。Board项,选择NodeMCU 1.0 (ESP-12E Module);Mode项,选择 Deserialize ;Input项,选择 String。点击右下方按钮 [Next:JSON]。


        2、复制JSON代码。将上述JSON原始数据复制到页面的【Input】输入框内,点击右下方按钮 【Next:Program】。

        3、生成解析程序代码。以下输入框内,就是使用助手自动生成解析代码。将代码复制到项目中,稍加调整修改后,就可以很方便地取出JSON内的数值了。

        4、测试。新建一个项目,把以下代码复制到 main.cpp 中,然后编译上传到开发板。

#include <Arduino.h>
#include <ArduinoJson.h>void setup()
{// Initialize serial portSerial.begin(9600);while (!Serial)continue;// JSON input string.const char *json = "{\"results\":[{\"location\":{\"id\":\"WWE0TGW4PX6N\",\"name\":\"济南\",\"country\":\"CN\",\"path\":\"济南,济南,山东,中国\",\"timezone\":\"Asia/Shanghai\",\"timezone_offset\":\"+08:00\"},\"now\":{\"text\":\"晴\",\"code\":\"0\",\"temperature\":\"28\",\"feels_like\":\"27\",\"pressure\":\"989\",\"humidity\":\"31\",\"visibility\":\"26.6\",\"wind_direction\":\"南\",\"wind_direction_degree\":\"201\",\"wind_speed\":\"30.0\",\"wind_scale\":\"5\",\"clouds\":\"15\",\"dew_point\":\"\"},\"last_update\":\"2024-05-10T11:07:41+08:00\"}]}";// String input;JsonDocument doc;DeserializationError error = deserializeJson(doc, json);if (error){Serial.print("deserializeJson() failed: ");Serial.println(error.c_str());return;}JsonObject results_0 = doc["results"][0];// Fetch the valuesSerial.println("");Serial.println("");Serial.print("地区名称: ");Serial.println(doc["results"][0]["location"]["name"].as<String>());Serial.print("当前天气: ");Serial.println(doc["results"][0]["now"]["text"].as<String>());Serial.print("当前温度: ");Serial.println(doc["results"][0]["now"]["temperature"].as<String>());Serial.print("空气湿度: ");Serial.println(doc["results"][0]["now"]["humidity"].as<String>());Serial.print("能见度: ");Serial.println(doc["results"][0]["now"]["visibility"].as<String>());Serial.print("风向: ");Serial.println(doc["results"][0]["now"]["wind_direction"].as<String>());Serial.print("风力: ");Serial.println(doc["results"][0]["now"]["wind_scale"].as<String>() + "级");Serial.print("风速: ");Serial.println(doc["results"][0]["now"]["wind_speed"].as<String>() + "公里/每小时");Serial.print("更新时间: ");Serial.println(doc["results"][0]["last_update"].as<String>().substring(0, 16));
}void loop(){}

        如果您在串口监视器看到如下输出信息,那就说明成功了。

四、本项目获取和解析JSON数据结构和功能函数

        关于获取和解析天气信息JSON数据的数据结构和函数,都封装在weather_xinzhi.h文件中,其中主要包括 2 个数据结构 和 4 个功能 函数。
        1、实况天气数据结构:struct weather_now_data{},用于保存解析成功后的实况天气信息。

struct weather_now_data
{// 天气现象文字,包括阴晴雨雪等天气状态的描述String text = "";// 天气现象代码int code = -1;// 温度,单位为c摄氏度String temperature = "0";// 体感温度,默认单位:摄氏度int feels_like = 0;// 大气压强,默认单位:百帕int pressure = -1;// 相对湿度,0~100,单位为百分比int humidity = -1;// 能见度,默认单位:公里int visibility = -1;// 风向文字String wind_direction = "";// 风向角度,范围0~360,0为正北,90为正东,180为正南,270为正西String wind_direction_degree = "-1";// 风速,单位为km/h公里每小时或mph英里每小时int wind_speed = -1;// 风力等级String wind_scale = "-1";// 数据更新时间(该城市的本地时间)String last_update = "";
} wd;

        2、天气预报数据结构:struct weather_tmr_data{},用于保存获取到的天气预报信息。

struct weather_tmr_data
{String location_name;              // 预报地区名称String date = "";                  // 日期(该城市的本地时间)String text_day = "";              // 白天天气现象文字String code_day = "";              // 白天天气现象代码String text_night = "";            // 晚间天气现象文字String code_night = "";            // 晚间天气现象代码String high = "";                  // 当天最高温度String low = "";                   // 当天最低温度String precip = "";                // 降水概率,范围0~1,单位百分比(目前仅支持国外城市)String wind_direction = "";        // 风向文字String wind_direction_degree = ""; // 风向角度,范围0~360String wind_speed = "";            // 风速,单位km/h(当unit=c时)、mph(当unit=f时)String wind_scale = "";            // 风力等级String rainfall = "";              // 降水量,单位mmString humidity = "";              // 相对湿度,0~100,单位为百分比String last_update = "";           // 数据更新时间(该城市的本地时间)
};weather_tmr_data wtd[3];

        3、获取实况天气函数:void get_now_Weather()

// 获取实况天气函数
void get_now_Weather()
{// 检查WI-FI是否已连接if (WiFi.status() == WL_CONNECTED){// 准备发起请求std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);client->setInsecure();HTTPClient https;// Serial.print("[HTTPS] begin...\n");// 请求接口if (https.begin(*client, "https://api.seniverse.com/v3/weather/now.json?key=" + key + "&location=" + city_name + "&language=zh-Hans&unit=c")){// 获取HTTP的状态码,一般200=成功,出现其他的比如404、500 均为各种报错int httpCode = https.GET();Serial.println(httpCode);if (httpCode > 0){if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY){// 从接口获取数据String payload = https.getString();Serial.println(payload);// 调用解析函数JsonDocument doc;DeserializationError err = deserializeJson(doc, payload);if (err.code() == DeserializationError::Ok){get_now_weather_data(doc);}else{Serial.println("数据解析出错");}}}else{Serial.printf("[HTTP] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());}https.end();}}
}

        4、获取未来几天的天气预报函数:void get_tmr_Weather(),可以在 https.begin() 函数中,根据需要修改起始日期和天数。

// 获取未来3天的天气预报
void get_tmr_Weather()
{// 检查WI-FI是否已连接if (WiFi.status() == WL_CONNECTED){// 准备发起请求std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);client->setInsecure();HTTPClient https;// 请求接口if (https.begin(*client, "https://api.seniverse.com/v3/weather/daily.json?key=" + key + "&location=" + city_name + "&language=zh-Hans&unit=c&start=1&days=3")){// 获取HTTP的状态码,一般200=成功,出现其他的比如404、500 均为各种报错int httpCode = https.GET();Serial.println(httpCode);if (httpCode > 0){if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY){// 从接口获取数据String payload = https.getString();Serial.println(payload);// 调用解析函数JsonDocument doc;DeserializationError err = deserializeJson(doc, payload);if (err.code() == DeserializationError::Ok){get_tmr_weather_data(doc);}else{Serial.println("数据解析出错");}}}else{Serial.printf("[HTTP] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());}https.end();}}
}

        5、提取实况天气具体数值的函数:void get_now_weather_data(JsonDocument &doc)

void get_now_weather_data(JsonDocument &doc)
{// 将数据保存到weahter_data 的结构体,方便后续调用wd.text = doc["results"][0]["now"]["text"].as<String>();wd.code = doc["results"][0]["now"]["code"];wd.temperature = doc["results"][0]["now"]["temperature"].as<String>();wd.feels_like = doc["results"][0]["now"]["feels_like"].as<int>();wd.pressure = doc["results"][0]["now"]["pressure"].as<int>();wd.humidity = doc["results"][0]["now"]["humidity"].as<int>();wd.visibility = doc["results"][0]["now"]["visibility"].as<int>();wd.wind_direction = doc["results"][0]["now"]["wind_direction"].as<String>();wd.wind_direction_degree = doc["results"][0]["now"]["wind_direction_degree"].as<String>();wd.wind_speed = doc["results"][0]["now"]["wind_speed"].as<int>();wd.wind_scale = doc["results"][0]["now"]["wind_scale"].as<String>();wd.last_update = doc["results"][0]["last_update"].as<String>().substring(0, 16);wd.last_update.replace("T", " ");
}

        6、提取未来天气预报具体数值的函数:void get_tmr_weather_data(JsonDocument &doc)

void get_tmr_weather_data(JsonDocument &doc)
{// 将数据保存到weahter_tmr_data 的结构体,方便后续调用wtd[0].location_name = doc["results"][0]["location"]["name"].as<String>();                          日期(该城市的本地时间)wtd[0].date = doc["results"][0]["daily"][0]["date"].as<String>();                                   日期(该城市的本地时间)wtd[0].text_day = doc["results"][0]["daily"][0]["text_day"].as<String>();                           // 白天天气现象文字wtd[0].code_day = doc["results"][0]["daily"][0]["code_day"].as<String>();                           // 白天天气现象代码wtd[0].text_night = doc["results"][0]["daily"][0]["text_night"].as<String>();                       // 晚间天气现象文字wtd[0].code_night = doc["results"][0]["daily"][0]["code_night"].as<String>();                       // 晚间天气现象代码wtd[0].high = doc["results"][0]["daily"][0]["high"].as<String>();                                   // 当天最高温度wtd[0].low = doc["results"][0]["daily"][0]["low"].as<String>();                                     // 当天最低温度wtd[0].precip = doc["results"][0]["daily"][0]["precip"].as<String>();                               // 降水概率,范围0~1,单位百分比(目前仅支持国外城市)wtd[0].wind_direction = doc["results"][0]["daily"][0]["wind_direction"].as<String>();               // 风向文字wtd[0].wind_direction_degree = doc["results"][0]["daily"][0]["wind_direction_degree"].as<String>(); // 风向角度,范围0~360wtd[0].wind_speed = doc["results"][0]["daily"][0]["wind_speed"].as<String>();                       // 风速,单位km/h(当unit=c时)、mph(当unit=f时)wtd[0].wind_scale = doc["results"][0]["daily"][0]["wind_scale"].as<String>();                       // 风力等级wtd[0].rainfall = doc["results"][0]["daily"][0]["rainfall"].as<String>();                           // 降水量,单位mmwtd[0].humidity = doc["results"][0]["daily"][0]["humidity"].as<String>();                           // 相对湿度,0~100,单位为百分比wtd[0].last_update = doc["results"][0]["last_update"].as<String>().substring(0, 16);                // 数据更新时间(该城市的本地时间)wtd[0].last_update.replace("T", " ");
}

        7、说明。关于 main.cpp 内容的修改,主要集中在调用既有功能函数和调整显示位置方面,请大家自行阅读代码。
        特别提醒修改两项内容:(1)WiFi连接的 ssid 和 password;(2)心知天气私钥。
        免费用户获的信息数据受到限制,可以申请开通试用版,测试体验全部信息数据。

// 项目 main.cpp 主要内容
#include <Arduino.h>
#include <TFT_eSPI.h>
#include <ArduinoJson.h>// 连接wifi用的库
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>/**配置您所在环境的wifi 账号和密码注意:切勿连接 5G的频率、不要使用双频融合(路由器)注意:账号密码必须完全正确,包括字母大小写、空格、中划线、下划线
*/
const char *ssid = "xcb940";
const char *password = "87589940abc";//const char *ssid = "LGCWZS";
//const char *password = "87129168";// 构造函数,实例化 TFT 屏幕对象
TFT_eSPI tft = TFT_eSPI();// WiFi 连接函数声明
void connectWiFi();// 程序用到的字库文件,后面会详细说明
#include "hefeng-min-40px.h"
#include "weather_font20.h"
#include "weather_font16.h"// 网络时钟的刷新频率
unsigned long last_ntp = 0;
const long interval_ntp = 1000; // 网络时钟的刷新频率(毫秒)// 今日天气的刷新频率
unsigned long last_weather = 0;
const long interval_weather = 1000 * 60 * 5; // 今日天气的刷新频率(毫秒),每300毫秒更新一次// 明日天气的刷新频率
unsigned long last_tmr_weather = 0;
const long interval_tmr_weather = 1000 * 60 * 60; // 明天天气的刷新频率(毫秒),每3600毫秒更新一次// 温湿度传感器的刷新频率
unsigned long last_sht = 0;
const long interval_sht = 3000; // 温湿度传感器的刷新频率(毫秒),每3000毫秒更新一次// 心知天气免费版密钥**************
// const String key = "**************";// 心知天气试用版密钥**************,有效期14天,自2024-05-09始
const String key = "**************";// 你的城市ID,获取方法参考课程
const String city_name = "jinan";#include "sht30.h"
#include "ntptime.h"
#include "weather_xinzhi.h"void setup()
{Serial.begin(115200);tft.init();tft.setSwapBytes(true);tft.setRotation(0);tft.fillScreen(TFT_BLACK);tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.setTextSize(2);// 联网tft.println("Wi-Fi >> " + String(ssid));// initWiFi();connectWiFi();tft.println("");tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.println("");// 今日天气tft.println("Get Today weather");get_now_Weather();get_tmr_Weather();tft.setTextSize(1);tft.println("");tft.setTextSize(2);// 对时tft.println("Get NTP Time");initNtp();// 温湿度传感器tft.println("");tft.println("load Sensor Data..");sht30_setup();tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.println("");tft.println("start...");delay(500);tft.fillScreen(TFT_BLACK);
}void loop()
{// 获取单片机启动至今的毫秒数unsigned long currentMillis = millis();// 显示当前日期,星期几,农历// update ntp 时间if (last_ntp == 0 || currentMillis - last_ntp >= interval_ntp){last_ntp = currentMillis;loopNtp();tft.loadFont(weather_font16);tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.drawString(dt.localDate + "  " + weekOfDate1(dt.year, dt.month, dt.day) + " " + outputLunarDate(dt.year, dt.month, dt.day), 0, 0);tft.unloadFont();tft.setTextSize(5);tft.setTextColor(TFT_GREEN, TFT_BLACK, true);tft.drawString(dt.localTime, 0, 30);}// 今日天气if (last_weather == 0 || currentMillis - last_weather >= interval_weather){if (last_weather > 0){get_now_Weather();}last_weather = currentMillis;// 擦除指定区域tft.fillRect(55, 90, 240, 40, TFT_BLACK);tft.setTextColor(TFT_YELLOW, TFT_BLACK, true);tft.loadFont(hefeng40);// tft.drawString(icon(wd.now_icon), 10, 90);tft.unloadFont();tft.loadFont(weather_font20);tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.drawString("Now: " + String(wd.temperature) + "° " + wd.text, 55, 90);tft.drawString(wd.wind_direction + "风" + String(wd.wind_scale) + "级 " + wd.wind_speed + "KM/H", 55, 110);tft.drawLine(0, 140, 240, 140, TFT_WHITE);}// 明日天气if (last_tmr_weather == 0 || currentMillis - last_tmr_weather > interval_tmr_weather){if (last_tmr_weather > 0){get_tmr_Weather();}last_tmr_weather = currentMillis;// 擦除指定区域tft.fillRect(55, 150, 240, 40, TFT_BLACK);tft.loadFont(hefeng40);tft.setTextColor(TFT_YELLOW, TFT_BLACK, true);// tft.drawString(icon(wtd[1].iconDay), 10, 150);tft.unloadFont();tft.loadFont(weather_font20);tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.drawString("明天 " + String(wtd[0].low) + "° - " + String(wtd[0].high) + "°", 55, 150);tft.drawString(wtd[0].text_day+ ", " + "风力" + wtd[0].wind_scale + "级", 55, 170);// 这条线其实没必要重新绘制tft.drawLine(0, 200, 240, 200, TFT_WHITE);}// 温湿度传感器的数据if (last_sht == 0 || currentMillis - last_sht > interval_sht){last_sht = currentMillis;sht30();tft.loadFont(weather_font20);tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.drawString("室温:", 0, 210);tft.setTextColor(TFT_GREEN, TFT_BLACK, true);tft.drawString(String(sht_data.temperature) + "C ", 40, 210);tft.setTextColor(TFT_WHITE, TFT_BLACK, true);tft.drawString("湿度", 120, 210);tft.setTextColor(TFT_GREEN, TFT_BLACK, true);tft.drawString(String(sht_data.humidity) + "%  ", 170, 210); //+3(原为120)的x轴位置,因为视觉上似乎贴的优点近了}
}// 连接wifi
void connectWiFi()
{Serial.print("Connecting to ");Serial.println(ssid);// 设置WiFi工作在终端模式,参数可选填WIFI_AP、WIFI_STA、WIFI_AP_STA、WIFI_OFFWiFi.mode(WIFI_STA);// 开始连接WiFi.begin(ssid, password);// 检查连接是否成功while (WiFi.status() != WL_CONNECTED){delay(500);Serial.print(".");tft.print(".");}tft.println("");tft.println("");tft.setTextColor(TFT_GREEN, TFT_BLACK, true);tft.println(WiFi.localIP());// 设置:当路由器断开连接时,是否启动自动重新连接功能。true: 启用自动重新连接;false:不启用此功能WiFi.setAutoReconnect(true);// 设置:是否将WiFi参数保存于Flash中,默认为true,即在每次调用WiFi.begin()、WiFi.softAP()、WiFi.disconnect、WiFi.softAPdisconnect方法时都会将相关数据写入到Flash中;//       当设置为false时,以上动作将不会把数据写入Flash中,仅仅改变内存中的WiFi设置WiFi.persistent(true);// 连接成功后,在串口监视器显示自身IP地址,以下5行代码作调试用Serial.println("");Serial.println("WiFi connected");Serial.println("IP address: ");Serial.println(WiFi.localIP());Serial.println("");
}

五、项目运行展示

NodeMcu1.0_天气时钟温湿度展示

六、项目源代码下载

        百度网盘下载地址:
        https://pan.baidu.com/s/1-cENF6LaInjF3sw_qs40Vg?pwd=me32,
        提取码:me32

        部分代码来自于网络大神,如有异议,请联系。

参考文档
1. JSON 基本使用_json怎么用-CSDN博客
2. JSON——概述、JSON语法、序列化和反序列化_所有文档都可以通过json序列化吗-CSDN博客

相关文章:

【NodeMCU实时天气时钟温湿度项目 6】解析天气信息JSON数据并显示在 TFT 屏幕上(心知天气版)

今天是第六专题&#xff0c;主要内容是&#xff1a;导入ArduinoJson功能库&#xff0c;借助该库解析从【心知天气】官网返回的JSON数据&#xff0c;并显示在 TFT 屏幕上。 如您需要了解其它专题的内容&#xff0c;请点击下面的链接。 第一专题内容&#xff0c;请参考&a…...

重构四要素:目的、对象、时机和方法

目录 1.引言 2.重构的目的:为什么重构(why) 3.重构的对象:到底重构什么(what) 4.重构的时机:什么时候重构(when) 5.重构的方法:应该如何重构(how) 6.思考题 1.引言 一些软件工程师对为什么要重构(why)、到底重构什么(what)、什么时候重构(when)应该如何重构(how)等问题的…...

基于Echarts的大数据可视化模板:服务器运营监控

目录 引言背景介绍研究现状与相关工作服务器运营监控技术综述服务器运营监控概述监控指标与数据采集可视化界面设计与实现数据存储与查询优化Echarts与大数据可视化Echarts库以及其在大数据可视化领域的应用优势开发过程和所选设计方案模板如何满足管理的特定需求模板功能与特性…...

Python3 笔记:Python的常量

常量&#xff08;constant&#xff09;&#xff1a;跟变量相对应&#xff0c;指第一次赋予值后就保持固定不变的值。 Python里面没有声明常量的关键字&#xff0c;其他语言像C/C/Java会有const修饰符&#xff0c;但Python没有。 Python中没有使用语法强制定义常量&#xff0c…...

【Linux】自动化构建工具make/Makefile和git介绍

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12625432.html 目录 前言 Linux项目自动化构建工具-make/Makefile 举例 .PHONY 常见符号 依赖关系…...

C语言—关于字符串(编程实现部分函数功能)

0.前言 当我们使用这些函数功能时&#xff0c;可以直接调用头文件---#include<string.h>&#xff0c;然后直接使用就行了,本文只是手动编写实现函数的部分功能 1.strlen函数功能实现 功能说明&#xff1a;strlen(s)用来计算字符串s的长度&#xff0c;该函数计数不会包括最…...

picoCTF-Web Exploitation-Trickster

Description I found a web app that can help process images: PNG images only! 这应该是个上传漏洞了&#xff0c;十几年没用过了&#xff0c;不知道思路是不是一样的&#xff0c;以前的思路是通过上传漏洞想办法上传一个木马&#xff0c;拿到webshell&#xff0c;今天试试看…...

SSH 免密登录,设置好仍然需要密码登录解决方法

说明&#xff1a; ssh秘钥登录设置好了&#xff0c;但是登录的时候依然需要提供密码 查看系统安全日志&#xff0c;定位问题 sudo cat /var/log/auth.log或者 sudo cat /var/log/secure找到下面的信息 Authentication refused: bad ownership or modes...&#xff08;网上的…...

【斑马打印机】web前端页面通过BrowserPrint API连接斑马打印机进行RFID条形码贴纸打印

web前端页面通过BrowserPrint API连接斑马打印机进行RFID条形码贴纸打印 在现代物流、仓储和零售行业中,RFID和二维码技术发挥着至关重要的作用。这些技术不仅提高了效率,还增强了追踪和管理的能力。本文将介绍如何使用JavaScript和斑马打印机的BrowserPrint API来打印RFID二…...

DigitalOcean 应用托管更新:应用端到端运行时性能大幅改进

DigitalOcean 希望可以为企业提供所需的工具和基础设施&#xff0c;以帮助企业客户加速云端的开发&#xff0c;实现业务的指数级增长。为此 DigitalOcean 在 2020 年就推出了App Platform。 App Platform&#xff08;应用托管&#xff09; 是一个完全托管的 PaaS 解决方案&…...

c/c++对于char*的理解(联合string容器)

在C和C中&#xff0c;char*是一个指向字符&#xff08;char&#xff09;的指针。它经常被用来处理C风格的字符串&#xff0c;这种字符串是以空字符&#xff08;\0&#xff09;结尾的字符数组。以下是关于char*的一些关键点&#xff1a; C风格的字符串&#xff1a; C风格的字符…...

Web前端三大主流框架是什么?

Web前端开发领域的三大主流框架分别是Angular、React和Vue.js。它们在Web开发领域中占据着重要的地位&#xff0c;各自拥有独特的特点和优势。 Angular Angular是一个由Google开发的前端框架&#xff0c;最初版本称为AngularJS&#xff0c;后来升级为Angular。它是一个完整的…...

一个基于servlet的MVC项目-登录验证

一、MVC的概念 MVC是Model、View、Controller的缩写&#xff0c;分别代表 Web 应用程序中的3种职责1 模型:用于存储数据以及处理用户请求的业务逻辑。 2视图:向控制器提交数据&#xff0c;显示模型中的数据。 3控制器:根据视图提出的请求&#xff0c;判断将请求和数据交给哪个…...

Windows 11 下 kafka 的安装踩坑

安装 windows系统kafka小白入门篇——下载安装&#xff0c;环境配置&#xff0c;入门代码书写&#xff08;推荐&#xff09; kafka在windows下安装和使用入门教程 问题1 参考链接 运行kafka集成的zookeeper时&#xff0c;命令&#xff1a;bin\windows\zookeeper-server-star…...

二维数组:行列互换/求最大值及其所在位置/求各行各列的和/矩阵乘积/深入理解二维数组

二维数组 1.定义 只有行号可以省略&#xff0c;初始化 全部初始化/部分初始化/不初始化 2.元素引用 3.存储形式 :顺序存储 按行存储 4.深入理解二维数组 #include<stdio.h> #include<stdlib.h>#define M 2 #define N 3int mian() {int a[M][N] {{1,2,3},{4,5,6}}…...

The Onion Router-洋葱

目录 Tor的运作原理 Tor挑战和局限性 Tor&#xff0c;即The Onion Router&#xff08;洋葱路由器&#xff09;&#xff0c;是一个用于匿名通信的开放网络&#xff0c;它旨在增强用户的隐私和安全。Tor的名字源自其设计原理&#xff0c;类似于将信息包装在多层“洋葱”中&…...

自动化工具 Ansible:playbooks 剧本编写

目录 前言 一、playbooks 剧本概述 1、playbooks 剧本概念 2、playbooks 剧本组成部分 3、playbooks 剧本特点与优势 二、ansible-playbook 命令 三、playbooks 剧本简单实例 1、编写 apache 的 yum 安装部署脚本 2、编写 nginx 的 yum 安装部署剧本 四、playbooks 定…...

AttributeError: module ‘flask.app‘ has no attribute ‘route‘

秒解方法一&#xff1a; # 未引入Flask app Flask(__name__)秒解方法二&#xff1a; AttributeError: ‘module’ object has no attribute ‘route’错误描述&#xff1a; 这个错误通常发生在使用 app.route 装饰器时&#xff0c;表示 Flask 无法找到 route 属性。 解决方法…...

在云计算与人工智能中,7ECloud扮演着什么样的角色

数据驱动的时代&#xff0c;云计算和人工智能已成为推动现代科技进步的两大引擎。作为一家专注于云计算的公司&#xff0c;7ECloud正是在这个领域发挥自己的力量&#xff0c;力图为企业提供一站式解决方案&#xff0c;并拥有来自厂家的源头支持&#xff0c;用极其低的价格助力企…...

视频推拉流EasyDSS视频直播点播平台如何优先展示正在直播的直播间?

视频推拉流EasyDSS视频直播点播平台集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体&#xff0c;可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务&#xff0c;在应用场景上&#xff0c;平台可以运用在互联网教育、在线课堂、游戏…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...