Minio工作类MinioUtils的配置及使用示例

依赖
        <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.3</version></dependency>
配置项
minio:url: http://localhost:9000accessKey: exampleAccessKeysecretKey: exampleSecretKeybucket: exampleBucketaccessUrl: http://localhost:9000/exampleBucket
配置属性绑定
@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {private String url;private String accessKey;private String secretKey;private String bucket;private String accessUrl;
}
工具类:
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;/*** @Author: Cookie* @Description: Minio工具类*/
@Slf4j
public class MinioUtils {private static MinioClient minioClient;private static String endpoint;private static String accessKey;private static String secretKey;private static final String SEPARATOR = "/";private MinioUtils() {}public MinioUtils(String endpoint, String accessKey, String secretKey) {MinioUtils.endpoint = endpoint;MinioUtils.accessKey = accessKey;MinioUtils.secretKey = secretKey;createMinioClient();}/*** 创建minioClient*/public void createMinioClient() {try {if (null == minioClient) {minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();System.err.println("创建Minio通道成功!");}} catch (Exception e) {System.err.println("创建Minio通道失败!");}}/*** 获取上传文件的基础路径** @return url*/public static String getBasisUrl(String bucketName) {return endpoint + SEPARATOR + bucketName + SEPARATOR;}/*** 验证bucketName是否存在** @return boolean true:存在*/public static boolean bucketExists(String bucketName)throws Exception {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/*** 创建bucket** @param bucketName bucket名称*/public static void createBucket(String bucketName)throws Exception {if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}}/*** 获取全部bucket*/public static List<Bucket> getAllBuckets() throws Exception {return minioClient.listBuckets();}/*** 根据bucketName获取信息** @param bucketName bucket名称*/public static Optional<Bucket> getBucket(String bucketName) throws Exception {return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}/*** 根据bucketName删除信息** @param bucketName bucket名称*/public static void removeBucket(String bucketName) throws Exception {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/*** 判断文件是否存在** @param bucketName 存储桶* @param objectName 对象* @return true:存在*/public static boolean doesObjectExist(String bucketName, String objectName) {boolean exist = true;try {minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());} catch (Exception e) {exist = false;}return exist;}/*** 判断文件夹是否存在** @param bucketName 存储桶* @param objectName 文件夹名称(去掉/)* @return true:存在*/public static boolean doesFolderExist(String bucketName, String objectName) {boolean exist = false;try {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());for (Result<Item> result : results) {Item item = result.get();if (item.isDir() && objectName.equals(item.objectName())) {exist = true;}}} catch (Exception e) {exist = false;}return exist;}/*** 根据文件前置查询文件** @param bucketName bucket名称* @param prefix     前缀* @param recursive  是否递归查询* @return MinioItem 列表*/public static List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws Exception {List<Item> list = new ArrayList<>();Iterable<Result<Item>> objectsIterator = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());if (objectsIterator != null) {for (Result<Item> o : objectsIterator) {Item item = o.get();list.add(item);}}return list;}/*** 通过MultipartFile,上传文件** @param bucketName  存储桶* @param file        文件* @param objectName  对象名* @param contentType 文件类型*/public static ObjectWriteResponse putObject(String bucketName, MultipartFile file, String objectName, String contentType) throws Exception {InputStream inputStream = file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType).stream(inputStream, inputStream.available(), -1).build());}/*** 通过MultipartFile,上传文件** @param bucketName 存储桶* @param file       文件* @param objectName 对象名*/public static ObjectWriteResponse putObject(String bucketName, MultipartFile file, String objectName) throws Exception {InputStream inputStream = file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());}/*** 上传本地文件** @param bucketName 存储桶* @param objectName 对象名称* @param filePath   文件路径(网络)*/public static ObjectWriteResponse putObject(String bucketName, String objectName, String filePath)throws Exception {URLConnection urlConnection = new URL(filePath).openConnection();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(urlConnection.getContentType()).stream(urlConnection.getInputStream(), urlConnection.getContentLength(), -1).build());}/*** 连接参数** @param bucketName  存储桶* @param fileAbsName 文件绝对路径* @param connection  链接对象* @return* @throws Exception*/public static ObjectWriteResponse putObject(String bucketName, String fileAbsName, URLConnection connection) throws Exception {InputStream inputStream = connection.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileAbsName).contentType(connection.getContentType()).stream(inputStream, inputStream.available(), -1).build());}/*** 通过流上传文件** @param bucketName  存储桶* @param objectName  文件对象* @param inputStream 文件流*/public static ObjectWriteResponse putObject(String bucketName, String objectName,InputStream inputStream)throws Exception {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());}/*** 创建文件夹或目录** @param bucketName 存储桶* @param objectName 目录路径*/public static ObjectWriteResponse putDirObject(String bucketName, String objectName)throws Exception {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());}/*** 拷贝文件** @param bucketName    bucket名称* @param objectName    文件名称* @param srcBucketName 目标bucket名称* @param srcObjectName 目标文件名称*/public static ObjectWriteResponse copyObject(String bucketName, String objectName,String srcBucketName, String srcObjectName)throws Exception {return minioClient.copyObject(CopyObjectArgs.builder().source(CopySource.builder().bucket(bucketName).object(objectName).build()).bucket(srcBucketName).object(srcObjectName).build());}/*** 文件下载** @param bucketName 桶名称* @param request    请求* @param response   请求响应*/public static void downloadFile(String bucketName, String originalName,HttpServletRequest request,HttpServletResponse response) {try {InputStream file = getObject(bucketName, originalName);//文件名乱码处理String useragent = request.getHeader("USER-AGENT").toLowerCase();if (useragent.contains("msie") || useragent.contains("like gecko") || useragent.contains("trident")) {originalName = URLEncoder.encode(originalName, StandardCharsets.UTF_8.displayName());} else {originalName = new String(originalName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);}response.setCharacterEncoding("UTF-8");response.setHeader("Content-Disposition", "attachment;filename=" + originalName);ServletOutputStream servletOutputStream = response.getOutputStream();int len;byte[] buffer = new byte[1024];while ((len = file.read(buffer)) > 0) {servletOutputStream.write(buffer, 0, len);}servletOutputStream.flush();file.close();servletOutputStream.close();} catch (Exception e) {System.err.println(String.format("下载文件:%s异常", originalName));}}/*** 获取文件流** @param bucketName bucket名称* @param objectName 文件名称* @return 二进制流*/public static InputStream getObject(String bucketName, String objectName) throws Exception {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 断点下载** @param bucketName bucket名称* @param objectName 文件名称* @param offset     起始字节的位置* @param length     要读取的长度* @return 流*/public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length).build());}/*** 获取路径下文件列表** @param bucketName bucket名称* @param prefix     文件名称* @param recursive  是否递归查找,如果是false,就模拟文件夹结构查找* @return 二进制流*/public static Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());}/*** 获取路径下文件列表** @param bucketName bucket名称* @param recursive  是否递归查找,如果是false,就模拟文件夹结构查找* @return 二进制流*/public static Iterable<Result<Item>> listObjects(String bucketName, boolean recursive) {return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(recursive).build());}/*** 删除文件** @param bucketName bucket名称* @param objectName 文件名称*/public static void removeObject(String bucketName, String objectName)throws Exception {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 批量删除文件** @param bucketName bucket* @param keys       需要删除的文件列表*/public static void removeObjects(String bucketName, List<String> keys) {List<DeleteObject> objects = new LinkedList<>();keys.forEach(s -> {objects.add(new DeleteObject(s));try {removeObject(bucketName, s);} catch (Exception e) {System.err.println("批量删除失败!");}});}/*** 生成预览链接,最大7天有效期;* 如果想永久有效,在 minio 控制台设置仓库访问规则总几率** @param object      文件名称* @param contentType 预览类型 image/gif", "image/jpeg", "image/jpg", "image/png", "application/pdf* @param validTime   有效时间 不能超过7天* @param timeUnit    单位 时 分 秒 天* @return java.lang.String**/public static String getPreviewUrl(String bucketName, String object, String contentType, Integer validTime, TimeUnit timeUnit) {Map<String, String> reqParams = null;if (contentType != null) {reqParams = new HashMap<>();reqParams.put("response-content-type", contentType != null ? contentType : "application/pdf");}String url = null;try {url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(object).expiry(validTime, timeUnit).extraQueryParams(reqParams).build());} catch (Exception e) {e.printStackTrace();}return url;}/*** Description 文件列表** @param limit 范围 1-1000**/public List<Item> listObjects(int limit, String bucketName) {List<Item> objects = new ArrayList<>();Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).maxKeys(limit).includeVersions(true).build());try {for (Result<Item> result : results) {objects.add(result.get());}} catch (Exception e) {e.printStackTrace();}return objects;}/*** Description 网络文件转储 minio** @param httpUrl 文件地址**/public static void netToMinio(String httpUrl, String bucketName) {int i = httpUrl.lastIndexOf(".");String substring = httpUrl.substring(i);URL url;try {url = new URL(httpUrl);URLConnection urlConnection = url.openConnection();// agent 模拟浏览器urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");DataInputStream dataInputStream = new DataInputStream(url.openStream());// 临时文件转储File tempFile = File.createTempFile(UUID.randomUUID().toString().replace("-", ""), substring);FileOutputStream fileOutputStream = new FileOutputStream(tempFile);ByteArrayOutputStream output = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = dataInputStream.read(buffer)) > 0) {output.write(buffer, 0, length);}fileOutputStream.write(output.toByteArray());// 上传minioputObject(bucketName, tempFile.getAbsolutePath(), tempFile.getName());dataInputStream.close();fileOutputStream.close();} catch (Exception e) {e.printStackTrace();}}/*** Description 文件转字节数组** @param path 文件路径* @return byte[] 字节数组**/public byte[] fileToBytes(String path) {FileInputStream fis = null;ByteArrayOutputStream bos = null;try {bos = new ByteArrayOutputStream();fis = new FileInputStream(path);int temp;byte[] bt = new byte[1024 * 10];while ((temp = fis.read(bt)) != -1) {bos.write(bt, 0, temp);}bos.flush();} catch (IOException e) {e.printStackTrace();} finally {try {if (Objects.nonNull(fis)) {fis.close();}} catch (IOException e) {e.printStackTrace();}}return bos.toByteArray();}/*** 将URLDecoder编码转成UTF8*/public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");return URLDecoder.decode(url, "UTF-8");}/*** 下载并压缩 Minio 桶中的文件,并通过 HTTP 响应输出** @param bucketName 桶名称* @param response   HTTP 响应对象*/public static void downloadMinioFileToZip(String bucketName, HttpServletResponse response) {downloadMinioFileToZip(bucketName, "", response);}/*** 下载并压缩 Minio 桶中的文件,并通过 HTTP 响应输出** @param bucketName 桶名称* @param folderPath 文件夹路径(可为空)* @param response   HTTP 响应对象*/public static void downloadMinioFileToZip(String bucketName, String folderPath, HttpServletResponse response) {try {// 如果 folderPath 为空,列出整个桶中的文件if (folderPath == null || folderPath.isEmpty()) {// 根目录folderPath = "";}// 设置 HTTP 响应头response.setContentType("application/zip");response.setHeader("Content-Disposition", "attachment;filename=" + bucketName + ".zip");// 创建 ZipOutputStream,将文件写入 response 的输出流try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {// 列出文件夹中的所有对象Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(folderPath).recursive(true).build());// 下载并压缩文件夹中的所有对象for (Result<Item> result : results) {Item item = result.get();String objectName = item.objectName();log.info("找到对象: {}", objectName);// 跳过目录对象,确保只处理实际文件if (objectName.endsWith("/")) {continue;}// 为每个对象创建一个新的 ZipEntry(压缩包中的文件条目)ZipEntry zipEntry = new ZipEntry(objectName);zipOut.putNextEntry(zipEntry);// 从 MinIO 获取对象输入流try (InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build())) {// 将文件数据写入压缩包byte[] buf = new byte[8192];int bytesRead;while ((bytesRead = stream.read(buf)) != -1) {zipOut.write(buf, 0, bytesRead);}// 关闭当前文件条目zipOut.closeEntry();log.info("文件压缩成功: {}", objectName);} catch (Exception e) {log.error("下载并压缩文件时发生错误: {}", e.getMessage(), e);}}log.info("所有文件已成功压缩并通过响应输出。");} catch (IOException e) {log.error("创建压缩包时发生错误: {}", e.getMessage(), e);}} catch (MinioException | InvalidKeyException | NoSuchAlgorithmException e) {log.error("发生错误: {}", e.getMessage(), e);}}}
配置类:
import com.saas.iot.utils.MinioUtils;
import io.minio.MinioClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.annotation.Resource;@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {@Resourceprivate MinioProperties minioProperties;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(minioProperties.getUrl()).credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()).build();}@Beanpublic MinioUtils creatMinioClient() {return new MinioUtils(minioProperties.getUrl(), minioProperties.getAccessKey(), minioProperties.getSecretKey());}}
测试接口实现类:
请求接口:
    /*** 文件上传请求*/@PostMapping("upload")@ApiOperation("文件上传")public R upload(MultipartFile file) {return R.ok(sysFileService.uploadFile(file));}
