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

快速搭建对象存储服务 - Minio,并解决临时地址暴露ip、短链接请求改变浏览器地址等问题

本文要解决的问题

基础的Minio下载安装、java操作方法、完整的工具类。

使用minio时需要注意的地方:

      使用Minio的时候,生成资源的临时访问链接时,生成的地址IP是真实的IP和端口,不安全,怎么办?

      生成的Minio的临时访问链接过长怎么办?

从而引导出:

1、如何生成短链接:

2、重定向和转发的区别?

3、重定向的实现方式:

4、如何保证浏览器地址不变的情况下请求资源?

基于Docker-compose的Minio安装

配置文件docker-compose.yml

创建docker-compose.yml,并在docker-compose.yml文件夹下面创建文件夹data

mkdir data

version: "3"
services:minio:image: minio/miniocontainer_name: minioprivileged: true  #是否要获取宿主机的特权volumes:- /root/common/data/minio/data:/data #目录映射ports:- "9001:9001"    #端口映射 ---- 不能采用:9001:9000之类的- "9000:9000"    #端口映射environment:MINIO_ACCESS_KEY: xxxxxA1    #账号MINIO_SECRET_KEY: xxxxxA2 #密码command: server --console-address ':9001' /data  #启动命令healthcheck: #健康检测test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]interval: 30stimeout: 20sretries: 3

启动

docker-compose up -d  # 后台启动

启动成功后登录webUI

URL:ip:9001

Access Key:xxxxxA1

Secret_key:xxxxxA2

上传资源-web操作 

创建bucket

上传资源

 

 上传成功后的样式

Java使用 --- 基础版

Step1、引入pom依赖


<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.17</version>
</dependency>

 Step2、创建一个新key,并下载

此时系统会下载:credentials.json

{"url":"http://ip:9001/api/v1/service-account-credentials","accessKey":"xxxxx","secretKey":"xxxxxxx","api":"s3v4","path":"auto"} 

 Step3、创建一个application.yml文件

minio:url: "http://ip:9000"  # 如果是http://ip:9001 会报错“S3 API Requests must be made to API port.”
#  url: "http://www.abcxxxx域名.com"  # 需要配置 指向MinIO真实地址:http://ip:9000; --- 可以使用Nginx反向代理 --- 解决暴露真实IP的方法accessKey: "xxxxxA1"secretKey: "xxxxxA2"api: "s3v4"

Step4、创建配置实体MinioProperties.java

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {private String url;private String accessKey;private String secretKey;private String api;
}

Step5、创建文件类型枚举类FileType.java 

package com.lting.minio.model;import lombok.Getter;
/**
* 枚举类,按需定义
*/
public enum FileType {// 修正后的枚举定义(包含扩展名和MIME类型)MP4("mp4", "video/mp4"),TXT("txt", "text/plain"),JSON("json", "application/json"),PNG("png", "image/png"),      // 修正PNG类型JPG("jpg", "image/jpeg"),PDF("pdf", "application/pdf"),DOC("doc", "application/msword"),DOCX("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),CSV("csv", "text/csv"),EXCEL("xls", "application/vnd.ms-excel");private final String extension;@Getterprivate final String mimeType;// 枚举构造函数FileType(String extension, String mimeType) {this.extension = extension;this.mimeType = mimeType;}// 根据文件名获取MIME类型public static String getMimeTypeForFile(String fileName) {String extension = getFileExtension(fileName);for (FileType type : values()) {if (type.extension.equalsIgnoreCase(extension)) {return type.mimeType;}}return "application/octet-stream"; // 默认类型}// 根据扩展名获取枚举实例public static FileType fromExtension(String extension) {for (FileType type : values()) {if (type.extension.equalsIgnoreCase(extension)) {return type;}}throw new IllegalArgumentException("Unsupported file extension: " + extension);}// 获取文件扩展名辅助方法private static String getFileExtension(String fileName) {int lastDotIndex = fileName.lastIndexOf('.');if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {return "";}return fileName.substring(lastDotIndex + 1).toLowerCase();}
}

Step6、创建工具类MinioUtils.java

