Qt系列:调用Edge浏览器示例
背景
需要解决以下几个问题
- 政府项目新浏览器兼容老系统ActiveX控件,Qt WebEngineView没有直接的实现方案,需要利用Qt的ActiveX兼容模块与浏览器往返多次交互
- Qt ActiveX未实现COM事件通知
- 官方Win32示例存在滥用lambda函数的嫌疑,lambda函数多层嵌套,程序逻辑层次混乱,整个逻辑被揉成一垛。
官方示例代码
官方介绍文档在这里:https://learn.microsoft.com/microsoft-edge/webview2/get-started/win32。官方代码仓库在这里:GitHub - MicrosoftEdge/WebView2Samples: Microsoft Edge WebView2 samples
摘录一段lambda多层嵌套的代码,你们体会一下:
CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>([hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {// Create a CoreWebView2Controller and get the associated CoreWebView2 whose parent is the main window hWndenv->CreateCoreWebView2Controller(hWnd, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>([hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {if (controller != nullptr) {webviewController = controller;webviewController->get_CoreWebView2(&webview);}// Add a few settings for the webview// The demo step is redundant since the values are the default settingswil::com_ptr<ICoreWebView2Settings> settings;webview->get_Settings(&settings);settings->put_IsScriptEnabled(TRUE);settings->put_AreDefaultScriptDialogsEnabled(TRUE);settings->put_IsWebMessageEnabled(TRUE);// Resize WebView to fit the bounds of the parent windowRECT bounds;GetClientRect(hWnd, &bounds);webviewController->put_Bounds(bounds);// Schedule an async task to navigate to Bingwebview->Navigate(L"https://www.bing.com/");// <NavigationEvents>// Step 4 - Navigation events// register an ICoreWebView2NavigationStartingEventHandler to cancel any non-https navigationEventRegistrationToken token;webview->add_NavigationStarting(Callback<ICoreWebView2NavigationStartingEventHandler>([](ICoreWebView2* webview, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT {wil::unique_cotaskmem_string uri;args->get_Uri(&uri);std::wstring source(uri.get());if (source.substr(0, 5) != L"https") {args->put_Cancel(true);}return S_OK;}).Get(), &token);// </NavigationEvents>// <Scripting>// Step 5 - Scripting// Schedule an async task to add initialization script that freezes the Object objectwebview->AddScriptToExecuteOnDocumentCreated(L"Object.freeze(Object);", nullptr);// Schedule an async task to get the document URLwebview->ExecuteScript(L"window.document.URL;", Callback<ICoreWebView2ExecuteScriptCompletedHandler>([](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT {LPCWSTR URL = resultObjectAsJson;//doSomethingWithURL(URL);return S_OK;}).Get());// </Scripting>// <CommunicationHostWeb>// Step 6 - Communication between host and web content// Set an event handler for the host to return received message back to the web contentwebview->add_WebMessageReceived(Callback<ICoreWebView2WebMessageReceivedEventHandler>([](ICoreWebView2* webview, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {wil::unique_cotaskmem_string message;args->TryGetWebMessageAsString(&message);// processMessage(&message);webview->PostWebMessageAsString(message.get());return S_OK;}).Get(), &token);// Schedule an async task to add initialization script that// 1) Add an listener to print message from the host// 2) Post document URL to the hostwebview->AddScriptToExecuteOnDocumentCreated(L"window.chrome.webview.addEventListener(\'message\', event => alert(event.data));" \L"window.chrome.webview.postMessage(window.document.URL);",nullptr);// </CommunicationHostWeb>return S_OK;}).Get());return S_OK;}).Get());
解决方案
下面以实现自动登录外网网关为目标,企业微信自动上线,免开机输入账号密码。这样领导看到你上线,可以开机以后就可以慢慢吃早餐了。(开个玩笑)
本实现方案把官方示例代码做成了静态库,没有添加其它东西。
新建CMake项目
这里用到了Qt5静态库,目的是单文件可执行,不需要部署。需要静态库的读者可以自行删除。代码如下:
cmake_minimum_required(VERSION 3.21)
project(auto-online CXX)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)add_definitions(/D_UNICODE /DUNICODE)
add_compile_definitions(WIN32 _WINDOWS)add_compile_options(/utf-8 $<IF:$<CONFIG:Debug>,/MTd,/MT>)
link_directories($ENV{Qt5_DIR}/lib)
link_directories($ENV{Qt5_DIR}/plugins/platforms)
link_directories($ENV{Qt5_DIR}/plugins/imageformats)
link_libraries(UxTheme Winmm Version ws2_32 imm32 dwmapi)link_libraries($<IF:$<CONFIG:Debug>,Qt5FontDatabaseSupportd,Qt5FontDatabaseSupport>)
link_libraries($<IF:$<CONFIG:Debug>,Qt5UiToolsd,Qt5UiTools>)
link_libraries($<IF:$<CONFIG:Debug>,Qt5AccessibilitySupportd,Qt5AccessibilitySupport>)
link_libraries($<IF:$<CONFIG:Debug>,Qt5EventDispatcherSupportd,Qt5EventDispatcherSupport>)
link_libraries($<IF:$<CONFIG:Debug>,Qt5ThemeSupportd,Qt5ThemeSupport>)
link_libraries($<IF:$<CONFIG:Debug>,Qt5UiToolsd,Qt5UiTools>)link_libraries($<IF:$<CONFIG:Debug>,qtpcre2d,qtpcre2>)
link_libraries($<IF:$<CONFIG:Debug>,qtlibpngd,qtlibpng>)
link_libraries($<IF:$<CONFIG:Debug>,qtharfbuzzd,qtharfbuzz>)
link_libraries($<IF:$<CONFIG:Debug>,qtfreetyped,qtfreetype>)
link_libraries($<IF:$<CONFIG:Debug>,qwindowsd,qwindows>)
link_libraries($<IF:$<CONFIG:Debug>,qicnsd,qicns>)
link_libraries($<IF:$<CONFIG:Debug>,qtgad,qtga>)
link_libraries($<IF:$<CONFIG:Debug>,qtiffd,qtiff>)
link_libraries($<IF:$<CONFIG:Debug>,qwbmpd,qwbmp>)
link_libraries($<IF:$<CONFIG:Debug>,qtiffd,qtiff>)
link_libraries($<IF:$<CONFIG:Debug>,qwebpd,qwebp>)
link_libraries($<IF:$<CONFIG:Debug>,qgifd,qgif>)
link_libraries($<IF:$<CONFIG:Debug>,qjpegd,qjpeg>)
link_libraries($<IF:$<CONFIG:Debug>,qicod,qico>)message("-- Qt5_DIR: " $ENV{Qt5_DIR})
find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED)include_directories(${CMAKE_SOURCE_DIR}/3rdparty/webview2loader/include)
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/wil/include)
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/webview2loader/lib)
link_libraries(Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network WebView2LoaderStatic)file(GLOB SRCS *.ui *.cpp *.h)
add_executable(${PROJECT_NAME} WIN32 ${SRCS})
set_directory_properties(PROPERTIES VS_STARTUP_PROJECT ${PROJECT_NAME})
# 环境变量的路径不能带双引号
# message("VCINSTALLDIR: " $ENV{VCINSTALLDIR})
# find_file(VSPATH NAMES "vcruntime140d.dll" PATHS $ENV{VCINSTALLDIR} REQUIRED NO_DEFAULT_PATH)
# file(TO_NATIVE_PATH ${VSPATH} VSPATH)
#message("VC CRT PATH: " ${VSPATH})
# set(VSPATH $<IF:$<CONFIG:Debug>,$ENV{VCINSTALLDIR}/Redist/MSVC/14.29.30133/onecore/debug_nonredist/x64/Microsoft.VC142.DebugCRT,$ENV{VCINSTALLDIR}/Redist/MSVC/14.29.30133/x64/Microsoft.VC142.CRT> CACHE STRING "VCRT" FORCE)
# string(CONCAT VSPATH ${VSPATH} ";$ENV{Qt5_DIR}\\bin")set_target_properties(${PROJECT_NAME} PROPERTIESVS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_BINARY_DIR}VS_DEBUGGER_ENVIRONMENT "Path=$ENV{Qt5_DIR}\\bin"WIN32_EXECUTABLE TRUE)
用Qt Designer设计一个简单的窗口类型
类型名字很简单,就是MainWindow。这个窗口仅启用了布局,没有添加任何控件。UI代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>600</height></rect></property><property name="windowTitle"><string>MainWindow</string></property><widget class="QWidget" name="central_widget"><layout class="QVBoxLayout" name="vl1"><property name="spacing"><number>0</number></property><property name="leftMargin"><number>0</number></property><property name="topMargin"><number>0</number></property><property name="rightMargin"><number>0</number></property><property name="bottomMargin"><number>0</number></property><item><widget class="QWidget" name="browser_widget" native="true"><layout class="QVBoxLayout" name="vl2"/></widget></item></layout></widget></widget><resources/><connections/>
</ui>
声明信号槽
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QThread>#include <windows.h>
#include <stdlib.h>
#include <string>
#include <tchar.h>
#include "wrl.h"
#include "wil/com.h"
#include "WebView2.h"#define PROFILE_DATA "cw_webview2"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();void load_webview2(HWND hWnd);void task_run();HRESULT cb_create_environment(HWND, HRESULT, ICoreWebView2Environment *);HRESULT cb_create_controller(HWND, HRESULT, ICoreWebView2Controller *);HRESULT on_navigate_started(ICoreWebView2 *, ICoreWebView2NavigationStartingEventArgs *);HRESULT cb_execute_script(HRESULT, LPCWSTR);HRESULT on_webmessage_received(ICoreWebView2 *, ICoreWebView2WebMessageReceivedEventArgs *);HRESULT on_navigate_completed(ICoreWebView2*, ICoreWebView2NavigationCompletedEventArgs*);// HRESULT cb_deliver(HWND, HRESULT, ...);signals:void prepare();void load_auth_page();void put_name();void put_password();void click_login();void wait(int iminute);protected:void resizeEvent(QResizeEvent* evt) override;void closeEvent(QCloseEvent*) override;protected slots:void on_prepare();void on_load_auth_page();void on_put_name();void on_put_password();void on_click_login();void on_wait(int iminute);private:Ui::MainWindow *ui;// Pointer to WebViewControllerwil::com_ptr<ICoreWebView2Controller> m_controller;bool m_brunning = false;QThread* m_task;// Pointer to WebView windowwil::com_ptr<ICoreWebView2_15> m_webview;Microsoft::WRL::ComPtr<ICoreWebView2ExecuteScriptCompletedHandler> js_cb;Microsoft::WRL::ComPtr<ICoreWebView2WebMessageReceivedEventHandler> msg_cb;
};#endif // MAINWINDOW_H
在合适的时机填入账号密码
本来想做成弹框让用户输入账号密码,忽然发现这种做法对信息部门的同事不太友好,各位读者如有请自行修改。示例代码中的网关地址、用户名和密码是乱写的。
#include "MainWindow.h"
#include "ui_MainWindow.h"#include <QResizeEvent>
#include <QRect>
#include <QDebug>
#include <QStandardPaths>
#include <QDir>
#include <QMessageBox>
#include <QTimer>
#include <QApplication>using namespace Microsoft::WRL;MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);load_webview2((HWND)ui->browser_widget->winId());setWindowTitle(u8"自动连接外网工具");connect(this, SIGNAL(prepare()), this, SLOT(on_prepare()), Qt::QueuedConnection);connect(this, SIGNAL(load_auth_page()), this, SLOT(on_load_auth_page()), Qt::QueuedConnection);connect(this, SIGNAL(put_name()), this, SLOT(on_put_name()), Qt::QueuedConnection);connect(this, SIGNAL(put_password()), this, SLOT(on_put_password()), Qt::QueuedConnection);connect(this, SIGNAL(click_login()), this, SLOT(on_click_login()), Qt::QueuedConnection);connect(this, SIGNAL(wait(int)), this, SLOT(on_wait(int)), Qt::QueuedConnection);
}MainWindow::~MainWindow()
{delete ui;
}HRESULT MainWindow::on_navigate_started(ICoreWebView2 *webview,ICoreWebView2NavigationStartingEventArgs *args)
{wil::unique_cotaskmem_string uri;args->get_Uri(&uri);QString zurl = QString::fromStdWString(uri.get());// std::wstring source(uri.get());// if (source.substr(0, 5) != L"https")// {// args->put_Cancel(true);// }qInfo().noquote() << "navigate: " << zurl;return S_OK;
}HRESULT MainWindow::cb_execute_script(HRESULT errorCode, LPCWSTR resultObjectAsJson)
{LPCWSTR URL = resultObjectAsJson;//doSomethingWithURL(URL);qInfo() << "executed javascript.";return S_OK;
}HRESULT MainWindow::on_webmessage_received(ICoreWebView2 *webview,ICoreWebView2WebMessageReceivedEventArgs *args)
{wil::unique_cotaskmem_string message;args->TryGetWebMessageAsString(&message);// processMessage(&message);//webview->PostWebMessageAsString(message.get());QString zmsg = QString::fromStdWString(message.get());qInfo().noquote() << "message: " << zmsg;return S_OK;
}HRESULT MainWindow::on_navigate_completed(ICoreWebView2 *webview,ICoreWebView2NavigationCompletedEventArgs *args)
{BOOL bsuccess;COREWEBVIEW2_WEB_ERROR_STATUS ierror;args->get_IsSuccess(&bsuccess);args->get_WebErrorStatus(&ierror);LPWSTR lpuri;webview->get_Source(&lpuri);QString zuri = QString::fromStdWString(lpuri);qInfo().noquote() << "complate : " << bsuccess << ", " << ierror << ", " << zuri;return S_OK;
}void MainWindow::resizeEvent(QResizeEvent *evt)
{if (!m_controller)return;RECT rc;QRect qrc = ui->browser_widget->rect();rc.left = qrc.left();rc.top = qrc.top();rc.right = qrc.right();rc.bottom = qrc.bottom();m_controller->put_Bounds(rc);
}void MainWindow::closeEvent(QCloseEvent *)
{m_brunning = false;m_task->terminate();QThread::sleep(1);m_task->deleteLater();m_task = nullptr;
}void MainWindow::on_prepare()
{if (!m_webview)return;m_webview->NavigateToString(L"Preparing...");
}void MainWindow::on_load_auth_page()
{if (!m_webview)return;m_webview->Navigate(L"http://1.1.1.3/ac_portal/default/pc.html?tabs=pwd");qInfo() << "begin load auth page";
}void MainWindow::on_put_name()
{if (!m_webview)return;m_webview->ExecuteScript(L"$('#password_name').val('test1');""window.chrome.webview.postMessage('put name ok.');",js_cb.Get());
}void MainWindow::on_put_password()
{if (!m_webview)return;m_webview->ExecuteScript(L"$('#password_pwd').val('123456');""window.chrome.webview.postMessage('put password ok.');",js_cb.Get());
}void MainWindow::on_click_login()
{if (!m_webview)return;m_webview->ExecuteScript(L"$('#password_submitBtn').click();""window.chrome.webview.postMessage('click login ok.');",js_cb.Get());
}void MainWindow::on_wait(int iminute)
{QString zhtml = QString("Already wairted %1 minutes.").arg(iminute);if (!m_webview)return;m_webview->NavigateToString(zhtml.toStdWString().c_str());
}HRESULT MainWindow::cb_create_controller(HWND hWnd, HRESULT result,ICoreWebView2Controller *controller)
{if (!controller)return E_POINTER;m_controller = controller;wil::com_ptr<ICoreWebView2> webview;HRESULT ir = m_controller->get_CoreWebView2(&webview);if (FAILED(ir))return ir;ir = webview->QueryInterface(IID_ICoreWebView2_15, (void **)&m_webview);if (FAILED(ir))return ir;// Add a few settings for the webview// The demo step is redundant since the values are the default settingswil::com_ptr<ICoreWebView2Settings> settings;m_webview->get_Settings(&settings);settings->put_IsScriptEnabled(TRUE);settings->put_AreDefaultScriptDialogsEnabled(TRUE);settings->put_IsWebMessageEnabled(TRUE);// Resize WebView to fit the bounds of the parent windowRECT bounds;GetClientRect(hWnd, &bounds);m_controller->put_Bounds(bounds);m_webview->NavigateToString(L"Preparing...");// <NavigationEvents>// Step 4 - Navigation events// register an ICoreWebView2NavigationStartingEventHandler to cancel any non-https navigationEventRegistrationToken token;auto nav_func = std::bind(&MainWindow::on_navigate_started, this, std::placeholders::_1,std::placeholders::_2);auto nav_cb = Callback<ICoreWebView2NavigationStartingEventHandler>(nav_func);m_webview->add_NavigationStarting(nav_cb.Get(), &token);auto com_func = std::bind(&MainWindow::on_navigate_completed, this, std::placeholders::_1,std::placeholders::_2);auto com_cb = Callback<ICoreWebView2NavigationCompletedEventHandler>(com_func);m_webview->add_NavigationCompleted(com_cb.Get(), &token);// </NavigationEvents>// <Scripting>// Step 5 - Scripting// Schedule an async task to add initialization script that freezes the Object object// 注入脚本//webview->AddScriptToExecuteOnDocumentCreated(L"Object.freeze(Object);", nullptr);// Schedule an async task to get the document URLauto js_func = std::bind(&MainWindow::cb_execute_script, this, std::placeholders::_1,std::placeholders::_2);js_cb = Callback<ICoreWebView2ExecuteScriptCompletedHandler>(js_func);//webview->ExecuteScript(L"window.document.URL;", js_cb.Get());// </Scripting>// <CommunicationHostWeb>// Step 6 - Communication between host and web content// Set an event handler for the host to return received message back to the web contentauto msg_func = std::bind(&MainWindow::on_webmessage_received, this, std::placeholders::_1,std::placeholders::_2);msg_cb = Callback<ICoreWebView2WebMessageReceivedEventHandler>(msg_func);m_webview->add_WebMessageReceived(msg_cb.Get(), &token);// Schedule an async task to add initialization script that// 1) Add an listener to print message from the host// 2) Post document URL to the host// 注入脚本//webview->AddScriptToExecuteOnDocumentCreated(// L"window.chrome.webview.addEventListener(\'message\', event => alert(event.data));" \// L"window.chrome.webview.postMessage(window.document.URL);",// nullptr);// </CommunicationHostWeb>m_task = QThread::create(&MainWindow::task_run, this);m_task->setParent(this);m_task->start();return S_OK;
}void MainWindow::load_webview2(HWND hWnd)
{MainWindow *obj = this;auto func = &MainWindow::cb_create_environment;auto fn = [hWnd, obj, func](HRESULT result, ICoreWebView2Environment * env)->HRESULT{return (obj->*func)(hWnd, result, env);};auto cb = Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(fn);QDir d(QStandardPaths::writableLocation(QStandardPaths::TempLocation));auto ztemp = d.absoluteFilePath(PROFILE_DATA).toStdWString();HRESULT ir = CreateCoreWebView2EnvironmentWithOptions(nullptr, ztemp.c_str(), nullptr, cb.Get());if (FAILED(ir)){qCritical() << "create webview2 failed. code: " << ir;QTimer::singleShot(3000, [](){QApplication::quit();_Exit(1);});QMessageBox::warning(this,windowTitle(),u8"严重错误。程序即将退出。\n""请检查Microsoft Edge WebView2 Runtime是否存在。\n");}
}void MainWindow::task_run()
{if (!m_controller || !m_webview)return;m_brunning = true;while (m_brunning){emit on_prepare();QThread::sleep(3);if (!m_brunning)break;emit load_auth_page();QThread::sleep(10);if (!m_brunning)break;emit put_name();QThread::sleep(3);if (!m_brunning)break;emit put_password();QThread::sleep(3);if (!m_brunning)break;emit click_login();for (int i = 0; i < 10; i++){QThread::sleep(60);if (!m_brunning)break;emit wait(i + 1);}}
}HRESULT MainWindow::cb_create_environment(HWND hWnd, HRESULT result, ICoreWebView2Environment *env)
{MainWindow *obj = this;auto func = &MainWindow::cb_create_controller;auto fn = [hWnd, obj, func](HRESULT result, ICoreWebView2Controller * controller)->HRESULT{return (obj->*func)(hWnd, result, controller);};// Create a CoreWebView2Controller and get the associated CoreWebView2 whose parent is the main window hWndauto cb = Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(fn);HRESULT hr = env->CreateCoreWebView2Controller(hWnd, cb.Get());return hr;
}
免责声明
此代码仅供技术研究娱乐之用,禁止用于商业用途,否则一切后果自负。
作者:岬淢箫声
岬淢箫声的博客_CSDN博客-C/C++,MFC/VC,桌面H5领域博主https://caowei.blog.csdn.net/
转载请注明来源
相关文章:
Qt系列:调用Edge浏览器示例
背景 需要解决以下几个问题 政府项目新浏览器兼容老系统ActiveX控件,Qt WebEngineView没有直接的实现方案,需要利用Qt的ActiveX兼容模块与浏览器往返多次交互Qt ActiveX未实现COM事件通知官方Win32示例存在滥用lambda函数的嫌疑,lambda函数…...
内推|香港外企急招ETL工程师!数据分析师+Python开发+运营专家
2月已过半还在找工作?快来看看有没有适合你的岗位!01公司:友邦科技 工作地点:成都市高新区OCG国际中心招聘岗位:ETL工程师 15-18k该岗位为香港项目,需要有数仓或者大数据经验。本科IT或数据相关专业&#…...
zlib压缩原理
数据压缩的本质 去除数据中的冗余信息,对于ABABABABABABAB字样的字符串,AB出现了7次,占用14个字节,如果将该字符串编码为7AB,只占用3个字节。 为什么需要对数据压缩 数据需要存储或者传输,为了节省磁盘空…...
论文阅读笔记《DEEP GRAPH MATCHING CONSENSUS》
核心思想 本文提出一种基于图神经网络的图匹配方法,首先利用节点相似度构建初始的匹配关系,然后利用局部的一致性对初始的匹配关系进行迭代优化,不断筛除误匹配点,得到最终的匹配结果。本文还提出几种措施来降低计算复杂度&#x…...
华为OD机试题 - 开放日活动(JavaScript)
最近更新的博客 2023新华为OD机试题 - 斗地主(JavaScript)2023新华为OD机试题 - 箱子之形摆放(JavaScript)2023新华为OD机试题 - 考古学家(JavaScript)2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)2023新华为OD机试题 - 最多等和不相交连续子序列(JavaScri…...
(考研湖科大教书匠计算机网络)第四章网络层-第八节:网际控制报文协议ICMP
获取pdf:密码7281专栏目录首页:【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一:网际控制报文协议ICMP(1)ICMP差错报告报文A:终点不可达B:源点抑制C:时间超过Dÿ…...
华为OD机试 - GPU 调度 | 备考思路,刷题要点,答疑 【新解法】
最近更新的博客 【新解法】华为OD机试 - 关联子串 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 停车场最大距离 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 任务调度 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试…...
华为OD机试题 - 任务总执行时长(JavaScript)
最近更新的博客 2023新华为OD机试题 - 斗地主(JavaScript)2023新华为OD机试题 - 箱子之形摆放(JavaScript)2023新华为OD机试题 - 考古学家(JavaScript)2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)2023新华为OD机试题 - 最多等和不相交连续子序列(JavaScri…...
还在想假期去哪玩?直接做一个旅游攻略小程序
憋了几年好不容易解封准备出去散散心,但看着大江南北这么多景点是不是有点让你选择强迫症呢?那就先制作一个旅游攻略小程序看看驴友们的分享吧。...
十四、vue3项目如何使用three.js
近期在开发过程中,因为项目已经接近尾声,就需要对项目中的数据进行整合,而数据看板不失为一个比较直观的展现形式。在数据看板中3D的展现形式是比较流行的展现形式,那么如何在项目引入一个大的场景,并且能够和后台发生…...
python 向excel表中添加新的sheet页或者向旧sheet中写入数据
import xlwt import xlrd from xlutils.copy import copy import os import numpy as np import pandas as pd class Excel_Add_Sheet():def save_table(self, table, file_name):# 保存表table.save(file_name)def add_new_sheet(self, file_name, sheet_name, titleNone):&q…...
RPC-grpc实践
参考:https://developer.aliyun.com/article/1152352?spma2c6h.12873639.article-detail.33.344f6446zEnbRi&scm20140722.ID_communityarticle1152352._.ID_communityarticle1152352-OR_rec-V_1 参考:https://onejson.blog.csdn.net/article/detai…...
JavaEE——MyBatis配置文件的详细介绍
简单介绍: 需要我们编写的配置文件主要有三个,分别是核心配置文件(mybatis-config.xml),数据库连接信息文件(db.properties),SQL语句映射文件(Mappers)&…...
bwmarrin/snowflake生成ID重复问题排查记录
现象 某日,运营反馈,在某个时间区间丢失了一段日志,让看看是什么问题。 排查 查看项目日志有无错误 发现项目日志有报错信息Error 1062 Duplicate entry 149059529550598144 for key PRIMARY,很显然,问题在此,数据库…...
操作系统题目收录(十)
1、在存储管理中,采用覆盖与交换技术的目的是()。 A:节省主存空间B:物理上扩充主存容量C:提高CPU效率D:实现主存共享 解析 覆盖和交换的提出就是为了解决主存空间不足的问题,但不…...
IOS 自动化测试环境搭建
购买MacPDD 比TB JD 便宜500,下单安装homebrew/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"安装npm cnpmbrew install node; npm install -g cnpm --registryhttps://registry.npm.taobao.org;安装类似Andro…...
系统设计原则
系统设计原则 好的系统是迭代出来的。先解决核心问题,预测未来可能出现的问题,对现有的问题有方案,对未来的问题有预案。不是一上来就按1亿用户量设计,也不要过度复杂化系统。 业务千变万化,技术层出不穷,…...
推荐130个网站,非常实用,比涨工资都重要
搞学习 TED(最优质的演讲):https://www.ted.com/ 谷粉学术:https://gfsoso.99lb.net/scholar.html 大学资源网:http://www.dxzy163.com/ 简答题:http://www.jiandati.com/ 网易公开课:https…...
手机棋牌游戏开发的流程是怎样的?
最近几年,随着网络游戏的兴起,棋牌手游开发也越来越受欢迎,在国内,几乎随处可见从事手游和手游的公司。不过,虽然公司和产品很多,但效果也不一样,区别就在于,他们能不能掌握好这款游…...
浅谈C++函数重载
C相较于C语言来说,重载是一重大特性,让我们一起简单的回顾一下重载那些事 传送门函数重载是什么为什么有函数重载函数重载是如何实现的总结函数重载是什么 函数重载:是函数的一种特殊情况,C允许在同一作用域中声明几个功能相似的同名函数 这些同名函数的形参列表(参数个数or类…...
数据分析spss应急考试
数据分析spss应急考试 前言 单项选择 15(项)*2(分)30 判断题 10*1 10 计算题 2*10 案例分析题目(考实验内容) 总四十分,分值不等 老师重点强调了回归分析因子分析方差分析参数、非参数检验 2独立样本的非参数检验应该用什么方法多独立样本…...
Handler postDelayed的实现原理
Handler postDelayed的实现原理 问题描述 Handler.postDelayed()的原理是如何保证延时执行的? 扩展:这样实现的好处是什么? 题目分析 猜测一下 以我们对Handler的了解,内部使用了Looper对消息队列进行循环获取执行࿰…...
【数据结构】平衡二叉树
目录 一、平衡二叉树的介绍 二、平衡二叉树的插入 1、平衡二叉树的插入步骤 2、平衡二叉树的旋转 2.1左单旋 2.2右单旋 2.3左右双旋 2.4右左双旋 三、平衡二叉树的删除(略) 四、个人对平衡二叉树见解 五、平衡二叉树整体代码 一、平衡二叉树的…...
Minecraft服务端配置
✨✨前言 ✨✨ 我的世界大家肯定都不陌生,在网易拿下中国区的代理后,很多小伙伴也是都转向了网易版我的世界,网易版我的世界可以说已经做是的十分全面了,使用起来也十分方便,一部分小伙伴也是看重了网易庞大的玩家数量…...
yunUI组件库解析:图片上传与排序组件yImgPro
yunUI是笔者开源的微信小程序功能库。目前其中包含了一些复杂的功能组件。方便使用。未来它将分为组件、样式、js三者合为一体,但分别提供。 本文所用代码皆来源于组件库中的yImgPro组件。详细代码可至github查看。地址: yunUI 。 npm地址:yu…...
Java基础:回调函数
因为在看Android代码的时候发现了许多关于回调函数的知识, 所以去了解了一下. 对于我来说不太好懂, 因为我觉得看的那些博文的讲法对我来说很绕, 所以我在理解了之后想写一篇关于回调函数的博文来给和我一样理解能力稍差的人一点帮助. 回调函数的作用其实就是将需要这个功能的调…...
Springboot多环境配置
此文章是根据黑马程序员课程所做的笔记课程视频 多环境开发 什么是多环境?其实就是说你的电脑上写的程序最终要放到别人的服务器上去运行。每个计算机环境不一样,这就是多环境。常见的多环境开发主要兼顾3种环境设置,开发环境——自己用的…...
Java Number Math 类,超详细整理,适合新手入门
目录 一、什么是Java Number类? 二、Java Number类提供了哪些基本的数字操作? 三、什么是包装类? 所有的包装类都是抽象类 Number 的子类。 四、什么是Java Math 类 Test类案例:(Math.PI 表示一个圆的周长与直径…...
俯瞰·明统系列·落霞与孤鹜齐飞、南征与北伐并举
尽江南百万兵,腰间宝剑血尤腥。 引言 元至正二十七年(1367年)四月,吴王朱元璋命中书右丞相徐达为征虏大将军、平章常遇春为副将军,率军25万由淮入河、北进中原(第一次北伐)。北伐中发布告北方官…...
Nodejs环境搭建和配置
Nodejs环境的搭建和配置 1、下载 官网:http://nodejs.cn/download/,选择windows64位 msi文件 2、安装和配置环境 双击安装之后,配置环境变量: ①系统变量那边创建NODE_PATH变量,值为nodejs文件夹的node_modules文…...
连云港营销型网站建设/前端seo优化
Chapter27:参数方程和极坐标27.参数方程和极坐标27.1 参数方程27.1.1 参数方程的导数27.1.2 参数定义的曲线长度27.1.3 参数化曲线的旋转体表面积27.2 极坐标27.2.1 极坐标与笛卡尔坐标互换27.2.2 极坐标中画曲线常见的极坐标曲线27.2.3 求极坐标曲线的切线27.2.4 求…...
外部网站可以做链接到淘宝吗/磁力狗bt
想要寻找一款各功能强大,使用简便的看图工具?一定不要错过这篇文章,小编精选了5款综合性非常高的软件分给大家,颜值和功能性都经得住吊打的那种,话不多说来看文字介绍吧~ macOS上简便好用的看图软件分享 XnViewMP fo…...
成都网站优化维护/网络舆情管理
2019 年阿里巴巴 双11 核心系统 100% 以云原生的方式上云,完美支撑了 54.4w 峰值流量以及 2684 亿的成交量。随着阿里巴巴经济体云原生技术的全面升级,容器性能、稳定性及在线率也得到了全面提升。本文作者将从云计算时代容器的发展路径为出发点…...
苏南建设集团网站/优化设计单元测试卷答案
摘要 本篇经验将和大家介绍Windows下安装和部署RabbitMQ消息队列服务器,希望对大家的工作和学习有所帮助! 目录 一、Erlang语言环境的搭建 二、RabbitMQ服务环境的搭建 三、RabbitMQ服务Web管理工具 一、Erlang语言环境的搭建 RabbitMQ开源消息队列服务是…...
企业网站首页设计评价/开封网站推广
神经网络实践心得1.关于神经网络层数2.关于隐藏层神经元个数3.关于优化器optimizer4.关于Mini-batch SGD5.关于hard-mining6.关于loss函数7.数据归一化与BN参考文献实践过程主要参考了此篇博客:The Number of Hidden Layersl。 1.关于神经网络层数 隐藏层先选择1层…...
如何做内部优惠券网站/网页制作源代码
hadoop distcp -i hdfs://192.168.10.211:9000/fileinfo hdfs://192.168.24.46:9000/fileinfo distcp [OPTIONS] <srcurl>* <desturl> -i Ignore failures 转载于:https://www.cnblogs.com/yanghuahui/p/3490713.html...