服务层接口方法:
    /*** 文件上传接口** @param file 上传的文件* @return 访问地址* @throws Exception*/String uploadFile(MultipartFile file) throws Exception;
实现方法:
    @Overridepublic String uploadFile(MultipartFile file) throws Exception {if (file.isEmpty() || file.getSize() <= 0 || StrUtil.isBlank(file.getOriginalFilename())) {throw new RuntimeException("上传文件不能为空");}String originalFilename = file.getOriginalFilename();// 定义支持格式文件String[] defaultAllowedExtension = MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION;Set<String> typeSet = new HashSet<>(Arrays.asList(defaultAllowedExtension));originalFilename = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);if (!typeSet.contains(originalFilename)){throw new RuntimeException("文件格式不支持");            }ObjectWriteResponse response = MinioUtils.putObject(minioConfig.getBucket(), file, getFileName(originalFilename), file.getContentType());return minioConfig.getAccessUrl() + minioConfig.getBucket() + "/" + response.object();}/*** 自定义文件名称*/private String getFileName(String suffix) {// 不同的后缀分为一组 data/local/jpg/xxx.jpgreturn "data/local/" + suffix + "/" + IdUtil.getSnowflake() + "." + suffix;}
定义系统允许文件类型:
    public static final String[] DEFAULT_ALLOWED_EXTENSION = {// 图片"bmp", "gif", "jpg", "jpeg", "png",// word excel powerpoint"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",// 压缩文件"rar", "zip", "gz", "bz2",//升级文件"bin", "apk", "ipa",// 视频格式"mp4", "avi", "rmvb",// 矢量文件"tif",// pdf"pdf" };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466136.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EV录屏好用吗?盘点2024年10款专业好用的录屏软件。

EV录屏的方式有很多种&#xff0c;它设置了很多模式&#xff0c;并且录制高清&#xff0c;可以免费使用。但是现在很多的录屏工具都有着与这个软件相似的功能&#xff0c;在这里我可以给大家列举一些。 1、福昕电脑录屏 这个软件为用户提供了多种录制模式&#xff0c;让视频录…

【网易云插件】听首歌放松放松

先看效果&#xff1a; 网易云有两种类似的插件。 第一种 &#xff1a; iframe 优点&#xff1a;可以自己调整插件的高度、宽度 缺点&#xff1a;很多博客网站不支持嵌入iframe&#xff0c;请试一下您的网站是否支持 登录可直接复制代码。 也可以在我这里 <iframe fram…

Java的Object类常用的方法(详述版本)

文章目录 一、什么是Object类二、常用方法&#xff1a;toString&#xff08;&#xff09;三、常用方法&#xff1a;对象比较equals&#xff08;&#xff09;四、常用方法&#xff1a;hashcode&#xff08;&#xff09;五、总结 一、什么是Object类 顾名思义&#xff0c;Object类…

SQL--查询连续三天登录数据详解

问题&#xff1a; 现有用户登录记录表&#xff0c;请查询出用户连续三天登录的所有数据记录 id dt1 2024-04-25 1 2024-04-26 1 2024-04-27 1 2024-04-28 1 2024-04-30 1 2024-05-01 1 2024-05-02 1 2024-05-04 1 2024-05-05 2 20…

docker+mysql配置

拉取mysql docker pull mysqlmysql配置 创建存储文件夹 mkdir -p /home/mysql/{date,conf}在conf文件中配置my.cnf sudo vim my.cnfmy.cnf具体配置 [mysqld] #Mysql服务的唯一编号 每个mysql服务Id需唯一 server-id1#服务端口号 默认3306 port3306#mysql安装根目录&#x…

qt QHeaderView详解

1、概述 QHeaderView 是 Qt 框架中的一个类&#xff0c;它通常作为 QTableView、QTreeView 等视图类的一部分&#xff0c;用于显示和管理列的标题&#xff08;对于水平头&#xff09;或行的标题&#xff08;对于垂直头&#xff09;。QHeaderView 提供了对这些标题的排序、筛选…

删除 需要来自XXXX的权限才能对此文件夹进行更改 文件的解决办法

如果你也是&#xff1a; 如果你也有类似上面的问题&#xff0c;这篇文章算是你看对了&#xff0c;哦哟&#xff01; 我的牙齿现在是怨灵的牙齿&#xff0c;可以啃下一头牛。 翻遍千山万水&#xff0c;咱们也是终于取到真经了家人们。 首先下一个everything好吗 甩一个官网链…

题目练习之二叉树那些事儿(续集)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ 这一篇博客我们继…

本地Docker部署ZFile网盘打造个人云存储,告别公共网盘让你数据安全感爆棚

文章目录 前言1.关于ZFile2.本地部署ZFile3.ZFile本地访问测试4.ZFile的配置5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定ZFile公网地址 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker本地部署ZFile文件管理系统&#xff0c;并结合cpolar内网穿透工具实现远程…

职场逆袭!学会管理上司,你也能成为职场赢家

书友们&#xff0c;不要错过了&#xff01;我挖到了一本真正让我彻夜难眠的小说&#xff0c;情节跌宕起伏&#xff0c;角色鲜活得就像从书里跳出来陪你聊天。每一页都是新的惊喜&#xff0c;绝对让你欲罢不能。要是你也在寻找那种让人上瘾的阅读体验&#xff0c;这本书就是你的…

LangChain Ollama实战文献检索助手(三)思维链COT、思维树TOT和思维网NOT

大模型的思考方式有时候并不尽人意。我们可以在提示词中引导大模型如何拆分任务&#xff0c;按部就班地思考。 一、思维链 思维链是引导模型一步一步地思考&#xff0c;分为Zero-Shot CoT和Few-Shot CoT。Zero-Shot CoT就是著名的Let’s think step by step。Few-Shot CoT是对…

ASP页面改为UTF-8编码后,刷新页面不定时中文输出乱码终极解决方案

IIS7下的ASP页面&#xff0c;改为Utf-8编码后&#xff0c;Html部分的中文显示正常&#xff0c;但是由 Response.Write 输出的中文字符&#xff0c;在不特定的时间会变成乱码&#xff0c;一开始以为是浏览器问题&#xff0c;测试了多个浏览器故障依旧不定时出现&#xff1a; &l…

Spring底层源码(一)

Spring的入门代码&#xff1a; public class XmlTest {public static void main(String[] args) {//构造一个容器.ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext("springTest.xml");//从容器中获取Bean对象UserService userService …

理解Web登录机制:会话管理与跟踪技术解析(二)-JWT令牌

JWT令牌是一种用于安全地在各方之间传递信息的开放标准&#xff0c;它不仅能够验证用户的身份&#xff0c;还可以安全地传递有用的信息。由于其结构简单且基于JSON&#xff0c;JWT可以在不同的系统、平台和语言间无缝传递&#xff0c;成为现代Web开发中不可或缺的一部分。 文章…

SpringBoot源码解析(二):引导上下文DefaultBootstrapContext

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext 目录 前言一、入口二、DefaultBootstrapContext1、BootstrapRegistry接口2、BootstrapContext接口3、DefaultBo…

运维高可用架构设计

一、硬件 1、服务器 2、网络架构 二、软件 1、基础组件 组件名称 高可用方式 最少节点数 负载均衡(Tenginx) corsyncpacemaker互为主备 多组集群通过DNS轮循实现一个大集群 2DNS主从集群2RabbitMQ原生HA镜像集群3Zookeeper原生分布式集群3Kafka原生分布式集群3ES原生分布式集…

C++之vector类的模拟实现

片头 嗨~小伙伴们&#xff0c;今天我们来一起学习关于C的vector类的模拟实现&#xff0c;准备好了吗&#xff1f;咱们开始咯~ 一、基本框架 namespace bit {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;// 针对const修…

MyBatis 返回 Map 或 List<Map>时,时间类型数据,默认为LocalDateTime,响应给前端默认含有‘T‘字符

一、问题 MyBatis 返回 Map 或 List时&#xff0c;时间类型数据&#xff0c;默认为LocalDateTime Springboot 响应给前端的LocalDateTime&#xff0c;默认含有’T’字符&#xff0c;如何统一配置去掉 二、解决方案 1、pom.xml 增加依赖&#xff08;2024.11.6 补充&#xff…

数据结构之二叉树前序,中序,后序习题分析(递归图)

1.比较相同的树 二叉树不能轻易用断言&#xff0c;因为树一定有空 2.找结点值 3.单值二叉树 4.对称二叉树 5.前序遍历

如何使用gewe开发微信机器人

[Gewe](微信管理系统)&#xff0c;个人微信**开源框架&#xff0c;支持二次开发、任意语言都可接入&#xff0c;Restful API接入。 gewe框架优势&#xff1a; - 简单易用&#xff0c;无接入难度&#xff0c;区别于其它开源项目&#xff0c;本框架无需用户安装电脑微信&#x…