AWS S3 协议对接 minio/oss 等
使用亚马逊 S3 协议访问对象存储 [s3-API](https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_Operations_Amazon_Simple_Storage_Service.html)- 兼容S3协议的对象存储有- minio- 似乎是完全兼容 [兼容文档](https://www.minio.org.cn/product/s3-compatibility.html)- 阿里云oss- [兼容主要的 API ](https://help.aliyun.com/zh/oss/developer-reference/compatibility-with-amazon-s3?spm=a2c4g.11186623.0.0.590b32bcHb4D6a)- 七牛云oss- 等等
依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--使用的依赖--><dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId><version>1.12.522</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency></dependencies>
读取配置
package com.xx.awss3demo.config;import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@ConfigurationProperties(prefix = "s3")
@Component
public class S3Properties {/*** 对象存储服务的URL*/private String endpoint;/*** path-style nginx 反向代理和S3默认支持* 模式 {http://bucketname.endpoint} -- true* 模式 {http://endpoint/bucketname} -- false*/private Boolean pathStyleAccess = false;/*** 区域*/private String region;/*** Access key就像用户ID,可以唯一标识你的账户*/private String accessKey;/*** Secret key是你账户的密码*/private String secretKey;/*** 最大线程数,默认: 100*/private Integer maxConnections = 50;}
配置文件
server:port: 8888s3:# aliyun oss#endpoint: http://oss-cn-shanghai.aliyuncs.com#accessKey: #secretKey: # minioendpoint: http://192.168.1.1:9000accessKey: adminsecretKey: admin1234bucketName: lqs3bucketregion:maxConnections: 100
文件操作
package com.xx.awss3demo.service;import com.amazonaws.ClientConfiguration;
import com.amazonaws.ClientConfigurationFactory;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.IOUtils;
import com.liuqi.awss3demo.config.S3Properties;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.PostConstruct;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;@ConditionalOnClass(S3Properties.class)
@Service
@Log4j2
public class S3FileService {@Autowiredprivate S3Properties s3Properties;private AmazonS3 amazonS3;@PostConstructpublic void init() {log.info(s3Properties);amazonS3 = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(s3Properties.getAccessKey(), s3Properties.getSecretKey()))).withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(s3Properties.getEndpoint(),s3Properties.getRegion())).withPathStyleAccessEnabled(s3Properties.getPathStyleAccess()).withChunkedEncodingDisabled(true).withClientConfiguration(new ClientConfiguration().withMaxConnections(s3Properties.getMaxConnections()).withMaxErrorRetry(1)).build();}/*** 创建bucket* 注意:bucket name 不允许有特殊字符及大写字母** @param bucketName bucket名称* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket">AWS API* Documentation</a>*/@SneakyThrowspublic void createBucket(String bucketName) {if (!bucketName.toLowerCase().equals(bucketName)) {throw new RuntimeException("bucket name not allow upper case");}if (checkBucketExist(bucketName)) {log.info("bucket: {} 已经存在", bucketName);return;}amazonS3.createBucket((bucketName));}@SneakyThrowspublic boolean checkBucketExist(String bucketName) {return amazonS3.doesBucketExistV2(bucketName);}/*** 获取全部bucket* <p>** @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS* API Documentation</a>*/@SneakyThrowspublic List<Bucket> getAllBuckets() {return amazonS3.listBuckets();}/*** 根据bucket获取bucket详情** @param bucketName bucket名称* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS* API Documentation</a>*/@SneakyThrowspublic Optional<Bucket> getBucket(String bucketName) {return amazonS3.listBuckets().stream().filter(b -> b.getName().equals(bucketName)).findFirst();}/*** @param bucketName bucket名称* @see <a href=* "http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket">AWS API* Documentation</a>*/@SneakyThrowspublic void removeBucket(String bucketName) {amazonS3.deleteBucket(bucketName);}/*** 复制文件* @param bucketName* @param srcObjectName* @param tarObjectName*/public void copyObject(String bucketName, String srcObjectName,String tarObjectName){amazonS3.copyObject(bucketName,srcObjectName,bucketName,tarObjectName);}/*** 上传文件,指定文件类型** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param contextType 文件类型* @throws Exception*/@SneakyThrowspublic void putObject(String bucketName, String objectName, InputStream stream,String contextType) {ObjectMetadata objectMetadata = new ObjectMetadata();objectMetadata.setContentLength(stream.available());objectMetadata.setContentType(contextType);putObject(bucketName, objectName, stream, objectMetadata);}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @throws Exception*/@SneakyThrowspublic void putObject(String bucketName, String objectName, InputStream stream) {ObjectMetadata objectMetadata = new ObjectMetadata();objectMetadata.setContentLength(stream.available());objectMetadata.setContentType("application/octet-stream");putObject(bucketName, objectName, stream, objectMetadata);}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param objectMetadata 对象元数据* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject">AWS* API Documentation</a>*/@SneakyThrowsprivate PutObjectResult putObject(String bucketName, String objectName, InputStream stream,ObjectMetadata objectMetadata) {byte[] bytes = IOUtils.toByteArray(stream);ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);// 上传return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);}/*** 判断object是否存在** @param bucketName bucket名称* @param objectName 文件名称* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS* API Documentation</a>*/@SneakyThrowspublic boolean checkObjectExist(String bucketName, String objectName) {return amazonS3.doesObjectExist(bucketName, objectName);}/*** 获取文件** @param bucketName bucket名称* @param objectName 文件名称* @return 二进制流* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS* API Documentation</a>*/@SneakyThrowspublic S3Object getObject(String bucketName, String objectName) {return amazonS3.getObject(bucketName, objectName);}/*** 删除文件** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject">AWS* API Documentation</a>*/@SneakyThrowspublic void deleteObject(String bucketName, String objectName) {amazonS3.deleteObject(bucketName, objectName);}/*** 大文件分段上传** @param file MultipartFile* @param bucketName bucketName* @param objectName objectName* @param minPartSize 每片大小,单位:字节(eg:5242880 <- 5m)*/public void uploadMultipartFileByPart(MultipartFile file, String bucketName, String objectName,int minPartSize) {if (file.isEmpty()) {log.error("file is empty");}// 计算分片大小long size = file.getSize();// 得到总共的段数,和 分段后,每个段的开始上传的字节位置List<Long> positions = Collections.synchronizedList(new ArrayList<>());long filePosition = 0;while (filePosition < size) {positions.add(filePosition);filePosition += Math.min(minPartSize, (size - filePosition));}if (log.isDebugEnabled()) {log.debug("总大小:{},分为{}段", size, positions.size());}// 创建一个列表保存所有分传的 PartETag, 在分段完成后会用到List<PartETag> partETags = Collections.synchronizedList(new ArrayList<>());// 第一步,初始化,声明下面将有一个 Multipart Upload// 设置文件类型ObjectMetadata metadata = new ObjectMetadata();metadata.setContentType(file.getContentType());InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName,objectName, metadata);InitiateMultipartUploadResult initResponse = this.initiateMultipartUpload(initRequest);if (log.isDebugEnabled()) {log.debug("开始上传");}//声明线程池ExecutorService exec = Executors.newFixedThreadPool(3);long begin = System.currentTimeMillis();try {// MultipartFile 转 FileFile toFile = multipartFileToFile(file);for (int i = 0; i < positions.size(); i++) {int finalI = i;exec.execute(() -> {long time1 = System.currentTimeMillis();UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(bucketName).withKey(objectName).withUploadId(initResponse.getUploadId()).withPartNumber(finalI + 1).withFileOffset(positions.get(finalI)).withFile(toFile).withPartSize(Math.min(minPartSize, (size - positions.get(finalI))));// 第二步,上传分段,并把当前段的 PartETag 放到列表中partETags.add(this.uploadPart(uploadRequest).getPartETag());if (log.isDebugEnabled()) {log.debug("第{}段上传耗时:{}", finalI + 1, (System.currentTimeMillis() - time1));}});}//任务结束关闭线程池exec.shutdown();//判断线程池是否结束,不加会直接结束方法while (true) {if (exec.isTerminated()) {break;}}// 第三步,完成上传,合并分段CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucketName,objectName,initResponse.getUploadId(), partETags);this.completeMultipartUpload(compRequest);//删除本地缓存文件if (toFile != null && !toFile.delete()) {log.error("Failed to delete cache file");}} catch (Exception e) {this.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, objectName,initResponse.getUploadId()));log.error("Failed to upload, " + e.getMessage());}if (log.isDebugEnabled()) {log.debug("总上传耗时:{}", (System.currentTimeMillis() - begin));}}/*** 根据文件前置查询文件集合** @param bucketName bucket名称* @param prefix 前缀* @param recursive 是否递归查询* @return S3ObjectSummary 列表* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS* API Documentation</a>*/@SneakyThrowspublic List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix,boolean recursive) {ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);return new ArrayList<>(objectListing.getObjectSummaries());}/*** 查询文件版本** @param bucketName bucket名称* @return S3ObjectSummary 列表* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS* API Documentation</a>*/@SneakyThrowspublic List<S3VersionSummary> getAllObjectsVersionsByPrefixV2(String bucketName,String objectName) {VersionListing versionListing = amazonS3.listVersions(bucketName, objectName);return new ArrayList<>(versionListing.getVersionSummaries());}/*** 获取文件外链** @param bucketName bucket名称* @param objectName 文件名称* @param expires 过期时间 <=7 单位天* @return url*/@SneakyThrowspublic String generatePresignedUrl(String bucketName, String objectName, Integer expires) {Date date = new Date();Calendar calendar = new GregorianCalendar();calendar.setTime(date);calendar.add(Calendar.DAY_OF_MONTH, expires);URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());return url.toString();}/*** 开放链接,默认public没有设置访问权限* url 规则:${endPoint}/${bucketName}/${objectName}** @param bucketName* @param objectName* @return*/public String generatePublicUrl(String bucketName, String objectName) {return s3Properties.getEndpoint() + "/" + bucketName + "/" + objectName;}/*** 初始化,声明有一个Multipart Upload** @param initRequest 初始化请求* @return 初始化返回*/private InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest initRequest) {return amazonS3.initiateMultipartUpload(initRequest);}/*** 上传分段** @param uploadRequest 上传请求* @return 上传分段返回* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart">AWS* API Documentation</a>*/private UploadPartResult uploadPart(UploadPartRequest uploadRequest) {return amazonS3.uploadPart(uploadRequest);}/*** 分段合并** @param compRequest 合并请求* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload">AWS* API Documentation</a>*/private CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest compRequest) {return amazonS3.completeMultipartUpload(compRequest);}/*** 中止分片上传** @param uploadRequest 中止文件上传请求* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload">AWS* API Documentation</a>*/private void abortMultipartUpload(AbortMultipartUploadRequest uploadRequest) {amazonS3.abortMultipartUpload(uploadRequest);}/*** MultipartFile 转 File*/private File multipartFileToFile(MultipartFile file) throws Exception {File toFile = null;if (file.equals("") || file.getSize() <= 0) {file = null;} else {InputStream ins = null;ins = file.getInputStream();toFile = new File(file.getOriginalFilename());//获取流文件OutputStream os = new FileOutputStream(toFile);int bytesRead = 0;byte[] buffer = new byte[8192];while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {os.write(buffer, 0, bytesRead);}os.close();ins.close();}return toFile;}
}
测试方法
package com.xx.awss3demo;import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.liuqi.awss3demo.service.S3FileService;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;@SpringBootTest
@Log4j2
class AwsS3DemoApplicationTests {@Autowiredprivate S3FileService s3FileService;public String bk="lqs3bucket";@Testvoid contextLoads() {}@Testpublic void bucketTest() {s3FileService.createBucket(bk);s3FileService.getAllBuckets().forEach(b -> System.out.println(b.getName()));s3FileService.removeBucket(bk);}@Testpublic void objectTest() throws IOException {s3FileService.createBucket(bk);if (s3FileService.checkObjectExist(bk, "d1/ss/1.txt")) {log.info("文件已经存在");}s3FileService.putObject(bk,"d1/ss/1.txt",new ByteArrayInputStream("hello world xxx".getBytes(StandardCharsets.UTF_8)));s3FileService.copyObject(bk,"d1/ss/1.txt","d1/ss/1_copy.txt");S3Object object = s3FileService.getObject(bk, "d1/ss/1_copy.txt");byte[] bytes = object.getObjectContent().readAllBytes();log.info("内容是:{}",new String(bytes,StandardCharsets.UTF_8));//s3FileService.deleteObject(bk,"1.txt");}@Testpublic void listTest(){List<S3ObjectSummary> objectList = s3FileService.getAllObjectsByPrefix(bk, "/d1", true);objectList.forEach(object->{log.info(object.getKey());});}@Testpublic void genUrlTest(){String s = s3FileService.generatePresignedUrl(bk, "1.txt", 7);System.out.println(s);}}
相关文章:

AWS S3 协议对接 minio/oss 等
使用亚马逊 S3 协议访问对象存储 [s3-API](https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_Operations_Amazon_Simple_Storage_Service.html)- 兼容S3协议的对象存储有- minio- 似乎是完全兼容 [兼容文档](https://www.minio.org.cn/product/s3-compatibility.htm…...

手机便签内容不见了怎么恢复正常?
在日常生活和工作中,很多人都需要随手记录事情,例如家庭琐事、孩子相关的事情、指定时间需要完成的工作任务、会议安排等。当我们需要随时随地记录事情的时候,手机便签应用就是非常不多的选择,我们直接打开手机上的便签APP就可以新…...

【架构】Java 系统架构演进的思考
文章目录 1 前言2 单体应用架构3 垂直应用架构4 分布式架构5 SOA 架构6 微服务云架构7 总结 1 前言 随着移动互联的发展,网站、H5、移动端的应用规模也不断扩大,不管是应用的数量还是质量都得到了指数级的提升。开发者的数量与日俱增,应用的…...

Python爬虫——解析_jsonpath
jsonpath的安装 pip install jsonpathjsonpath的使用: obj json.load(open(json文件, r, encodingutf-8)) ret jsonpath.jsonpath(obj, jsonpath语法)json文件: { "store": {"book": [{ "category": "末世"…...

华为发布数字资产继承功能
在华为开发者大会2023(HDC.Together)上,华为常务董事、终端BG CEO、智能汽车解决方案BU CEO余承东正式发布了数字资产继承功能,HarmonyOS提供了安全便捷的数字资产继承路径。 在鸿蒙世界中,我们每个人在每台设备、应用…...

阿里云NAS文件存储基本介绍与购买使用
文章目录 1.NAS文件存储基本概念1.1.什么是NAS文件存储1.2.NAS的应用场景1.3.NAS、OSS、EBS的区别 2.购买NAS文件存储2.1.开通NAS服务2.2.创建NAS文件系统2.3.配置NAS文件系统属性2.4.查看购买的NAS服务 3.NAS文件存储基本使用3.1.修改NAS文件系统默认的名称3.2.NAS的权限组3.3…...

大模型使用——超算上部署LLAMA-2-70B-Chat
大模型使用——超算上部署LLAMA-2-70B-Chat 前言 1、本机为Inspiron 5005,为64位,所用操作系统为Windos 10。超算的操作系统为基于Centos的linux,GPU配置为A100,所使用开发环境为Anaconda。 2、本教程主要实现了在超算上部署LLAM…...

机器学习笔记:李宏毅ChatGPT课程1:刨析ChatGPT
ChatGPT——Chat Generative Pre-trained Transformer 1 文字接龙 每次输出一个概率分布,根据概率sample一个答案 ——>因为是根据概率采样,所以ChatGPT每次的答案是不一样的(把生成式学习拆分成多个分类问题)将生成的答案加到…...

Llama 2 with langchain项目详解(三)
Llama 2 with langchain项目详解(三) 17.3 Llama 2 with langchain基础 本节讲解在LangChain中使用Llama 2模型的基础知识,展示如何运行LangChain的代码,及在云端运行Llama 2的700亿模型。 首先,使用Python的pip管理器安装一系列库,包括huggingface/transformers、datase…...

牛客 AB30 排序(快排模板)
描述 给定一个长度为 n 的数组,请你编写一个函数,返回该数组按升序排序后的结果。 数据范围: 0≤�≤11030≤n≤1103,数组中每个元素都满足 0≤���≤1090≤val≤109 要求࿱…...

【Linux旅行记】第一个小程序“进度条“!
文章目录 一、预备知识1.1回车换行1.2缓冲区 二、倒计时三、进度条3.1普通版本源代码3.2高级版本源代码 🍀小结🍀 🎉博客主页:小智_x0___0x_ 🎉欢迎关注:👍点赞🙌收藏✍️留言 &…...

DeepMind将AI用于可控核聚变:将等离子体形状模拟精度提高65%
近日,英国AI公司DeepMind宣布取得了一项新的突破,成功实现了AI可控核聚变。这一技术能够在高温等离子体环境下实现精准放电,为核聚变技术的发展提供了新的思路和创新。 长期以来,相关领域的科学家们,一直在寻找清洁、取…...

Scrum是什么意思,Scrum敏捷项目管理工具有哪些?
一、什么是Scrum? Scrum是一种敏捷项目管理方法,旨在帮助团队高效地开展软件开发和项目管理工作。 Scrum强调迭代和增量开发,通过将项目分解为多个短期的开发周期(称为Sprint),团队可以更好地应对需求变…...

【从零单排Golang】第十三话:使用WaitGroup等待多路并行的异步任务
在后端开发当中,经常会遇到这样的场景:请求给了批量的输入,对于每一个输入,我们都要给外部发请求等待返回,然后才能继续其它自己的业务逻辑。在这样的case下,如果每一个输入串行处理的话,那么很…...

WSL2安装CentOS7和CentOS8
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、下载ZIP包?二、安装1.打开Windows子系统支持2.安装到指定位置3.管理虚拟机4.配置虚拟机1.配置国内源2.安装软件3.安装第三方源 5.配置用户1.创建…...

不平衡电网条件下基于变频器DG操作的多目标优化研究(Matlab代码Simulink实现)
目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码&Simulink实现&文章讲解 💥1 概述 文献来源: 最近,利用并网转换器(GCC)克服电网故障并支撑电网电压已…...

【Leetcode】(自食用)简单题||单词数
step by step. 题目: 统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。 请注意,你可以假定字符串里不包括任何不可打印的字符。 示例: 输入: "Hello, my name is John" 输出: 5 解释: 这里的单词是指连续的不是空格…...

C语言代码的x86-64汇编指令分析过程记录
先通过Xcode创建一个terminal APP,语言选择C。代码如下: #include <stdio.h>int main(int argc, const char * argv[]) {int a[7]{1,2,3,4,5,6,7};int *ptr (int*)(&a1);printf("%d\n",*(ptr));return 0; } 在return 0处打上断点&…...

基于springboot+vue的房屋租赁系统(前后端分离)
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...

Python文件读写操作详解:从基础到高级
摘要:文件读写是Python编程中常见的操作之一。本文将介绍Python中文件读写的基础知识,包括打开文件、读取文件内容、写入文件、关闭文件等基本操作。此外,还将探讨一些高级文件读写技术,如使用上下文管理器、处理异常、使用with语…...

ThreadLocal基本介绍
文章目录 什么是ThreadLocalThreadLocal解决了什么问题ThreadLocal的作用 ThreadLocal的使用场景ThreadLocal的代码示例ThreadLocal的优点ThreadLocal的缺点与volatile、synchronized、ThreadLocal比较 总结 什么是ThreadLocal ThreadLocal是Java中的一个线程本地变量…...

ffmpeg源码编译成功,但是引用生成的静态库(.a)报错,报错位置在xxx_list.c,报错信息为某变量未定义
背景:本文是对上一个文章的补充,在源码编译之前,项目是有完整的ffmpeg编译脚本的,只不过新增了断点调试ffmpeg,所以产生的上面的文章,也就是说,我在用make编译成功后,再去做的源码编…...

2023爱分析·信创云市场厂商评估报告:中国电子云
01 研究范围定义 信创2.0时代开启,信创进程正在从局部到全面、从细分到所有领域延展。在这个过程中,传统的系统集成,也在逐步向信创化、数字化及智能化转变。随着信创产业的发展,企业需要更多的技术支持和服务,而传统的系统集成已…...

网络安全学习笔记——XFF攻击流程
手工注入 手动报错注入,填写格式如:X-Forwarded-For: and updatexml(1,concat(0x7e,(select database()),0x7e),1) or 11 库名 1 and updatexml(1,concat(0x7e,database(),0x7e),1), 表名 1 and updatexml(1,concat(0x7e,(select table_name from…...

微信小程序阻止用户返回上一页,并弹窗给用户确定是否要返回上一页
在onload中调用微信的enableAlertBeforeUnload方法,在首次进入会自动监听当前的页面,在返回的时候会自动弹出弹窗阻止用户返回上一页,点击确定则返回上一页,取消则停留在当前页 onLoad: function(){wx.enableAlertBeforeUnload({…...

LangChain+ChatGLM整合LLaMa模型(二)
开源大模型语言LLaMa LLaMa模型GitHub地址添加LLaMa模型配置启用LLaMa模型 LangChainChatGLM大模型应用落地实践(一) LLaMa模型GitHub地址 git lfs clone https://huggingface.co/huggyllama/llama-7b添加LLaMa模型配置 在Langchain-ChatGLM/configs/m…...

【NLP】训练chatglm2的评价指标BLEU,ROUGE
当进行一定程度的微调后,要评价模型输出的语句的准确性。由于衡量的对象是一个个的自然语言文本,所以通常会选择自然语言处理领域的相关评价指标。这些指标原先都是用来度量机器翻译结果质量的,并且被证明可以很好的反映待评测语句的准确性&a…...

java+springboot+mysql员工工资管理系统
项目介绍: 使用javaspringbootmysql开发的员工工资管理系统,系统包含超级管理员,系统管理员、员工角色,功能如下: 超级管理员:管理员管理;部门管理;员工管理;奖惩管理&…...

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版
FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版是一个完整的软件音乐制作环境或数字音频工作站(DAW)。它代表了 25 多年的创新发展,将您创作、编曲、录…...

探索Python数据容器之乐趣:列表与元组的奇妙旅程!
文章目录 零 数据容器入门一 数据容器:list(列表)1.1 列表的定义1.2 列表的下表索引1.3 列表的常用操作1.3.1 列表的查询功能1.3.2 列表的修改功能1.3.3 列表常用方法总结 1.4 补充:append与extend对比1.5 list(列表)的遍历1.6 补…...