【微服务】springboot整合minio详解

news2024/11/24 16:48:38

目录

一、前言

二、Minio 概述

2.1 Minio简介

2.1 Minio特点

三、Minio 环境搭建

3.1 部署过程

3.1.1 拉取镜像

3.1.2 启动容器

3.1.3 访问web页面

四、Minio基本使用

4.1 基本概念

4.2 上传文件演示

4.3 用户管理

4.4 Java操作Minio

4.4.1 导入依赖

4.4.2 上传文件到minio

五、springboot整合Minio

5.1 前置准备

5.1.1 引入依赖

5.1.2 核心配置文件

5.2 编码过程

5.2.1 创建一个参数配置类

5.2.2 创建minio配置类

5.2.3 创建minio文件服务类或工具类

5.2.4 编写测试接口

5.2.5 接口测试

六、写在文末


一、前言

在很多互联网产品应用中,都涉及到各种与文件存储相关的业务,随着技术的发展,关于如何解决分布式文件存储也有了比较成熟的方案,比如私有云部署下可以考虑fastdfs,阿里云对象存储oss,七牛云等,本篇将为你介绍另一种文件存储方式,即MinIO 。

二、Minio 概述

2.1 Minio简介

MinIO基于Apache License v2.0开源协议的对象存储服务,可以做为云存储的解决方案用来保存海量的图片,视频,文档,是一款高性能、分布式的对象存储系统, 可以100%的运行在标准硬件,即X86等低成本机器也能够很好的运行MinIO。

传统的存储和其他的对象存储不同的是:

它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。

2.1 Minio特点

Minio具有如下特点

  • 性能高,准硬件条件下它能达到55GB/s的读、35GB/s的写速率;
  • 部署自带管理界面;
  • MinIO.Inc运营的开源项目,社区活跃度高;
  • 提供了所有主流开发语言的SDK;
  • 基于Golang语言实现,配置简单,单行命令可以运行起来;
  • 兼容亚马逊S3云存储服务接口,适合于存储大容量非结构化的数据,一个对象文件可以是任意大小,从几kb到最大5T不等;

三、Minio 环境搭建

本文采用docker的方式快速搭建起Minio的环境,也可以通过官网下载安装包部署,官网安装包下载地址

3.1 部署过程

3.1.1 拉取镜像

docker pull minio/minio

3.1.2 启动容器

docker run -d -p 9000:9000 -p 9090:9090 \
     --name minio \
     -e "MINIO_ACCESS_KEY=minio" \
     -e "MINIO_SECRET_KEY=minio" \
     -v /home/minio/data:/data \
     -v /home/minio/config:/root/.minio \
     minio/minio server \
     /data --console-address ":9090" -address ":9000"

3.1.3 访问web页面

容器启动成功后,注意开发相关的防火墙端口即可,然后访问地址:IP:9000,即可访问Minio的web界面

输入账户和密码,登录进去之后,看到下面的效果说明Minio环境搭建完成

四、Minio基本使用

4.1 基本概念

在正式开始使用Minio之前,有必要先了解下几个相关的概念

  • bucket ,类比于文件系统的目录;
  • Object ,类比文件系统的文件;
  • Keys ,类比文件名;

4.2 上传文件演示

如下,点击创建一个新的bucket,创建完成后就可以在列表上看到这个bucket;

给当前这个bucket上传一个文件

点击文件夹图标

上传一张本地文件,上传完成后就可以看到这个文件了,也可以浏览上传的文件

4.3 用户管理

针对客户端的操作,经常需要维护相关的账号来管理,比如账户的操作权限,访问控制等;

点击,创建用户

填写用户信息,勾选权限保存即可

然后在用户列表就可以看到这个用户了

4.4 Java操作Minio

通过上面的环境搭建和操作,演示并了解了如何快速使用Minio,更多的功能可以参阅相关资料进一步学习了解,下面我们编写java代码完成文件的上传。

4.4.1 导入依赖

在当前的maven工程中导入minio的依赖,客户端具体版本可以根据你的实际需要选择

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

4.4.2 上传文件到minio

通过下面这段代码将本地的一张图片文件上传到minio的test这个bucket目录下

