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

chrom扩展开发配合百度图像文字识别实现自动登录(后端.net core web api)

好久没做浏览器插件开发了,因为公司堡垒机,每次登录都要输入账号密码和验证码。太浪费时间了,就想着做一个右键菜单形式的扩展。

实现思路也很简单,在这里做下记录,方便下次开发参考。

一,先来了解下chrome扩展开发,必备文件。

manifest.json也叫清单文件。
先简单看下配置:

 //需要做C#兼职  或者浏览器插件兼职的请加我QQ:3388486286
{"manifest_version": 2,"name": "堡垒机自动化","version": "1.0","description": "右键菜单跳转到堡垒机页面,并自动登录","permissions": ["tabs", "contextMenus","webRequest","webRequestBlocking","https://127.0.0.4/*","http://127.0.0.4/*"],"background": {"scripts": ["background.js"]},"content_scripts": [{"matches": ["https://127.0.0.4/*","http://127.0.0.4/*"],"js": ["JS/log.js"]}],"web_accessible_resources": ["JS/config.json"],"icons": {"16": "Images/icon.png","48": "Images/icon.png","128": "Images/icon.png"}}

上述配置基本包含了插件开发的常用配置。现在简单介绍下每个配置的作用:

1.manifest_version :也就是版本的意思,你需要使用的插件版本,不过现在已经是第三版了,因为之前用过2开发,2和3的语法有差别,估本版本还是用到老版本的语法。新版本没时间去研究,反正都能用。

2.name :插件名称(自定义)

3.version : 当前插件的版本(自定义)

4.description : 插件描述

5.permissions :权限(你需要使用哪些API就需要对应的开通权限,也叫注册服务吧)

 "tabs", (该权限可以打开新的页面)
"contextMenus",(该权限可以右键创建新的菜单)
"webRequest",(该权限可以监听网络请求)
"webRequestBlocking",(该权限可以监听网络请求并且修改请求)
"https://127.0.0.4/*",(表示插件需要访问以 HTTPS 协议开头、IP 地址为 127.0.0.4 的所有页面或资源。这意味着插件将被允许在浏览器中与这些特定的 IP 地址和相关页面进行通信,无论是通过 HTTP 还是 HTTPS 访问。)
"http://127.0.0.4/*"(表示插件需要访问以 HTTP 协议开头、IP 地址为 127.0.0.4 的所有页面或资源。)
添加对应的地址作用:这意味着插件将被允许在浏览器中与这些特定的 IP 地址和相关页面进行通信,无论是通过 HTTP 还是 HTTPS 访问。
  1. "background":
    { "scripts": ["background.js"] }该脚本会一直运行监听。

具体含义如下:

"background":表示指定插件的后台脚本。
"scripts":表示指定后台脚本文件的路径。
"background.js":表示插件的后台页面脚本文件名为 "background.js"。
通过将脚本文件名添加到 "scripts" 数组中,你可以告诉浏览器插件在加载时要运行哪个脚本文件作为后台页面。这个后台页面脚本通常用于处理插件的核心功能、与浏览器 API 进行交互以及响应来自其他插件部分(如内容脚本或浏览器操作栏)的事件。

7.content_scripts

 //content_scripts  为业务JS注入,就是你要操作前端页面元素的JS  其中matches表示你JS要注入到哪些页面地址。"content_scripts": [{"matches": ["https://127.0.0.4/*","http://127.0.0.4/*"],"js": ["JS/log.js"]   //需要注入的Js文件}]

8.web_accessible_resources:这里面往往放些静态全局的配置文件。
9.icons:图标文件。

二 、先说下background.js的思路。

1.先注册右键菜单,这样你右键浏览器,就可以看到自己的扩展程序了。