package com.lting.minio;import com.lting.minio.model.FileType;
import com.lting.minio.model.MinioProperties;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;/*** 0、桶列表* 1、CRUD桶Buckets* 2、Upload(指定路径)* 3、查看桶下面的list列表* 4、Delete* 5、Download*/
@Component
@Log4j2
public class MinioUtils {@Getterprivate final MinioProperties minioProperties;private MinioClient minioClient;@Autowiredpublic MinioUtils(MinioProperties minioProperties) {this.minioProperties = minioProperties;}@PostConstructpublic void init() {try {this.minioClient = MinioClient.builder().endpoint(minioProperties.getUrl()) // 使用代理域名---不然生成的临时地址为真实ip地址.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()).build();} catch (Exception e) {log.error("初始化minio配置异常", e.fillInStackTrace());}}/*** 已经存在的bucket集合列表*/public List<Bucket> listBucket() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {return minioClient.listBuckets();}/*** 创建buckets*/public void createBuckets(final String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}/*** 某一个bucket是否存在*/public boolean bucketExists(final String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {return this.minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/*** 删除buckets*/public void removeBucket(final String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/*** 上传文件* 通用上传方法*/public ObjectWriteResponse uploadFile(final String bucketName, final String fileName, final InputStream inputStream, final long fileSize, String contentType) throws Exception {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, fileSize, -1).contentType(contentType).build());}/*** 上传文件(如图片/PDF等)*/public ObjectWriteResponse uploadFile(File file, String bucketName, final String fileName) throws Exception {String contentType = Files.probeContentType(file.toPath());if (contentType == null) {contentType = "application/octet-stream"; // 默认类型}try (InputStream inputStream = new FileInputStream(file)) {return uploadFile(bucketName, fileName, inputStream, file.length(), contentType);}}/*** 上传本地文件*/public ObjectWriteResponse uploadLocalFile(final String bucketName, final String filePath, final String fileType) throws Exception {this.isMakeBuckets(bucketName);File file = new File(filePath);try (InputStream inputStream = new FileInputStream(file)) {return uploadFile(bucketName, file.getName(), inputStream, file.length(), fileType);}}/*** 上传MultipartFile(适用于HTTP文件上传)*/public ObjectWriteResponse uploadMultipartFile(final String bucketName, MultipartFile file, String fileName) throws Exception {this.isMakeBuckets(bucketName);final String contentType = file.getContentType();try (InputStream inputStream = file.getInputStream()) {return uploadFile(bucketName, fileName, inputStream, file.getSize(), contentType);}}/*** 上传二进制数据(如图片/PDF等) --- 会自动生成文件*/public ObjectWriteResponse uploadBytes(String bucketName, String fileName, byte[] data, final String fileType) throws Exception {this.isMakeBuckets(bucketName);try (InputStream inputStream = new ByteArrayInputStream(data)) {return uploadFile(bucketName, fileName, inputStream, data.length, fileType);}}/*** 上传文本内容 --- 会自动生成文件*/public ObjectWriteResponse uploadText(String bucketName, String fileName, String text) throws Exception {this.isMakeBuckets(bucketName);byte[] bytes = text.getBytes(StandardCharsets.UTF_8);try (InputStream inputStream = new ByteArrayInputStream(bytes)) {return uploadFile(bucketName, fileName, inputStream, bytes.length, FileType.TXT.getMimeType());}}/*** 上传JSON内容 --- 会自动生成文件*/public ObjectWriteResponse uploadJson(final String bucketName, final String fileName, final String json) throws Exception {this.isMakeBuckets(bucketName);byte[] bytes = json.getBytes(StandardCharsets.UTF_8);try (InputStream inputStream = new ByteArrayInputStream(bytes)) {return uploadFile(bucketName, fileName, inputStream, bytes.length, FileType.JSON.name());}}private void isMakeBuckets(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {boolean found = this.bucketExists(bucketName);if (!found) {this.createBuckets(bucketName);}}/*** 查看已经存在的buckets下面的文件*/public List<Result<Item>> listObject(final String bucketName) throws Exception {return listObject(bucketName, "", 1000);}public List<Result<Item>> listObject(final String bucketName, final String prefix, final int size) throws Exception {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix) // 开始名称.maxKeys(size) // 最大数量.includeVersions(true).recursive(true) // 是否递归遍历子目录.build());return StreamSupport.stream(results.spliterator(), false).collect(Collectors.toList());}/*** 下载到流*/public InputStream downloadToStream(String bucketName, String fileName) throws Exception {try {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());} catch (MinioException e) {throw new Exception("下载失败: " + e.getMessage());}}/*** 下载到本地*/public void downloadToLocal(String bucketName, String fileName, String localFilePath) throws Exception {try (InputStream inputStream = downloadToStream(bucketName, fileName)) {Path path = Path.of(localFilePath);Files.copy(inputStream, path);} catch (Exception e) {throw new Exception("文件保存失败: " + e.getMessage());}}/*** 单个文件删除*/public void deleteObject(String bucketName, String fileName) throws Exception {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());} catch (MinioException e) {throw new Exception("删除失败: " + e.getMessage());}}/*** 批量删除(需自行遍历)*/public void batchDelete(String bucketName, List<String> objectNames) {objectNames.forEach(name -> {try {deleteObject(bucketName, name);} catch (Exception e) {// 记录日志或处理异常System.err.println("删除失败: " + name + " | 原因: " + e.getMessage());}});}/*** 获取预览地址* 有效时间默认1H** @return*/public String getPreviewFileUrl(String bucketName, String fileName) throws Exception {return getPreviewFileUrl(bucketName, fileName, 10, TimeUnit.MINUTES);}public String getPreviewFileUrl(String bucketName, String fileName, final int expiryTime, final TimeUnit timeUnit) throws Exception {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).expiry(expiryTime, timeUnit).build());}
}

Step7、启动类MinioApplication.java

@SpringBootApplication
@EnableConfigurationProperties(MinioProperties.class) // 显式启用
public class MinioApplication {public static void main(String[] args) {SpringApplication.run(MinioApplication.class, args);}
}

Step8、测试类---按需

import com.lting.MinioApplication;
import io.minio.ObjectWriteResponse;
import io.minio.Result;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.File;
import java.util.List;@SpringBootTest(classes = MinioApplication.class)
public class MinioTest {@Autowiredprivate MinioUtils minioUtils;@Test@DisplayName("MinioUtils")public void properties() {System.out.println(minioUtils.getMinioProperties());}@Test@DisplayName("listBuckets")public void listBuckets() {try {List<Bucket> buckets = minioUtils.listBucket();buckets.forEach(x -> System.out.println(x.creationDate() + ", " + x.name()));} catch (Exception e) {throw new RuntimeException(e);}}@Test@DisplayName("makeBuckets")public void createBuckets() {try {minioUtils.createBuckets("test_code_create");listBuckets();} catch (Exception e) {throw new RuntimeException(e);}}@Test@DisplayName("deleteBuckets")public void deleteBuckets() {try {minioUtils.removeBucket("test_code_create");listBuckets();} catch (Exception e) {throw new RuntimeException(e);}}@Test@DisplayName("uploadLocalFile")public void uploadLocalFile() throws Exception {final String bucketName = "test_code_create";final String filePath = "C:\\Users\\xxxxx.png";final File file = new File(filePath);ObjectWriteResponse owr = minioUtils.uploadFile(file, bucketName,"2025/04/25/pig.png");  // 当在webui中创建的路径:V1/V2/V3一样的效果System.out.println(owr.etag());}@Test@DisplayName("listBuckets")public void uploadText() throws Exception {String content = "{\"url\":\"http://ip:9001/api/v1/service-account-credentials\",\"accessKey\":\"xxxx\",\"secretKey\":\"xxxxxx\",\"api\":\"s3v4\",\"path\":\"auto\"}";ObjectWriteResponse owr= minioUtils.uploadText("test_code_create", "/2025/04/25/测试.txt", content);System.out.println(owr.etag());}@Test@DisplayName("listObject")public void listObject() throws Exception {List<Result<Item>> items= minioUtils.listObject("test_code_create");items.forEach(x -> {try {Item item = x.get();System.out.println(item.etag() + "\t" + item.objectName() + "\t" + item.size() + "\t" + item.lastModified().toLocalDateTime() + "\t" + item.versionId());} catch (Exception e) {throw new RuntimeException(e);}});}@Test@DisplayName("getPreviewFileUrl")public void getPreviewFileUrl() throws Exception {System.out.println(minioUtils.getPreviewFileUrl("test_code_create", "2025/04/25/ltingzx.png"));;}@Test@DisplayName("downloadToLocal")public void downloadToLocal() throws Exception {minioUtils.downloadToLocal("test_code_create", "requirements.txt", "C:\\Users\\YiYang\\Desktop\\LLama-Factory\\req.txt");}}

关于Minio真实IP解决方法:

使用Minio的时候,生成资源的临时访问链接时,生成的地址IP是真实的IP和端口,不安全,怎么办?

minio通过“minioUtils.getPreviewFileUrl”方法生成临时链接为一般为比较长的链接,比如:“http://127.0.0.1:9001/test/xxxx_47109.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=gKK5g5pdjV6LWdW8XtoO%2F20250428%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250428T100736Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=bd9560f5655e341263a8944545142449b1a7a393e8952eb20f9be9be9cc1391b”

---- 注意:解决方案有很多种,但是本文使用的是,短链接+Nginx代理+代理请求方案解决

Step1、前提准备

准备一个域名 比如 minio.ltingzx.com

如果没有域名,可以在本地修改hosts文件 添加: 127.0.0.1 minio.ltingzx.com

step2、修改application.yml文件

将url修改为step1中的域名;

minio:url: "http://minio.ltingzx.com"  # 需要配置 指向MinIO真实地址:http://ip:9000; --- 可以使用Nginx反向代理

Step3、添加nginx.conf配置,并启动nginx

关于优化,因为我们使用的是minio存储图片等资源,所以我们可以在Nginx上面开启缓存,用以优化...;

server {listen       80;server_name  minio.ltingzx.com;# 指定前端项目所在的位置location / {proxy_pass http://ip:9000; # 指向MinIO真实地址proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}

Step4、生成短链接以及访问短链接

长链接请求接口A ,接口A 生成短链接并返回;

用户拿到短链接后,请求服务的接口,服务接口拿到短链接以后,在映射关系中找到对应的长链接,直接重定向/转发/代理请求即可。

重定向:重定向是需要服务器端返回url地址,由浏览器端再次请求---此时依然会暴露真实ip和端口,且浏览器会改变地址;

转发:之所以不使用转发,核心原因是因为,转发的话需要资源和服务在同一网络---此时我们的minio在云端服务器,服务在本地,所以不适用。

代理请求:拿到短链接后,直接由服务器进行请求;然后服务器拿到的资源返回给response的outputstream流即可。

本文使用UUID临时处理,并且直接使用map方法存储:
真实开发中,我们的映射关系可以存储在数据库(比如Redis/MySQL)中,并且要设置过期时间;

使用重定向访问短链接

    private final static Map<String, String> URL_MAP = new HashMap<>();
@PostMapping("/generate")public R<String> generate(@RequestParam("longUrl") String longUrl) {String shortUrl = UUID.randomUUID().toString().replace("-", "");URL_MAP.put(shortUrl, longUrl);return R.ok(shortUrl);}/*** 短链接点击跳转*重定向方法: ---- 要改变浏览器地址* 设置sendRedirect,比如response.sendRedirect(URL_MAP.get(shortURL))* 或者设置状态302,*      response.setStatus(302);*      response.setHeader("Location", URL_MAP.get(shortURL));* @param shortURL*/
@GetMapping("/{shortURL}")public void redirect(@PathVariable("shortURL") String shortURL, HttpServletResponse response) throws IOException, NotFoundException {System.out.println("短链接 redirect to :" + shortURL);if (URL_MAP.containsKey(shortURL)) {
//            response.sendRedirect(URL_MAP.get(shortURL));response.setStatus(302);response.setHeader("Location", URL_MAP.get(shortURL));
//            response.sendRedirect(URL_MAP.get(shortURL));} else {throw new NotFoundException("短链已过期");}}

服务端代理请求形式 --- 直接由服务器端发起请求

实现步骤

  1. 生成短链接:将长URL映射为短码(如Base62编码),并存储映射关系。

  2. 处理短链接请求:当访问短链接时,服务器通过短码获取长URL。

  3. 代理请求:服务器端发起HTTP请求到长URL,将响应内容返回客户端,保持地址栏不变。

    @GetMapping("/{shortURL}")public void proxyRequest(@PathVariable("shortURL") String targetUrl, HttpServletResponse resp) throws IOException, NotFoundException {try (CloseableHttpClient httpClient = HttpClients.createDefault()) {HttpGet httpGet = new HttpGet(URL_MAP.get(targetUrl));try (CloseableHttpResponse response = httpClient.execute(httpGet)) {// 复制状态码resp.setStatus(response.getStatusLine().getStatusCode());// 复制响应头org.apache.http.Header[] headers = response.getAllHeaders();for (org.apache.http.Header header : headers) {resp.setHeader(header.getName(), header.getValue());}// 复制响应内容HttpEntity entity = response.getEntity();if (entity != null) {try (InputStream inputStream = entity.getContent();OutputStream outputStream = resp.getOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}}}}}}

相关文章:

快速搭建对象存储服务 - Minio,并解决临时地址暴露ip、短链接请求改变浏览器地址等问题

本文要解决的问题 基础的Minio下载安装、java操作方法、完整的工具类。 使用minio时需要注意的地方&#xff1a; 使用Minio的时候&#xff0c;生成资源的临时访问链接时&#xff0c;生成的地址IP是真实的IP和端口&#xff0c;不安全&#xff0c;怎么办&#xff1f; 生成的Min…...

2025年- H11-Lc118-53.最大子数组和(普通数组)---java版

1.题目描述 2.思路 用动态规划方法来解决【最大子数组和】&#xff08;Maximum Subarray&#xff09;问题。 pre&#xff08;当前位置最大和&#xff09;、 maxAns&#xff08;全局最大和&#xff09; 3.代码实现 class H53 {public int maxSubArray(int[] nums) {int curr…...

基于蓝牙Beacon人员导航方案

基于蓝牙Beacon人员导航方案 一、室内定位市场痛点与技术选择 大型商场&#xff08;单层超2万㎡&#xff09;和医院&#xff08;科室超200个&#xff09;的复杂空间中&#xff0c;传统GPS信号衰减超90%&#xff0c;用户平均寻路耗时10-15分钟&#xff0c;30%购物决策因“找店…...

mysql模糊多次OR查询某一个字段,针对这个字段进行查询分组

一. 需求 有一个mysql表t_test,有两个字段className和studentStr 其中studentStr会用来模糊查询 假如现在有6条数据 1.studentStr字段数据:“小明,小红,小同,小芳,小特,小兰” 2.studentStr字段数据:“小明,小红,小同” 3.studentStr字段数据:“小芳,小特,小兰” 4.stud…...

OpenGL进阶系列21 - OpenGL SuperBible - blendmatrix 例子学习

一:概述 颜色输出阶段是 OpenGL 渲染管线中最后一个阶段。它决定了片段在离开片段着色器之后,最终显示在用户屏幕上的颜色值。颜色输出阶段最重要的一个操作就是混合。本例子重点介绍下OpenGL中的混合操作。 对于每个通过片段测试(per-fragment tests)的片段,会执行混合操…...

阿里语音处理工具ClearerVoice-Studio项目上手指南

ClearerVoice-Studio:开源语音处理全能工具箱 🚀 核心功能速览 语音增强:消除环境噪声(支持16kHz/48kHz)语音分离:多人对话场景的说话人分离(8kHz/16kHz)超分辨率:16kHz→48kHz音质提升目标说话人提取:基于人脸/手势/EEG的多模态提取语音质量评估:9种客观评价指标A…...

31、简要描述Promise.all的用途

Promise.all 是 JavaScript 中用于处理多个异步操作的核心方法&#xff0c;其核心用途是并行聚合多个 Promise 的结果&#xff0c;并在所有操作成功时统一返回结果数组。以下是其关键特性与典型应用场景的简要描述&#xff1a; 核心功能 1、并行执行 接收一个 Promise 数组&…...

OpenVLA-OFT

TL;DR 2025 年斯坦福提出的 OpenVLA 工作的续作 OpenVLA-OFT&#xff0c;优化 VLA 能够有效适应新的机器人平台和任务&#xff0c;优化的技术主要有并行解码、动作块处理、连续动作、L1 回归和&#xff08;可选的&#xff09;FiLM 语言调节 Paper name Fine-Tuning Vision-La…...

2025“钉耙编程”中国大学生算法设计春季联赛(8)10031007

题目的意思很好理解找从最左边到最右边最短路&#xff08;BFS&#xff09; #include <bits/stdc.h> using namespace std; int a[510][510]; // 存储网格中每个位置是否有障碍&#xff08;1表示有障碍&#xff0c;0表示无障碍&#xff09; int v[510][510]; // 记录每…...

代码随想录算法训练营第六十一天 | floyd算法

Floyd 算法精讲 题目链接&#xff1a;97. 小明逛公园 文章讲解&#xff1a;代码随想录 思想&#xff1a;本题是多源最短路&#xff0c;即求多个起点到多个终点的多条最短路径。用Floyd 算法。 Floyd 算法对边的权值正负没有要求&#xff0c;都可以处理&#xff0c;Floyd算法…...

[三分钟]web自动化测试(三):selenium自动化测试常用函数(下)

文章目录 4.等待4.1 强制等待4.2 隐式等待4.3 显式等待 5.浏览器导航5.1 浏览器的前进、后退、刷新5.2 打开网站 6. 弹窗6.1 确认和取消6.2 输入信息 7. 文件上传 4.等待 如果页面渲染的速度赶不上代码执行的速度&#xff0c;可能会因为渲染过慢出现自动化误报的问题。 此时可…...

文档声明:HTML文档的基石

在前端开发的世界里&#xff0c;文档声明虽是一个看似不起眼的细节&#xff0c;却在网页的解析和渲染过程中扮演着至关重要的角色。今天&#xff0c;就让我们深入探讨文档声明的奥秘&#xff0c;揭开它背后的原理和重要性。 一、文档声明的定义与作用 文档声明&#xff0c;顾…...

光学涡旋干涉仪

一、什么是涡旋干涉仪&#xff1f; 涡旋光束一般指电场含有螺旋相位因子exp(iℓθ)的光束&#xff0c;其中ℓ为拓扑荷数&#xff0c;θ为方位角&#xff0c;其波前为螺旋形&#xff0c;光束中心存在相位奇点&#xff0c;因此涡旋光束的光强轮廓是中心强度为零的圆环。早在1992…...

Wireshark快速入门--对启动的后端程序进行抓包

怎么对自己启动的后端程序进行抓包&#xff1f; 1. 安装并启动 Wireshark 你要先从 Wireshark 官网 下载对应系统的安装包&#xff0c;然后进行安装。安装完成后&#xff0c;启动该软件。 可以快速入门可以参考博文&#xff1a;从零开始学 Wireshark&#xff1a;网络分析入门…...

ViTa-Zero:零样本视觉触觉目标 6D 姿态估计

25年4月来自Amazon 公司、Brown 大学和 Northestern 大学的论文“ViTa-Zero: Zero-shot Visuotactile Object 6D Pose Estimation”。 目标 6D 姿态估计是机器人技术中的一项关键挑战&#xff0c;尤其对于操作任务而言。虽然先前结合视觉和触觉&#xff08;视觉触觉&#xff0…...

继承(c++版 非常详细版)

一. 继承的概念及定义 1.1 继承的概念 继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段&#xff0c;它允许我们在保持原有 类特性的基础上进⾏扩展&#xff0c;增加⽅法(成员函数)和属性(成员变量)&#xff0c;这样产⽣新的类&#xff0c;称派⽣类。继…...

解锁服务器迁移的未来:《2025 服务器迁移效率白皮书》(附下载)

一、背景&#x1f3d9;️ 随着全球数字化转型的不断加速&#xff0c;企业在推动 IT 基础设施现代化过程中&#xff0c;面临着前所未有的服务器迁移挑战。传统的迁移工具和多云、混合云环境带来的复杂性&#xff0c;导致迁移效率低、成本高、人力投入大&#xff0c;从而严重阻碍…...

STM32的Flash映射双重机制

在STM32微控制器中&#xff0c;存在一个重要的内存映射特性&#xff1a;Flash存储器可以同时出现在两个不同的地址区域&#xff0c;而且可以通过重映射功能改变CPU启动时从哪个地址获取初始指令。 STM32的Flash映射双重机制 当描述"通常起始于地址0x00000000&#xff0c…...

简单了解跨域问题

什么是跨域&#xff1f; 跨域是浏览器基于同源策略的安全机制。 如何两个请求之间&#xff0c;域名&#xff0c;端口&#xff0c;协议三者中有任意一个不同&#xff0c;就会产生跨域问题。 跨域的解决方案 1. CORS&#xff08;跨源资源共享&#xff09; 后端通过设置响应头声…...

sql学习笔记(四)

今天看到一个sql题&#xff0c;“近30天&#xff0c;******”&#xff0c;这里需要用到一个函数&#xff0c;date_add&#xff0c;其作用是在指定日期基础上添加一个时间间隔。 语法&#xff08;以mysql为例&#xff09;&#xff1a; DATE_ADD(date, INTERVAL value unit) d…...

基于 Java 的实现前端组装查询语句,后端直接执行查询方案,涵盖前端和后端的设计思路

1. 前端设计 前端负责根据用户输入或交互条件,动态生成查询参数,并通过 HTTP 请求发送到后端。 前端逻辑: 提供用户界面(如表单、筛选器等),让用户选择查询条件。将用户选择的条件组装成 JSON 格式的查询参数。发送 HTTP 请求(如 POST 或 GET)到后端。示例: 假设用…...

反射与注解实现动态功能扩展案例-插件系统

学海无涯&#xff0c;志当存远。燃心砺志&#xff0c;奋进不辍。 愿诸君得此鸡汤&#xff0c;如沐春风&#xff0c;事业有成。 若觉此言甚善&#xff0c;烦请赐赞一枚&#xff0c;共励学途&#xff0c;同铸辉煌&#xff01; 开发一个需要高度扩展性的应用&#xff0c;比如Web框…...

auto(x) decay copy

该提案为auto又增加了两个新语法&#xff1a;auto(x) 和auto{x}。两个作用一样&#xff0c;只是写法不同&#xff0c;都 是为x 创建一份拷贝。 为什么需要这么个东西&#xff1f;看一个例子&#xff1a; void bar(const auto&);void foo(const auto& param) {auto co…...

基于STM32、HAL库的DS2411R安全验证及加密芯片驱动程序设计

一、简介: DS2411R是Maxim Integrated(现为Analog Devices)生产的一款1-Wire硅序列号芯片,具有以下特点: 64位唯一ROM序列号(包括8位家族码、48位序列号和8位CRC校验码) 工作电压范围:2.8V至5.25V 工作温度范围:-40C至+85C 采用TO-92或SOT-223封装 通过1-Wire协议通信…...

疫苗接种体系进入“全生命周期”时代:公共卫生治理再提速

疫苗接种体系进入“全生命周期”时代&#xff1a;公共卫生治理再提速 在防控重大传染病的国家公共卫生战略中&#xff0c;疫苗接种始终处于基础性、先导性地位。2025年4月25日是第39个全国儿童预防接种日&#xff0c;活动主题为“打疫苗、防疾病、保健康”。近年来&#xff0c…...

zynq 7010 PS 串口打印

前言 之前写过一篇文章《zynq 7010 PL 点灯例程》&#xff0c;介绍的是 zynq PL 部分的使用&#xff0c;今天这篇文章则是介绍 zynq PS 部分的使用。 在此之前&#xff0c;先总结点题外话 PL 编程&#xff0c;核心思想是生成 bitstream 文件&#xff0c;加载到 FPGA 运行PS …...

【补题】ACPC Kickoff 2025 F. Kinan The Bank Robber

题意&#xff1a;给出长度为n的序列&#xff0c;接下来给出了两个包裹&#xff0c;你可以选择把数字放进这两个包裹当中&#xff0c;要求你放的的方式&#xff0c;最终会让包裹内的数字双双互质&#xff0c;请你给出你的放法&#xff0c;如果没有输出-1 思路&#xff1a; 1.包…...

局域网传文件——基于flask实现

项目地址 git clone gitgitee.com:xhdx/co_-shared_-doc_in_-local_-net.git 所需python包 flask2.2.3 markdown3.4.1 bleach5.0.1 通过局域网的方式实现文件夹共享&#xff0c;共享的文件会放在uploads这个文件夹下&#xff1a; 运行界面&#xff1a; 包括预览、删除、下载等…...

苍穹外卖10

WebSocket WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信----浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP是短链接 WebSocke…...

第一天 车联网定义、发展历程与生态体系

前言 车联网&#xff08;Internet of Vehicles, IoV&#xff09;作为物联网&#xff08;IoT&#xff09;在汽车领域的延伸&#xff0c;正在彻底改变人们的出行方式。无论是自动驾驶、远程诊断&#xff0c;还是实时交通优化&#xff0c;车联网技术都扮演着核心角色。本文将从零…...

大模型(LLMs)强化学习—— PPO

一、大语言模型RLHF中的PPO主要分哪些步骤&#xff1f; 二、举例描述一下 大语言模型的RLHF&#xff1f; 三、大语言模型RLHF 采样篇 什么是 PPO 中 采样过程&#xff1f;介绍一下 PPO 中 采样策略&#xff1f;PPO 中 采样策略中&#xff0c;如何评估“收益”&#xff1f; …...

麻衣相法【麻衣相士】开篇

好久没有发布新的文章了,主要最近一方面没看书,时间基本都用来打游戏了;另一方面看的几本书实在是看不懂,就更不能写上来了。不过今天看到了《麻衣相法》这本书,就又点燃了本人的兴趣,以后失业了,可以摆个小摊子谋生! 话不多说,先把这本书开始的针对人的面部部位进行各…...

vLLM技术解析:大语言模型推理服务的性能革新引擎

vLLM大模型 vLLM&#xff08;Vectorized Large Language Model Serving System&#xff09;是由加州大学伯克利分校计算机系统研究团队开发的下一代大语言模型推理服务系统。作为专为现代化AI部署设计的开源框架&#xff0c;该系统通过突破性的内存架构创新和计算流程优化&…...

《无刷空心杯电机减速机选型及行业发展趋势》

无刷空心杯电机作为高精度驱动系统的核心部件,通常需搭配减速机以实现低转速、高扭矩输出。以下是当前主流的减速机类型、市场占比、参数对比及优劣势分析,结合行业数据与典型应用场景展开说明: 一、主流减速机类型及市场占比 1. 行星减速机 市场占比:约 45%-55%(工业自…...

Java锁的升级流程详解:无锁、偏向锁、轻量级锁、重量级锁

在Java中&#xff0c;为了在多线程并发场景下既保证线程安全&#xff0c;又尽可能提高性能&#xff0c;JVM针对synchronized实现了锁的优化升级机制。 锁可以从无锁逐步升级到偏向锁、轻量级锁&#xff0c;最后是重量级锁。 话不多说&#xff0c;发车&#xff01; 一、无锁&am…...

terraform local-exec与remote-exec详解

在 Terraform 中&#xff0c;local-exec 和 remote-exec 是两种常用的 provisioner&#xff08;资源调配器&#xff09;&#xff0c;用于在资源创建前后执行脚本或命令。它们的核心区别在于执行位置&#xff1a;local-exec 在运行 Terraform 的本地机器上执行命令&#xff0c;而…...

武装Burp Suite工具:APIKit插件_接口安全扫描.

武装Burp Suite工具&#xff1a;APIKit插件_接口安全扫描. API安全是指通过技术手段和管理措施保护应用程序接口&#xff08;API&#xff09;免受未授权访问、数据泄露或恶意攻击的防护体系&#xff0c;核心措施包括身份认证&#xff08;如OAuth2.0/JWT&#xff09;、权限控制…...

数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记6

前言 经过前面几篇文章的介绍&#xff0c;已经完成了对于数据查询操作的介绍&#xff0c;接下来&#xff0c;本篇文章将介绍数据更新这一板块&#xff0c;包括插入数据、修改数据以及删除数据三种操作方法。 注&#xff1a;本文中所涉及的数据库前文中已经介绍&#xff08;指…...

如何在idea中写spark程序

1. 安装配置 Java 和 Scala Java&#xff1a;确保已安装合适版本的 Java Development Kit&#xff08;JDK&#xff09;&#xff0c;并配置好 JAVA_HOME 环境变量。Scala&#xff1a;由于 Spark 常用 Scala 语言编写&#xff0c;需安装 Scala 开发环境。可在 IDEA 中通过 Se…...

Linux428 chmod 0xxx 1xxx 2xxx 4xxx;umask;chown 属主属组 软件包rpm

sudo: 账户过期&#xff0c;或 PAM 配置缺少 sudo 使用的“account”节&#xff0c;联系您的系统管理员 这样子有没有用嘞 不行 为什么使用caozx26用户sudo修改了shop文件夹强制位&#xff0c;shop文件夹权限中不显示 成功了&#xff1f;真奇怪 查看文件夹权限用 -ld ch…...

基于强化学习的用于非刚性图像配准的引导式超声采集|文献速递-深度学习医疗AI最新文献

Title 题目 Guided ultrasound acquisition for nonrigid image registration usingreinforcement learning 基于强化学习的用于非刚性图像配准的引导式超声采集 01 文献速递介绍 超声成像通常用于引导手术和其他医疗程序&#xff0c;在这些过程中&#xff0c;临床医生会持…...

Shell脚本-嵌套循环应用案例

在Shell脚本编程中&#xff0c;嵌套循环是一种强大的工具&#xff0c;可以用于处理复杂的任务和数据结构。通过在一个循环内部再嵌套另一个循环&#xff0c;我们可以实现对多维数组、矩阵操作、文件处理等多种高级功能。本文将通过几个实际的应用案例来展示如何使用嵌套循环解决…...

QTableView复选框居中

目录 方法一&#xff1a;QSS方法2:自定义复选框委托类一、构造函数 CheckBoxDelegate()二、paint() 方法三、editorEvent() 方法四、关键设计要点五、扩展应用场景六、代码示例&#xff08;补充&#xff09; 方法一&#xff1a;QSS QTableView::indicator {position: relative…...

C语言教程(十八):C 语言共用体详解

一、共用体的定义 共用体的定义和结构体类似&#xff0c;使用 union 关键字&#xff0c;其基本语法如下&#xff1a; union 共用体名 { 数据类型 成员1; 数据类型 成员2; // 可以有更多成员 }; 以下是一个简单的共用体定义示例&#xff1a; union Data {int i;float f;char …...

企业办公系统开发如何重塑现代工作方式?

随着工作方式的革新&#xff0c;企业办公软件开发已成为提升组织效率的核心驱动力。从基础的文档处理到复杂的协同办公平台开发&#xff0c;现代办公系统正在彻底改变传统工作模式。本文将深入解析办公类软件的关键技术与发展趋势。 一、企业级办公系统开发的核心模块 专业的O…...

springboot 实现敏感信息脱敏

记录于2025年4月28号晚上--梧州少帅 1. 定义枚举类&#xff1a; public enum DesensitizeType {NAME, EMAIL } 2. 创建自定义注解&#xff1a; 用于标记需要脱敏的字段及其类型。 Retention(RetentionPolicy.RUNTIME) JacksonAnnotationsInside JsonSerialize(using Desen…...

JavaWeb学习打卡-Day5-Spring事务管理、SpringAOP

Spring事务管理 Transactional注解 位置&#xff1a;业务层&#xff08;Service&#xff09;的方法上、类上、接口上。作用&#xff1a;将当前方法交给spring进行事务管理&#xff0c;方法执行前&#xff0c;开启事务&#xff1b;成功执行完毕&#xff0c;提交事务&#xff1…...

项目立项管理

项目立项管理是对拟规划和实施的项目技术上的先进性、适用性&#xff0c;经济上的合理性、效益性&#xff0c;实施上的可能性、风险性以及社会价值的有效性、可持续性等进行全面科学的综合分析&#xff0c;为项目决策提供客观依据的一种技术经济研究活动。 一般包括项目建议与…...

一文梳理业财融合在财务管理中的运用!

目录 一、业财融合在财务管理中的运用概括 二、促进财务决策科学化 1. 传统财务决策的局限性 2. 业财融合助力财务决策科学化 三、加强成本控制 1. 传统成本控制的不足 2. 业财融合实现精准成本管控 四、优化资金管理 1. 传统资金管理的问题 2. 业财融合优化资金配置…...

C#核心知识

委托 如何声明一个委托&#xff1a;通过 【delegate 返回值类型 委托名称】 的格式来定义 如何使用一个委托&#xff1a;使用new关键字&#xff0c;并传入和声明委托的构造相同的方法名&#xff0c;比如&#xff1a;new 委托名称(与委托的参数和返回值相同的一个方法名) 如何…...