当前位置: 首页 > 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。…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…...