public static void main(String[] args) {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream("F:\\网盘\\Title-logo.png");
            MinioClient client = MinioClient.builder().credentials("minio", "minio").endpoint("http://IP:9000").build();
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object("logo.png")
                    .contentType("image/png")
                    .bucket("test")
                    .stream(inputStream, inputStream.available(), -1)
                    .build();
            client.putObject(putObjectArgs);
            System.out.println("上传成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

运行这段代码,上传成功后,去到test的目录下刷新之后可以看到文件已经上传

五、springboot整合Minio

接下来让我们看看如何在springboot中集成Minio,参考下面的操作步骤

5.1 前置准备

5.1.1 引入依赖

创建一个maven工程,引入如下相关的依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>


    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

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

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

    </dependencies>

5.1.2 核心配置文件

在配置文件中添加如下内容

server:
  port: 8087

logging:
  level:
    root: info
    com.congge.model: debug

minio:
  username: minio
  pwd: minio
  bucket: test
  endpoint: http://IP:9000
  readPath: http://IP:9000

5.2 编码过程

5.2.1 创建一个参数配置类

通过这种方式将配置文件中以minio开头的那些配置加载到spring容器中管理,其他位置使用的时候直接注入即可

@Data
@ConfigurationProperties(prefix = "minio")
@Component
public class MinIOConfigProperties implements Serializable {

    private String username;
    private String pwd;
    private String bucket;
    private String endpoint;
    private String readPath;

}

5.2.2 创建minio配置类

通过这个全局的配置类,其他需要上传文件的类中直接注入MinioClient即可

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
public class MinIOConfig {

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    @Bean
    public MinioClient buildMinioClient() {
        return MinioClient
                .builder()
                .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                .endpoint(minIOConfigProperties.getEndpoint())
                .build();
    }
}

5.2.3 创建minio文件服务类或工具类

在日常开发中,可以自定义一个minio的工具类,使用的时候就比较方便了,下面的代码中列举了常用的一些API操作方法,可以结合实际需要自定义更多的工具方法


import com.congge.config.MinIOConfig;
import com.congge.config.MinIOConfigProperties;
import com.congge.service.MinioFileService;
import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Slf4j
@Import(MinIOConfig.class)
@Service
public class MinioFileServiceImpl implements MinioFileService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    private final static String separator = "/";

    /**
     * 下载文件
     *
     * @param pathUrl 文件全路径
     * @return 文件流
     */
    @Override
    public void downLoadFile(String pathUrl, HttpServletResponse response) {
        String[] pathItems = pathUrl.split("/");
        String originFileName = pathItems[pathItems.length - 1];
        String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", "");
        int index = key.indexOf(separator);
        //String bucket = key.substring(0,index);
        String filePath = key.substring(index + 1);
        InputStream inputStream = null;
        try {
            inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build());
            response.setHeader("Content-Disposition", "attachment;filename=" + originFileName);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            IOUtils.copy(inputStream, response.getOutputStream());
            System.out.println("下载成功");
        } catch (Exception e) {
            log.error("minio down file error.  pathUrl:{}", pathUrl);
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public String uploadFile(MultipartFile file) throws Exception {
        String bucketName = minIOConfigProperties.getBucket();
        String endpoint = minIOConfigProperties.getEndpoint();

        // 检查存储桶是否已经存在
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (isExist) {
            System.out.println("Bucket already exists.");
        } else {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
        String originalFilename = file.getOriginalFilename();
        //拼接生成新的UUID形式的文件名
        String objectName = new SimpleDateFormat("yyyy/MM/dd/").format(new Date()) +
                UUID.randomUUID().toString().replaceAll("-", "")
                + originalFilename.substring(originalFilename.lastIndexOf("."));

        PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
                .bucket(bucketName)
                .contentType(file.getContentType())
                .stream(file.getInputStream(), file.getSize(), -1).build();
        minioClient.putObject(objectArgs);
        //组装桶中文件的访问url
        String resUrl = endpoint + "/" + bucketName + "/" + objectName;
        return resUrl;
    }

    /**
     * 删除文件
     *
     * @param pathUrl 文件全路径
     */
    @Override
    public void delete(String pathUrl) {
        String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", "");
        int index = key.indexOf(separator);
        String bucket = key.substring(0, index);
        String filePath = key.substring(index + 1);
        // 删除Objects
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();
        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            log.error("minio remove file error.  pathUrl:{}", pathUrl);
            e.printStackTrace();
        }
    }

    public List<Bucket> listBuckets()
            throws Exception {
        return minioClient.listBuckets();
    }

    public boolean bucketExists(String bucketName) throws Exception {
        boolean flag = minioClient.bucketExists(bucketName);
        if (flag) {
            return true;
        }
        return false;
    }

    @Override
    public List<String> listBucketNames() throws Exception{
        List<Bucket> bucketList = listBuckets();
        List<String> bucketListName = new ArrayList<>();
        for (Bucket bucket : bucketList) {
            bucketListName.add(bucket.name());
        }
        return bucketListName;
    }

    @Override
    public boolean makeBucket(String bucketName) throws Exception{
        boolean flag = bucketExists(bucketName);
        if (!flag) {
            minioClient.makeBucket(bucketName);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean removeBucket(String bucketName) throws Exception{
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                // 有对象文件,则删除失败
                if (item.size() > 0) {
                    return false;
                }
            }
            // 删除存储桶,注意,只有存储桶为空时才能删除成功。
            minioClient.removeBucket(bucketName);
            flag = bucketExists(bucketName);
            if (!flag) {
                return true;
            }

        }
        return false;
    }

    @Override
    public List<String> listObjectNames(String bucketName) throws Exception{
        List<String> listObjectNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                listObjectNames.add(item.objectName());
            }
        }
        return listObjectNames;
    }

    @Override
    public boolean removeObject(String bucketName, String objectName) throws Exception{
        boolean flag = bucketExists(bucketName);
        if (flag) {
            List<String> objectList = listObjectNames(bucketName);
            for (String s : objectList) {
                if(s.equals(objectName)){
                    minioClient.removeObject(bucketName, objectName);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public String getObjectUrl(String bucketName, String objectName) throws Exception{
        boolean flag = bucketExists(bucketName);
        String url = "";
        if (flag) {
            url = minioClient.getObjectUrl(bucketName, objectName);
        }
        return url;
    }

    public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            return minioClient.listObjects(bucketName);
        }
        return null;
    }


}

5.2.4 编写测试接口

为了方便测试,下面定义了一个测试接口


import com.congge.service.MinioFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

@RestController
@Slf4j
public class FileController {

    @Autowired
    private MinioFileService minioFileService;

    /**
     * 上传文件
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping("/upload")
    public String upload(@RequestBody MultipartFile file) throws Exception {
        String url = minioFileService.uploadFile(file);
        return "文件上传成功,文件路径:" + url;
    }

    /**
     * 下载文件
     * @param pathUrl
     * @param response
     */
    @GetMapping("/download")
    public void download(@RequestParam("pathUrl") String pathUrl, HttpServletResponse response) {
        minioFileService.downLoadFile(pathUrl,response);
    }

    /**
     * 列出所有bucket名称
     * @return
     * @throws Exception
     */
    @PostMapping("/list/bucket")
    public List<String> list() throws Exception {
        return minioFileService.listBucketNames();
    }


    /**
     * 创建bucket
     * @param bucketName
     * @return
     * @throws Exception
     */
    @PostMapping("/create/bucket")
    public boolean createBucket(@RequestParam("bucketName")String bucketName) throws Exception {
        return minioFileService.makeBucket(bucketName);
    }

    /**
     * 删除bucket
     * @param bucketName
     * @return
     * @throws Exception
     */
    @PostMapping("/delete/bucket")
    public boolean deleteBucket(@RequestParam("bucketName")String bucketName) throws Exception {
        return minioFileService.removeBucket(bucketName);
    }

    /**
     * 列出bucket的所有对象名称
     * @param bucketName
     * @return
     * @throws Exception
     */
    @PostMapping("/list/object_names")
    public List<String> listObjectNames(@RequestParam("bucketName")String bucketName) throws Exception {
        return minioFileService.listObjectNames(bucketName);
    }

    /**
     * 删除bucket中的某个对象
     * @param bucketName
     * @param objectName
     * @return
     * @throws Exception
     */
    @PostMapping("/remove/object")
    public boolean removeObject(@RequestParam("bucketName")String bucketName,@RequestParam("objectName") String objectName) throws Exception {
        return minioFileService.removeObject(bucketName, objectName);
    }

    /**
     * 获取文件访问路径
     * @param bucketName
     * @param objectName
     * @return
     * @throws Exception
     */
    @PostMapping("/get/object/url")
    public String getObjectUrl(@RequestParam("bucketName")String bucketName, @RequestParam("objectName")String objectName) throws Exception {
        return minioFileService.getObjectUrl(bucketName, objectName);
    }

}

5.2.5 接口测试

上传文件测试

上传成功后,返回了文件的完整路径,方便后续使用

然后在控制台的test这个bucket中检查是否上传上去了

下载文件测试

使用上一步返回的url,直接调用下载接口,下载完成后可以直接预览

更多的接口有兴趣的同学可以一一尝试下,就不再赘述了。

六、写在文末

本文详细总结了Minio的搭建使用,以及与springboot整合的完整步骤,作为一款适用且轻量级的文件存储服务器,可以私有化部署,也可以很方便进行云上部署、容器化部署,为今后在实际项目中的技术选型提供一个参考,本篇到此结束,感谢观看。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法专题二:滑动窗口

算法专题二&#xff1a;滑动窗口 一.长度最小的子数组&#xff1a;1.思路一&#xff1a;暴力解法2.思路二&#xff1a;滑动窗口双指针3.GIF题目解析&#xff1a;思路一&#xff1a;思路二&#xff1a; 二.无重复字符的最长子串&#xff1a;1.思路一&#xff1a;滑动窗口2.GIF题…

【神器】wakatime代码时间追踪工具

文章目录 wakatime简介支持的IDE安装步骤API文档插件费用写在最后 wakatime简介 wakatime就是一个IDE插件&#xff0c;一个代码时间追踪工具。可自动获取码编码时长和度量指标&#xff0c;以产生很多的coding图形报表。这些指标图形可以为开发者统计coding信息&#xff0c;比如…

[C++从入门到精通] 14.虚函数、纯虚函数和虚析构(virtual)

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/weixin_43197380&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 Loewen丶原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&…

STM32_窗口看门狗

什么是窗口看门狗&#xff1f; 窗口看门狗用于监测单片机程序运行时效是否精准&#xff0c;主要检测软件异常&#xff0c;一般用于需要精准检测 程序运行时间的场合。 窗口看门狗的本质是一个能产生 系统复位信号 和 提前唤醒中断 的 6 位计数器 产生复位条件&#xff1a; 当…

推荐算法架构6:数据样本

1 整体架构 深度学习的数据样本决定了算法的上限&#xff0c;模型只是去不断逼近这个上限&#xff0c;可见数据样本对于深度学习的重要意义。与CV和NLP不同&#xff0c;推荐系统可以获取大量用户的浏览和点击等行为&#xff0c;很容易构造正负样本。例如&#xff0c;在精排点击…

瑞友天翼应用虚拟化系统 多处SQL 注入漏洞复现(可RCE)

0x01 产品简介 瑞友天翼应用虚拟化系统是西安瑞友信息技术资讯有限公司研发的具有自主知识产权,基于服务器计算架构的应用虚拟化平台。它将用户各种应用软件集中部署在瑞友天翼服务器(群)上,客户端通过WEB即可快速安全的访问经服务器上授权的应用软件,实现集中应用、远程接…

【MATLAB】数据拟合第13期-基于最小二乘支持向量机的拟合

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 基于最小二乘支持向量机的拟合算法是一种数学优化技术&#xff0c;它通过最小化误差的平方和寻找数据的最佳函数匹配。这种算法在曲线拟合中应用广泛&#xff0c;包括线性拟合和非线性拟合…

司铭宇销售技巧培训师需要具备的功底

销售技巧培训师需要具备的功底 售技巧培训师是负责传授销售技巧和策略的专业人士&#xff0c;他们需要具备深厚的功底&#xff0c;以帮助销售人员提高销售业绩。以下是一些销售技巧培训师需要具备的功底 一、深厚的销售理论功底 销售技巧培训师要想在培训过程中游刃有余&…

dbeaver导出数据为excel格式

dbeaver导出excel 目前数据的可选择只有这几种 恰好没有我们需要的excel模式,而我们需要数据一般都需要excel的 所以我们可以通过以下步骤得到我们的excel格式的数据集: 1.直接选csv模式,至于csv有陌生的小伙伴可以理解:CSV&#xff08;Comma-Separated Values&#xff09;是…

众和策略:如何稳健投资股票?

怎么稳健出资股票&#xff1f;下降股票亏本概率的办法&#xff01; 1、长时间坚持 股票商场的动摇是非常大的&#xff0c;特别是短期内呈现的改变&#xff0c;假如不是短线出资者的话&#xff0c;那么建议长时间出资较为稳健&#xff0c;长时间出资能够协助出资者躲避商场动摇…

代码随想录刷题题Day17

刷题的第十七天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day17 任务 ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先 1 二叉搜索树的最小绝对差 …

Elasticsearch 索引生命周期和翻滚 (rollover) 策略

Elasticsearch 是搜索引擎中的摇滚明星&#xff0c;它的蓬勃发展在于使你的数据井井有条且速度快如闪电。 但当你的数据成为一场摇滚音乐会时&#xff0c;管理其生命周期就变得至关重要。 正确使用索引生命周期管理 (ILM) 和 rollover 策略&#xff0c;你的后台工作人员可确保顺…

【JVM从入门到实战】(八)垃圾回收(1)

内存泄漏&#xff1a;指的是不再使用的对象在系统中未被回收&#xff0c;内存泄漏的积累可能会导致内存溢出 什么是垃圾回收 Java中为了简化对象的释放&#xff0c;引入了自动的垃圾回收&#xff08;Garbage Collection简称GC&#xff09;机制。通过垃 圾回收器来对不再使用的…

20231218在微软官网下载WINDOWS10以及通过rufus-4.3p写入U盘作为安装盘

20231218在微软官网下载WINDOWS10以及通过rufus-4.3p写入U盘作为安装盘 2023/12/18 17:06 百度搜索&#xff1a;下载 windows10 https://www.microsoft.com/zh-cn/software-download/windows10 下载 Windows 10 更新之前&#xff0c;请参阅 Windows 版本信息状态中的已知问题&a…

STM32 CAN多节点组网项目实操 挖坑与填坑记录2

系列文章&#xff0c;持续探索CAN多节点通讯&#xff0c; 上一篇文章链接&#xff1a; STM32 CAN多节点组网项目实操 挖坑与填坑记录-CSDN博客文章浏览阅读120次。CAN线性组网项目开发过程中遇到的数据丢包问题&#xff0c;并尝试解决的记录和推测分析。开发了一个多节点线性…

【可用性】Redis作为注册中心配合Spring Task的高可用案例

需求&#xff1a; 假设当前有一个短信服务是多节点集群部署&#xff0c;我们希望每个服务节点在启动时能将服务信息"注册"到redis缓存中&#xff0c;所有服务节点每隔3分钟上报一次&#xff0c;表示当前服务可用。每个服务还会作为哨兵节点每隔10分钟查询一次redis&a…

I.MX6ULL_Linux_驱动篇(47)linux RTC驱动

RTC 也就是实时时钟&#xff0c;用于记录当前系统时间&#xff0c;对于 Linux 系统而言时间是非常重要的&#xff0c;就和我们使用 Windows 电脑或手机查看时间一样&#xff0c;我们在使用 Linux 设备的时候也需要查看时间。本章我们就来学习一下如何编写 Linux 下的 RTC 驱动程…

小程序自定义轮播图样式

小程序自定义轮播图样式以下是各案例&#xff0c;仅供大家参考。 效果展示&#xff1a; index.wxml代码&#xff1a; <view><!-- 轮播 --><view><swiper indicator-dots"{{indicatorDots}}"autoplay"{{autoplay}}" interval"{{…

易点易动:实现固定资产账实一致和一站式管理的财务系统打通

在当今竞争激烈的商业环境中&#xff0c;企业需要高效管理其固定资产&#xff0c;确保资产账实一致&#xff0c;并实现一站式管理。易点易动是一种集成的财务系统&#xff0c;它通过打通各个环节&#xff0c;提供了一种便捷的方式来管理固定资产。本文将探讨易点易动系统的优势…

基于ssm大学学生成长系统论文

摘 要 随着互联网技术的发展&#xff0c;各类网站应运而生&#xff0c;网站具有新颖、展现全面的特点。因此&#xff0c;为了满足阜阳师范大学学生成长管理的需求&#xff0c;特开发了本阜阳师范大学学生成长系统。 本阜阳师范大学学生成长系统采用Java技术&#xff0c;基于SS…