chrome.contextMenus.create({title:"堡垒机自动化",onclick:function(){console.log('准备跳转..')//跳转指定页面chrome.tabs.create({url:'https://127.0.0.4/index.php/login'},(tab)=>{console.log('跳转成功..')console.log(tab)//执行业务代码 注入JSchrome.tabs.executeScript(tab.id,{ file: 'JS/content_script.js'})})}})

其中executeScript也是注入JS的一种方式,这种方式比较灵活,这种注入方式也可以和页面元素进行交互。

2.跳转到指定页面后,我们需要输入账号和密码,这块业务逻辑就写在content_script.js


var credentials = {};// 读取配置文件并存储到全局对象
async function getConfig() {try {const response = await fetch(chrome.runtime.getURL('JS/config.json'));credentials = await response.json();console.log(credentials); // 打印全局对象// 调用填充函数fillCredentials();} catch (error) {console.error('Error reading config file:', error);}
} // 在页面上填充账号和密码
function fillCredentials() {document.querySelector("#pwd_username").value = credentials.username;document.querySelector("#pwd_pwd").value = credentials.password;//GetAccessToken();}

这里我们调用下getConfig()方法,进行配置文件读取,然后赋值给全局变量存储。,然后调用fillCredentials()进行账号密码赋值。

3.验证码识别,并赋值登录。
我们验证码就是一个4位字母图片,这块逻辑我是直接调用百度API实现的,本来想着自己后端实现,但是用了下第三方库,要么响应时间太久了,要么就是识别不准确。百度API直接帮你解决了这2个麻烦。但是要收费,我只用了100次的免费体验。
现在说下具体实现思路吧,本来想着直接前端发送请求识别,但是浏览器有同源策略,跨域了…这个最终还是要用到后端服务,于是就用了后端API去做图片识别功能了。

3.1先获取验证码图片的url地址。
这里我们在background.js中添加网络监听,因为图片url有固定格式,很好匹配。具体代码如下:

// 声明一个变量用于保存监听器
let requestListener;
// 启动网络请求监听器requestListener = function(details) {// 检查请求地址是否以指定的 URL 开头if (details.url.startsWith('https://127.0.0.4/captcha/')) {// 提取图片地址const imageUrl = details.url;// 输出图片地址console.log('图片地址:', imageUrl);// 在这里可以进行进一步的处理sendImageURLToContentScript(imageUrl);}}chrome.webRequest.onBeforeRequest.addListener(requestListener,{ urls: ['https://127.0.0.4/captcha/*'] }, // 监听以指定 URL 开头的请求['blocking']);

通过 chrome.webRequest.onBeforeRequest.addListener开启网络监听,当匹配到指定url开头的信息后,就代表该url是图片url,然后把imageUrl传给content_script.js
这里声明下:
background.js是不能直接和操作的页面通信的,background.js主要操作浏览器提供的API。实际操作Dom元素需要通过业务JS去操作。这里的业务JS就是content_script.js
那么background.jscontent_script.js如何通信呢,看代码:

 // 在background.js中获取到图片地址后,延迟1秒发送消息给业务 JSfunction sendImageURLToContentScript(imageUrl) {chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {if (tabs.length > 0) {const tabId = tabs[0].id;setTimeout(function() {chrome.tabs.sendMessage(tabId, { imageUrl: imageUrl }, function(response) {// 在收到业务 JS 的响应后进行处理(可选)console.log('收到业务 JS 的响应:', response);});}, 500); // 延迟1秒后发送消息}});}

通过 chrome.tabs.sendMessage 发送消息。

// 业务 JS 接收消息,并进行处理
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {// 接收到来自 background.js 的消息if (request.imageUrl) {const imageUrl = request.imageUrl;// 在这里进行业务逻辑处理,使用获取到的图片地址console.log('收到来自 background.js 的图片地址:', imageUrl);GetCode(imageUrl);//GetBase64(imageUrl);// 可以通过 sendResponse 向 background.js 发送响应消息(可选)sendResponse({ message: '已收到图片地址' });}});

通过chrome.runtime.onMessage.addListener接收消息
这样就实现了background.jscontent_script.js的通信。
至于为什么要延迟500毫秒再发送,是因为我们点击右键后,content_script.js才注入到页面,而再这时候,background.js已经再运行了。所有延迟会再发送消息,这样可以避免content_script.js那边接收不到消息。

3.2业务JS发送imageUrl给后端api进行图像验证码识别

 function GetCode(imageUrl){fetch(credentials.getcode_url, {method: "POST",headers: {"Content-Type": "application/json"},body: JSON.stringify(imageUrl)}).then(response => response.text()).then(result => {let data = JSON.parse(result);// 获取 words_result 字段的值  let wordsResult = data.words_result;// 获取数组中第一个元素的 words 字段的值let words = wordsResult[0].words;console.log(words);  // 输出: "code"//赋值codedocument.querySelector("#pwd_captcha").value = words;//点击登录document.querySelector("#sign-box > form.form-vertical.login-content.active > div.submit-row > button").click();}).catch(error => {console.error("请求出错:", error);});}

好了这样就实现了验证码识别,然后赋值登录操作呢。

三、给出所有相关代码

config.json:

{"username": "username","password": "password","client_id":"FrktGAjFVjGv9SSA6S3","client_secret":"IFL6FbU6tuFrPoCjaYnvvRrCGd","token_url":"https://aip.baidubce.com/oauth/2.0/token","getcode_url":"http://localhost:5270/api/CodeIdentity"
}

background.js


// 声明一个变量用于保存监听器
let requestListener;
// 启动网络请求监听器requestListener = function(details) {// 检查请求地址是否以指定的 URL 开头if (details.url.startsWith('https://127.0.0.4/captcha/')) {// 提取图片地址const imageUrl = details.url;// 输出图片地址console.log('图片地址:', imageUrl);// 在这里可以进行进一步的处理sendImageURLToContentScript(imageUrl);}}chrome.webRequest.onBeforeRequest.addListener(requestListener,{ urls: ['https://127.0.0.4/captcha/*'] }, // 监听以指定 URL 开头的请求['blocking']);// 在background.js中获取到图片地址后,延迟1秒发送消息给业务 JSfunction sendImageURLToContentScript(imageUrl) {chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {if (tabs.length > 0) {const tabId = tabs[0].id;setTimeout(function() {chrome.tabs.sendMessage(tabId, { imageUrl: imageUrl }, function(response) {// 在收到业务 JS 的响应后进行处理(可选)console.log('收到业务 JS 的响应:', response);});}, 500); // 延迟1秒后发送消息}});}chrome.contextMenus.create({title:"堡垒机自动化",onclick:function(){console.log('准备跳转..')//跳转指定页面chrome.tabs.create({url:'https://127.0.0.4/index.php/login'},(tab)=>{console.log('跳转成功..')console.log(tab)//执行业务代码 注入JSchrome.tabs.executeScript(tab.id,{ file: 'JS/content_script.js'})})}})// // 启动网络请求监听器
// chrome.webRequest.onBeforeRequest.addListener(
//     function(details) {
//       // 检查请求地址是否以指定的 URL 开头
//       if (details.url.startsWith('https://127.0.0.4/captcha/')) {
//         // 提取图片地址
//         const imageUrl = details.url;//         // 输出图片地址
//         console.log('图片地址:', imageUrl);//         // 在这里可以进行进一步的处理
//         sendImageURLToContentScript(imageUrl);
//       }
//     },
//     { urls: ['https://127.0.0.4/captcha/*'] }, // 监听以指定 URL 开头的请求
//     ['blocking']
//   );// 在background.js中获取到图片地址后,延迟1秒发送消息给业务 JS
// function sendImageURLToContentScript(imageUrl) {
//     chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
//       if (tabs.length > 0) {
//         const tabId = tabs[0].id;//         setTimeout(function() {
//           chrome.tabs.sendMessage(tabId, { imageUrl: imageUrl }, function(response) {
//             // 在收到业务 JS 的响应后进行处理(可选)
//             console.log('收到业务 JS 的响应:', response);
//                  // 移除监听器
//         chrome.webRequest.onBeforeRequest.removeListener(requestListener);
//           });
//         }, 100); // 延迟1秒后发送消息
//       }
//     });
//   }// 开始监听网络请求
//startRequestListener();

content_script.js

// 业务 JS 接收消息,并进行处理
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {// 接收到来自 background.js 的消息if (request.imageUrl) {const imageUrl = request.imageUrl;// 在这里进行业务逻辑处理,使用获取到的图片地址console.log('收到来自 background.js 的图片地址:', imageUrl);GetCode(imageUrl);//GetBase64(imageUrl);// 可以通过 sendResponse 向 background.js 发送响应消息(可选)sendResponse({ message: '已收到图片地址' });}});var credentials = {};// 读取配置文件并存储到全局对象
async function getConfig() {try {const response = await fetch(chrome.runtime.getURL('JS/config.json'));credentials = await response.json();console.log(credentials); // 打印全局对象// 调用填充函数fillCredentials();} catch (error) {console.error('Error reading config file:', error);}
} // 在页面上填充账号和密码
function fillCredentials() {document.querySelector("#pwd_username").value = credentials.username;document.querySelector("#pwd_pwd").value = credentials.password;//GetAccessToken();}/*** 使用 AK,SK 生成鉴权签名(Access Token)* @returns 鉴权签名信息(Access Token)*/
//  function GetAccessToken() {
//     const url = credentials.token_url;
//     const data = {
//       grant_type: 'client_credentials',
//       client_id: credentials.client_id,
//       client_secret: credentials.client_secret
//     };//     const requestOptions = {
//       method: 'POST',
//       mode: 'cors',
//       headers: { 'Content-Type': 'application/json' },
//       body: JSON.stringify(data)
//     };//     return fetch(url, requestOptions)
//       .then(response => {
//         if (!response.ok) {
//           throw new Error('Network response was not ok');
//         }
//         return response.json();
//       })
//       .then(data => {
//         console.log(data);
//         console.log(data.access_token);
//         return data.access_token;
//       })
//       .catch(error => {
//         console.error(error);
//       });
//   }function GetCode(imageUrl){fetch(credentials.getcode_url, {method: "POST",headers: {"Content-Type": "application/json"},body: JSON.stringify(imageUrl)}).then(response => response.text()).then(result => {let data = JSON.parse(result);// 获取 words_result 字段的值  let wordsResult = data.words_result;// 获取数组中第一个元素的 words 字段的值let words = wordsResult[0].words;console.log(words);  // 输出: "code"//赋值codedocument.querySelector("#pwd_captcha").value = words;//点击登录// document.querySelector("#sign-box > form.form-vertical.login-content.active > div.submit-row > button").click();}).catch(error => {console.error("请求出错:", error);});}//图片转base64
//   function getFileContentAsBase64(path) {
//     return new Promise((resolve, reject) => {
//       fetch(path)
//         .then(response => response.arrayBuffer())
//         .then(buffer => {
//           const bytes = new Uint8Array(buffer);
//           let binary = '';
//           for (let i = 0; i < bytes.byteLength; i++) {
//             binary += String.fromCharCode(bytes[i]);
//           }
//           const base64 = btoa(binary);
//           resolve(base64);
//         })
//         .catch(error => reject(error));
//     });
//   }// function GetBase64(captchaUrl)
// {
// // 使用fetch函数获取验证码图片的二进制数据
// fetch(captchaUrl)
//   .then(response => response.blob())
//   .then(blob => {
//     // 创建一个FileReader对象来读取blob数据
//     const reader = new FileReader();
//     reader.onloadend = function() {
//       // 读取完成后,将二进制数据转换为Base64编码
//       const base64 = reader.result.split(',')[1];//       // 调用getFileContentAsBase64方法进行后续处理
//       getFileContentAsBase64(base64)
//         .then(result => {
//           console.log("base64:",result);
//         })
//         .catch(error => {
//           console.error(error);
//         });
//     };
//     reader.readAsDataURL(blob);
//   })
//   .catch(error => {
//     console.error(error);
//   });// }//识别验证码// 获取配置并存储到全局对象
getConfig();

后端代码:

using CodeIdentify.Servers;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IBaiDuCodeIdentity, BaiDuCodeIdentityRepostoty>();
builder.Services.AddCors(options => {options.AddPolicy("AllowAll", builder =>{builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();});
});var app = builder.Build();app.UseCors("AllowAll");
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseAuthorization();app.MapControllers();app.Run();
namespace CodeIdentify.Servers
{public interface IBaiDuCodeIdentity{Task<string> GetAccessTokenAsync();Task<string> GetCodeAsync(string base64);Task DownloadImageAsync(string url , string saveDirectory);string GetFileContentAsBase64(string path);void DeleteImage(string path);}
}
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using RestSharp;
using System.Net;namespace CodeIdentify.Servers
{public class BaiDuCodeIdentityRepostoty : IBaiDuCodeIdentity{public void DeleteImage(string path){try{// 获取指定文件夹中的所有图片文件string[] imageFiles = Directory.GetFiles(path, "*.jpg");foreach (string file in imageFiles){// 删除文件File.Delete(file);Console.WriteLine($"已删除文件: {file}");}Console.WriteLine("所有图片文件已删除。");}catch (Exception ex){throw new Exception(ex.Message);Console.WriteLine($"删除图片文件时出错:{ex.Message}");}}public async Task DownloadImageAsync(string imageUrl, string saveDirectory){// 创建自定义的 HttpClientHandler,并禁用证书验证var handler = new HttpClientHandler(){ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true};// 创建 HttpClient 实例,并使用自定义的 HttpClientHandlerusing (HttpClient httpClient = new HttpClient(handler)){try{// 发送 GET 请求并获取响应消息HttpResponseMessage response = await httpClient.GetAsync(imageUrl);response.EnsureSuccessStatusCode();// 从响应消息中获取图片内容byte[] imageBytes = await response.Content.ReadAsByteArrayAsync();// 创建文件保存路径Directory.CreateDirectory(saveDirectory);string savePath = Path.Combine(saveDirectory, "image.jpg"); // 要保存的文件名// 将图片内容保存到本地文件File.WriteAllBytes(savePath, imageBytes);Console.WriteLine("图片下载完成。");}catch (Exception ex){throw new  Exception($"图片下载失败:{ex.Message}");Console.WriteLine($"图片下载失败:{ex.Message}");}}}public async Task<string> GetAccessTokenAsync(){try{var client = new RestClient($"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=FrktGAjFVjSSA6S3Tcs0f&client_secret=IFL6FbU6rPoCjaSiKjMLYnvvRrCGd");var request = new RestRequest(String.Empty, Method.Post);request.AddHeader("Content-Type", "application/json");request.AddHeader("Accept", "application/json");var body = @"";request.AddParameter("application/json", body, ParameterType.RequestBody);var response = await client.ExecuteAsync(request);var result = JsonConvert.DeserializeObject<dynamic>(response.Content??"");Console.WriteLine(result?.access_token.ToString());return result?.access_token.ToString()??"";}catch (Exception e){throw new Exception($"可能次数用完了:{e.Message}");}}public async Task<string> GetCodeAsync(string base64){var token = await GetAccessTokenAsync();var client = new RestClient($"https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token={token}");var request = new RestRequest(String.Empty, Method.Post);request.AddHeader("Content-Type", "application/x-www-form-urlencoded");request.AddHeader("Accept", "application/json");// image 可以通过 GetFileBase64Content('C:\fakepath\captcha.png') 方法获取request.AddParameter("image", base64);var  response = await client.ExecuteAsync(request);Console.WriteLine(response.Content);return response.Content??"";}public string GetFileContentAsBase64(string path){using (FileStream filestream = new FileStream(path, FileMode.Open)){byte[] arr = new byte[filestream.Length];filestream.Read(arr, 0, (int)filestream.Length);string base64 = Convert.ToBase64String(arr);return base64;}}}
}
using CodeIdentify.Servers;
using Microsoft.AspNetCore.Mvc;namespace CodeIdentify.Controllers
{[Route("api/[controller]")][ApiController]public class CodeIdentityController : ControllerBase{private readonly IBaiDuCodeIdentity _baiDuCodeIdentity;public CodeIdentityController(IBaiDuCodeIdentity baiDuCodeIdentity) {_baiDuCodeIdentity = baiDuCodeIdentity;}[HttpPost]public async Task<IActionResult> GetCode([FromBody] string url) {string path = "Images\\image.jpg";string deletepath = "Images";await _baiDuCodeIdentity.DownloadImageAsync(url, "Images");string code = await _baiDuCodeIdentity.GetCodeAsync(_baiDuCodeIdentity.GetFileContentAsBase64(path));if(string.IsNullOrWhiteSpace(code)) return BadRequest("空字符串,识别有误");_baiDuCodeIdentity.DeleteImage(deletepath);return Ok(code);} }
}

相关文章:

chrom扩展开发配合百度图像文字识别实现自动登录(后端.net core web api)

好久没做浏览器插件开发了&#xff0c;因为公司堡垒机&#xff0c;每次登录都要输入账号密码和验证码。太浪费时间了&#xff0c;就想着做一个右键菜单形式的扩展。 实现思路也很简单&#xff0c;在这里做下记录&#xff0c;方便下次开发参考。 一&#xff0c;先来了解下chro…...

香港服务器怎么打开SSH

​  SSH是一种远程登录协议&#xff0c;可以通过加密方式在网络上安全地传输数据。它允许用户在远程服务器上执行命令&#xff0c;管理文件和目录&#xff0c;并进行其他系统管理任务。 如何打开SSH服务? 1.确认已安装OpenSSH服务器&#xff1a; 你可以通过命令sudoapt-geti…...

【LeetCode】437.路径总和Ⅲ

题目 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节…...

Mybatis-plus中操作JSON字段

1.实体类上要加上自动映射 TableName(value "school", autoResultMap true)2.json字段上加上json处理器 TableField(value "cover_url", typeHandler JacksonTypeHandler.class)private List<String> cover_url;参考博客 http://www.dedeyun.co…...

第十五课、Windows 下打包发布 Qt 应用程序

功能描述&#xff1a;讲解了 Windows 下打包发布 Qt 应用程序的三种方法&#xff0c;并对比优缺点 一、利用 windepolyqt 工具打包发布 Qt 提供了一个 windeployqt 工具来自动创建可部署的文件夹。 打包发布流程&#xff1a; 1. 新建一个文件夹&#xff0c;将编译后的可执行…...

【php】windows下php运行已有php web项目环境配置教程

php环境配置教程 php安装composer安装扩展安装redis扩展安装 composer install 本文操作系统使用的是win11&#xff0c;软件PhpStorm 2023.1 php安装 要安装的php版本可以在composer.json看到&#xff0c;下载安装对应版本 windows下载地址https://windows.php.net/download …...

【mybatis】 mybatis在mysql 更新update 操作 更新时间字段按照年月日时分秒格式 更新为当前时间...

参考链接 【mybatis】 mybatis在mysql 更新update 操作 更新时间字段按照年月日时分秒格式 更新为当前时间…...

C++动态规划经典案例解析之合并石子

1. 前言 区间类型问题&#xff0c;指求一个数列中某一段区间的值&#xff0c;包括求和、最值等简单或复杂问题。此类问题也适用于动态规划思想。 如前缀和就是极简单的区间问题。如有如下数组&#xff1a; int nums[]{3,1,7,9,12,78,32,5,10,11,21,32,45,22}现给定区间信息[…...

go MongoDB

安装 go get go.mongodb.org/mongo-driver/mongo package mongodbexampleimport ("context""fmt""ginapi/structs""time""go.mongodb.org/mongo-driver/bson""go.mongodb.org/mongo-driver/bson/primitive""…...

算法与数据结构(八)--优先队列

普通的队列是一种先进先出的数据结构&#xff0c;元素在队列尾追加&#xff0c;而从队列头删除&#xff0c;在某些情况下&#xff0c;我们可能需要找出队列中的最大值或者最小值。 例如使用一个队列保存计算机的任务&#xff0c;一般情况下计算机的任务都是有优先级的&#xff…...

React 全栈体系(三)

第二章 React面向组件编程 四、组件三大核心属性3: refs与事件处理 1. 效果 需求: 自定义组件, 功能说明如下: 点击按钮, 提示第一个输入框中的值当第2个输入框失去焦点时, 提示这个输入框中的值 2. 理解 组件内的标签可以定义ref属性来标识自己 3. 编码 3.1 字符串形式…...

腾讯云下一代CDN -- EdgeOne加速MinIO对象存储

省流 使用MinIO作为EdgeOne的源站。 背景介绍 项目中需要一个兼容S3协议的对象存储服务&#xff0c;腾讯云的COS虽然也兼容S3协议&#xff0c;但是也只是支持简单的上传下载&#xff0c;对于上传的时候同时打标签这种需求&#xff0c;就不兼容S3了。所以决定自建一个对象存储…...

GitLab-CI 指南

GitLab CI 指南 前置工作 部署GitLab 部署GitLab-Runner 注册Runner到GitLab docker exec -it gitlab-runner bash # 进入容器 gitlab-runner register #调用register命令开始注册 # 在Gitlab Setting中找到Runners,如下图所示Enter the GitLab instance URL (for example, …...

MyBatis的核心技术掌握,简单易懂(上)

目录 一.MyBatis中的动态SQL 二.MyBatis中的模糊查询 1. # 符号 2. $ 符号 ---问题 ---所以大家知道 # 和 $ 在MyBatis中的模糊查询中的区别了嘛&#xff1f;&#xff1f; 三.MyBatis 中的结果映射 1. resultType&#xff1a; 2. resultMap&#xff1a; ---问题 ---…...

Redisson自定义序列化

Redisson自定义序列化_redisson 序列化_yzh_1346983557的博客-CSDN博客 redis存取的数据一定是可序列化的&#xff0c;而可序列化方式可以自定义。如果不同客户端设置的可序列化方式不一样&#xff0c;会导致读取不一致的问题。常见的序列化方式有几下几种...

MongoDB Long 类型 shell 查询

场景 1、某数据ID为Long类型&#xff0c;JAVA 定义实体类 Id Long id 2、查询数据库&#xff0c;此数据存在 3、使用 shell 查询&#xff0c;查不到数据 4、JAVA代码查询Query.query 不受任何影响 分析 尝试解决&#xff08;一&#xff09; long 在 mongo中为 int64 类型…...

回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测

回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现GA-…...

Spring cache整合Redis使用介绍

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…...

Metasploit提权

一、bypassuac 用户账户控制&#xff08;User Account Control&#xff0c;简写作UAC)是微软公司在其Windows Vista及更高版本操作系统中采用的一种控制机制。其原理是通知用户是否对应用程序使用硬盘驱动器和系统文件授权&#xff0c;以达到帮助阻止恶意程序&#xff08;有时也…...

TypeScript三种特殊类型

1.any类型 说明&#xff1a;any类型代表着可以赋值任意类型 let nickname:any"王二"nickname15nicknametruenicknameundefinednicknamenullnickname{}2.unknown类型 说明&#xff1a;类似any类型&#xff1b;只是不能赋值到其它类型上&#xff1b;除了any和known。…...

如何使用CSS实现一个响应式轮播图?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现响应式轮播图的示例⭐ HTML 结构⭐ CSS 样式 (styles.css)⭐ JavaScript 代码 (script.js)⭐ 实现说明⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带…...

数据生成 | MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成

数据生成 | MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成 目录 数据生成 | MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成生成效果基本描述模型描述程序设计参考资料 生成效果 基本描述 1.MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成&#xff1b; 2.马尔科夫链蒙特卡洛方…...

【从零开始的rust web开发之路 二】axum中间件和共享状态使用

系列文章目录 第一章 axum学习使用 第二章 axum中间件使用 文章目录 系列文章目录前言一、中间件是什么二、中间件使用常用中间件使用中间件使用TraceLayer中间件实现请求日志打印自定义中间件 共享状态 前言 上篇文件讲了路由和参数相应相关的。axum还有个关键的地方是中间件…...

Vue操作时间

一、获取现在时间 const currentTime () > {let date new Date();let year date.getFullYear(); //月份从0~11&#xff0c;所以加一let month date.getMonth();let dateArr [date.getMonth() 1,date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds(),…...

数据库——Redis 常见数据结构以及使用场景分析

文章目录 1. string2. list3. hash4. set5. sorted set 你可以自己本机安装 redis 或者通过 redis 官网提供的在线 redis 环境。 1. string 介绍 &#xff1a;string 数据结构是简单的 key-value 类型。虽然 Redis 是用 C 语言写的&#xff0c;但是 Redis 并没有使用 C 的字符串…...

数学建模-规划工具箱yalmip

官网下载 实例 %% yalmip 求解 yalmip clc;clear;close all; %% %sdpvar实型变量 intvar 整形变量 binvar 0-1型变量 psdpvar(3,1); %定义变量 %目标函数 要把求最大值转化为最小值 Objective-p(1)^2p(2)^2-p(2)*p(3);%约束条件 Constraints[0<p<1,(p(1)^2p…...

[SQL挖掘机] - 窗口函数 - 计算移动平均

介绍: 在窗口函数使用时&#xff0c;计算的是累积到当前行的所有的数据的相关操作。 实际上&#xff0c;还可以指定更加详细的汇总范围。该汇总范围称为 框架 (frame)。 其实这里也可以理解成一个窗口, 这个窗口是我们可以进行设置的. 之前我们介绍的窗口函数是根据partition…...

域名和hostname

最近用git克隆远程仓库时总是超时&#xff0c;报错说是代理的问题&#xff0c;但打开和关闭代理都没能解决问题&#xff0c;后面了解到可以关闭git命令的全局代理&#xff1a; git config --global --unset http.proxy git config --global --unset https.proxy如果下次要用的…...

echarts 甘特图一组显示多组数据

<template><el-button type"primary" click"addlin">添加线</el-button><el-button type"success" click"addArea">添加区域</el-button><div ref"echart" id"echart" class&qu…...

1139. 最大的以 1 为边界的正方形;2087. 网格图中机器人回家的最小代价;1145. 二叉树着色游戏

1139. 最大的以 1 为边界的正方形 核心思想&#xff1a;枚举正方向的右下角坐标&#xff08;i&#xff0c;j&#xff09;&#xff0c;然后你只需要判断四条边的连续一的最小个数即可&#xff0c;这里是边求连续一的个数同时求解结果。 087. 网格图中机器人回家的最小代价 核心…...

css滚动条的使用

前言&#xff1a; css滚动条的使用。 1、使用案例1&#xff1a;背景不要&#xff0c;只展示一个滚动条 如果是默认整体&#xff0c;::就够用了&#xff0c;如果是某个元素&#xff0c;可以 .abc:: ,如果是scss这种的 &:: ::-webkit-scrollbar {width: 6px; } ::-webkit…...

优化Python代理爬虫的应用

当我们在资源受限的环境中使用Python代理爬虫时&#xff0c;我们需要采取一些优化措施&#xff0c;以确保程序的高效性和稳定性。在本文中&#xff0c;我将分享一些关于如何优化Python代理爬虫在资源受限环境下的应用的实用技巧。 首先我们来了解&#xff0c;哪些情况算是资源…...

[C++] STL_vector使用与常用接口的模拟实现

文章目录 1、vector的介绍2、vector的使用2.1 vector的定义2.2 vector迭代器的使用2.3 vector的空间增长问题 3、vector的增删查改3.1 push_back&#xff08;重点&#xff09;3.2 pop_back&#xff08;重点&#xff09;3.3 operator[]&#xff08;重点&#xff09;3.4 insert3.…...

【LeetCode】167. 两数之和 II - 输入有序数组 - 双指针

目录标题 2023-8-23 09:25:08 2023-8-23 09:25:08 自己写的不是常量级的额外空间&#xff0c;但是写出来了&#xff0c;记录一下。 下次写的时候&#xff0c;请用双指针。 &#xff08;其实我想了想一想&#xff0c;双指针就没感觉出来&#xff1a;因为我只想到双指针两个都…...

YOLOV1

YOU ONLY LOOK ONCE...

美团增量数仓建设新进展

摘要&#xff1a;本文整理自美团系统研发工程师汤楚熙&#xff0c;在 Flink Forward Asia 2022 实时湖仓专场的分享。本篇内容主要分为四个部分&#xff1a; 建设背景核心能力设计与优化业务实践未来展望 点击查看原文视频 & 演讲PPT 一、美团增量数仓的建设背景 美团数仓架…...

​LeetCode解法汇总2337. 移动片段得到字符串

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给你两个字…...

Fpass与Fstop

在MATLAB中&#xff0c;“Fpass”、“Fstop”、"Apass"和"Astop"是数字滤波器设计中常用的参数。它们用于定义滤波器的频率响应和滤波器的性能。 "Fpass"表示通带频率&#xff0c;指的是滤波器允许通过的频率范围。在数字滤波器设计中&#xff0…...

Java快速入门体验

Java快速入门体验 一、环境信息1.1 硬件信息1.2 软件信息 二、Maven安装2.1 Maven介绍2.2 Maven安装包下载2.3 Maven安装2.4 Maven初始化 三、Java安装3.1 JDK下载3.2 JDK安装3.3 JDK初始化 四、开发环境搭建4.1 安装开发工具4.2 关联Maven环境4.2.1 新建JAVA项目4.2.2 Maven与…...

父组件传给子组件的数据是异步的,为什么会导致子组件比父组件先执行?

当父组件传递给子组件的数据是异步获取的时候&#xff0c;可能会导致子组件先执行的问题。这是因为在 Vue 的更新机制中&#xff0c;当组件的模板开始渲染时&#xff0c;会立即触发子组件的创建和挂载过程&#xff0c;而父组件的数据可能还没有完全加载完成。 具体来说&#xf…...

泛型编程 学习笔记

#include "iostream"using namespace std;template<typename T> void Print(T a) {cout << a << endl; }int main() {int a 5;double b 2.3;char c e;string d "sdfasd";Print(a);Print(b);Print(c);Print(d);return 0; } 它可以不用…...

电脑文件删除了可以找回吗?分享一种简单恢复删除电脑文件办法!

电脑文件删除了可以找回吗&#xff1f;可以。在原理上讲电脑删除的文件是有希望恢复的&#xff0c;因为操作系统在删除文件的时候并会不会立刻将文件彻底删除。当文件被删除的时候&#xff0c;其文件记录被删除&#xff0c;并且被文件占用的磁盘空间被标记为空闲。 这样对于用户…...

Pygame编程(4)event模块

Pygame编程&#xff08;4&#xff09;event模块 函数示例 函数 pygame.event.pump 让 Pygame 内部自动处理事件pygame.event.get 从队列中获取事件pygame.event.poll 从队列中获取一个事件pygame.event.wait 等待并从队列中获取一个事件pygame.event.peek 检测某类型事件是否在…...

Python数据采集实战-使用BeautifulSoup框架解析HTML文档并提取所需内容(附源码和实现效果)

实现功能 使用BeautifulSoup框架解析HTML文档并提取所需内容的例子&#xff1a;假设我们要从以下HTML文档中提取所有超链接的链接地址 实现代码 from bs4 import BeautifulSoup import requests# 发送请求并获取HTML文档 url "https://www.baidu.com" response r…...

Java“牵手”天猫商品列表数据,关键词搜索天猫商品数据接口,天猫API申请指南

天猫商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取天猫商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问天猫商城的网页来获取商品详情信息。以下是两种常用方法的介绍&…...

idea切换Git分支时保存未提交的文件

解决方案 我们现在有三个分支&#xff0c;如下图&#xff1a; 我们目前在tenant分支上进行开发&#xff0c;需要去修复master的Bug&#xff0c;假设我们在tenant分支上修改了一个文件&#xff0c;如下图&#xff1a; 方法一&#xff1a;使用Shelve Changes 1、选中tenant上你不…...

Qt串口通信学习文档

这是官方文档&#xff0c;我也在学习。 QSerialPort Class | Qt Serial Port 5.15.14https://doc.qt.io/qt-5/qserialport.html...

018-时间处理库,预处理

018-时间处理库,预处理 ⼀、C语⾔的时间处理库 time.h是C/C++中的⽇期和时间头⽂件,通过他可以获取系统时间及时间格式 转换 time库中常⽤函数介绍 1、函数名称: time 2、函数名称: localtime 3、函数名称: asctime 4、函数名称: ctime 5、函数名称: gmtime 6、函数名…...

Sketch 98 中文版-mac矢量绘图设计

Sketch是一款专为Mac操作系统设计的矢量图形编辑软件&#xff0c;被广泛应用于UI/UX设计、网页设计、移动应用设计等领域。Sketch提供了各种工具和功能&#xff0c;包括绘图、图形设计、排版等&#xff0c;可以帮助设计师轻松地创建高质量的矢量图形和模型。Sketch的主要特点包…...

Springboot继承Keycloak实现单点登陆与退出

由于网上博客大部分都只有登陆没有退出&#xff0c;自己花了一些时间研究了一下&#xff0c;这里将相关内容进行记录&#xff0c;基于Keyclaok 20的版本&#xff0c;实现springboot服务单点登录与退出 一、依赖 <!-- 在父工程中 --> <dependencyManagement><d…...