文件服务器FastDFS 消息队列中间件RabbitMQ

news2024/12/27 15:20:19

新标签页 (chinaunix.net)

FastDFS - Browse Files at SourceForge.net

 一、FastDFS

         Tracker和Storage:

                tracker用来管理所有的storage,只是管理服务器,负责负载均衡。

                storage是存储服务器,每一个storage服务器都是一个单独的个体,storage服务器之间没有交互关系。

        在FastDFS中根目录包含256个一级目录、每个一级目录中包含256个二级子目录,在二级子目录中存储图片。存储图片时服务器会返回相应的group和remote,访问文件时通过这两个键值对获取图片。

        



     ①、在虚拟机中使用docker安装FastDFS

docker load -i fastdfs.tar  //在docker中加载镜像源文件

mkdir -p /opt/fdfs/tracker  

docker run -d --network=host --name tracker -v /opt/fdfs/tracker:/var/fdfs delron/fastdfs tracker  

mkdir -p /opt/fdfs/storage

docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.222.128:22122 -v /opt/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage


//重启服务器需要删除文件。
rm -rf /opt/fdfs/tracker/data/*.pid 
rm -rf /opt/fdfs/storage/data/*.pid

//更改服务器的磁盘限制
docker exec -it tracker bash
cd /etc/fdfs
vi /etc/fdfs/tracker.conf
reserved_storage_space = 10K //磁盘剩余多少空间时关闭上传文件功能

   



    ②、java代码使用FastDFS

                1)首先编写FastDFS配置信息fdfs.properties

fastdfs.connect_timeout_in_seconds=10
fastdfs.network_timeout_in_seconds=30
fastdfs.charset=UTF-8
# tracker????????????????
fastdfs.tracker_servers=192.168.222.128:22122
# tracker????????tracker.conf??http??????????
fastdfs.http_tracker_http_port=8080

             2)FastDFS 操作工具类

                                封装了加载配置文件fdfs.properties的静态代码块,还有上传和下载的方法。

package com.xja.util;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

import java.io.InputStream;
import java.util.Properties;

/**
 * FastDFS Java客户端工具
 */
public final class FastDFSUtils {
    /**
     * 定义静态属性,Properties和StorageClient
     */
    private final static Properties PROPERTIES;
    private final static StorageClient STORAGE_CLIENT;

    /**
     * 静态初始化代码块,初始化静态属性
     * 静态初始化代码块有异常如何处理?
     * 处理的时候,try。。catch。。 抛出一个Error,终止虚拟机。
     */
    static{
        try {
            PROPERTIES = new Properties();
            // 读取配置文件
            PROPERTIES.load(
                    FastDFSUtils.class
                            .getClassLoader()
                            .getResourceAsStream("fdfs.properties")
            );
            // 使用ClientGlobal初始化FastDFS客户端配置
            ClientGlobal.initByProperties(PROPERTIES);
            // 创建Tracker客户端对象
            TrackerClient trackerClient = new TrackerClient();
            // 基于Tracker客户端对象,获取Tracker服务器对象
            TrackerServer trackerServer = trackerClient.getConnection();
            // 基于Tracker服务器和客户端对象,获取Storage服务器对象
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            // 创建Storage客户端对象
            STORAGE_CLIENT = new StorageClient(trackerServer, storageServer);
        }catch (Exception e){
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * 删除文件
     * int delete_file(String 卷名, String 路径及文件名);
     * 返回值: 0代表成功,其他数字代表错误编码
     */
    public static int remote(String group, String remote){
        try {
            return STORAGE_CLIENT.delete_file(group, remote);
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * 查询某文件的元数据
     * @param group 卷名
     * @param remote 路径及文件名
     * @return 返回文件的元数据数组。发生错误返回null
     */
    public static NameValuePair[] getMetaData(String group, String remote){
        try{
            return STORAGE_CLIENT.get_metadata(group, remote);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 下载文件工具方法
     *  下载方法
     *  byte[] download_file(String 卷名, String 路径及文件名)
     *  返回要下载的文件内容
     * @param group 卷名
     * @param remote 路径及文件名
     * @return 返回下载的文件内容,发生错误返回null
     */
    public static byte[] download(String group, String remote){
        try {
            return STORAGE_CLIENT.download_file(group, remote);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 上传文件的工具方法
     * 一定保存文件到FastDFS,一定保存至少一个元数据(文件原始名称)
     * @param inputStream 要上传的文件的输入流
     * @param fileName 上传文件的原始名称
     * @param metaProperties 上传文件的元数据,成对提供,如: 名,值,名,值
     * @return
     */
    public static String[] uploadFile(InputStream inputStream, String fileName, String... metaProperties){
        try {
            int length = inputStream.available();
            byte[] datas = new byte[length];
            inputStream.read(datas, 0, length);
            // 处理元数据
            NameValuePair[] nameValuePairs = null;
            if (metaProperties.length % 2 == 0) {
                // 参数数量满足要求,开始处理
                nameValuePairs = new NameValuePair[metaProperties.length / 2 + 1];
                for (int i = 0; i < nameValuePairs.length; i = i + 2) {
                    nameValuePairs[i / 2] = new NameValuePair(metaProperties[i], metaProperties[i + 1]);
                }
            } else {
                nameValuePairs = new NameValuePair[1];
            }
            nameValuePairs[nameValuePairs.length - 1] = new NameValuePair("fileName", fileName);
            // 获取文件后缀
            String extName = getExtName(fileName);
            // 上传文件到FastDFS
            String[] result = STORAGE_CLIENT.upload_file(datas, extName, nameValuePairs);
            for (String s : result) {
                System.out.println("s = " + s);
                //s = group1
                //s = M00/00/00/wKjegGbqfoKACfLIAAAnJ2OoZs8411.txt
            }
            System.out.println("============= " + nameValuePairs[0]+ "/n"+ nameValuePairs[1]);
            //============= org.csource.common.NameValuePair@4ae28001/norg.csource.common.NameValuePair@3e472f5d
            return result;
        }catch (Exception e){
            // 发生任何异常,上传文件失败。返回null
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 截取文件后缀
     * @param fileName
     * @return
     */
    private static String getExtName(String fileName){
        if(fileName.lastIndexOf(".") > -1){
            // 文件名称中包含字符 .
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        }else{
            // 文件名称中不包含字符 .
            return "";
        }
    }

    /**
     * 提供获取Storage客户端对象的工具方法
     */
    public static StorageClient getStorageClient(){
        return STORAGE_CLIENT;
    }

    private FastDFSUtils(){}
}

                3)编写上传和下载路由

                           下载路由中需要加上内容类型和响应头,否则可能出现访问下载却出现在线预览图片

@Controller
public class LoginController {
    @RequestMapping("/index")
    public String uploadPage(){
        return "index";
    }

    @RequestMapping("/upload")
    public String upload(MultipartFile file, HttpSession session) throws IOException {
        InputStream inputStream = file.getInputStream();
        String originalFilename = file.getOriginalFilename();
        String[] strings = FastDFSUtils.uploadFile(inputStream, originalFilename, "s", "");
        System.out.println(strings);
        return "a";
    }
    @RequestMapping("/download")
    public void download(String group,String remote,HttpServletResponse response) throws IOException {
        byte[] datas = FastDFSUtils.download(group, remote);
        response.setContentType("application/octet-stream");
        // 设置下载文件的附件名称

        NameValuePair[] metaData = FastDFSUtils.getMetaData(group, remote);
        String fileName = "";
        for (NameValuePair metaDatum : metaData) {
            if ("fileName".equals(metaDatum.getName()))
                fileName = metaDatum.getValue();
        }

        response.setHeader("content-disposition",
                "attachment;filename="+fileName.toString());
        // 输出要下载的文件内容到客户端
//        byte[] datas = (byte[]) result.get("datas");
        response.getOutputStream().write(datas, 0, datas.length);
        response.getOutputStream().flush();
    }

}

                4)上传一张图片,在浏览器中访问图片 

                           这里的端口号为8888,fastdfs中内置有nginx服务器,请求从nginx服务器转发到storage服务器.

 

二、RabbitMQ

        publisher项目使用RabbitMQ软件将消息推送至交换机,交换机根据路由键将消息推送至相应队列中。Consumer项目中的监听器时刻监听提前设置好的监听队列,如果有消息进入队列中,会调用单元方法将消息中的数据取出消费,消费成功后返回信息在队列中删除消息

        如果消息在Consumer项目中拿取数据或者消费过程中出现错误,这个时候不会被删除,而是会多次尝试再次获取 消息 消费。达到一定次数,停止尝试。

        1)虚拟机使用docker安装RabbitMQ

             0、docker命令:

docker pull rabbitmq:management

docker run -d --name rabbitmq -p 15672:15672 -p 5672:5672 --restart=always -e DEFAULT_USER=wollo -e DEFAULT_PASS=wollo rabbitmq:management

            ①、 访问 http:192.168.222.128:15672:   //Docker宿主机IP:15672

                        这个是RabbitMQ提供的可视化界面,类似于Navicat。

        ②、使用可视化界面操作RabbitMQ: 

                         创建交换机、创建队列、将交换机和队列绑定并设置路由键

   

                       

        



    2)使用java代码连接操作RabbitMQ

        

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

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

相关文章

计算机毕业设计之:基于微信小程序的疫苗预约系统的设计与实现(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Shiro rememberMe反序列化漏洞(Shiro-550)

开启环境抓包验证Shiro框架 使⽤BurpSuite进⾏抓包&#xff0c;在请求包中的cookie字段中添加 rememberMe123; &#xff0c;看响应包 header中是否返回 rememberMedeleteMe 值&#xff0c;若有&#xff0c;则证明该系统使⽤了Shiro框架&#xff1a; 使用工具爆破密钥爆破利用…

论文大杀器!分享4款ai论文写作工具软件

在当今学术研究和论文写作领域&#xff0c;AI技术的应用已经变得越来越普遍。这些工具不仅能够提高写作效率&#xff0c;还能帮助研究人员生成高质量的论文内容。本文将重点介绍四款优秀的AI论文写作工具&#xff0c;并特别推荐千笔-AIPassPaper。 一、千笔-AIPassPaper 传送门…

2024寻找那些能精准修改PDF内容的工具

如今&#xff0c;我们使用 PDF 文档的频率不断攀升&#xff0c;很多时候收到的表格等资料都是 PDF 格式。若先进行格式转换后编辑&#xff0c;再转换回 PDF 格式&#xff0c;着实有些麻烦。那么&#xff0c;pdf怎么编辑修改内容呢&#xff1f;在这篇文章中&#xff0c;我将为大…

python爬虫案例——抓取链家租房信息

文章目录 1、任务目标2、分析网页3、编写代码1、任务目标 目标站点:链家租房版块(https://bj.lianjia.com/zufang/) 要求:抓取该链接下前5页所有的租房信息,包括:标题、详情信息、详情链接、价格 如: 2、分析网页 用浏览器打开链接,按F12或右键检查,进入开发者模式;因…

防火墙--NAT技术,基于源NAT,NAT服务器,双向NAT

文章目录 防火墙--NAT技术一、基于源NAT**方式**&#xff1a;NAT No-PATNAPT出接口地址方式Smart NAT三元组 NAT 二、基于服务器的NAT多出口场景下的NAT Server 三、双向NAT 防火墙–NAT技术 基于源NAT&#xff1a;用于将内部网络的私有IP地址转换为公共IP地址&#xff0c;以便…

使用 IntelliJ IDEA 连接到达梦数据库(DM)

前言 达梦数据库是一款国产的关系型数据库管理系统&#xff0c;因其高性能和稳定性而被广泛应用于政府、金融等多个领域。本文将详细介绍如何在 IntelliJ IDEA 中配置并连接到达梦数据库。 准备工作 获取达梦JDBC驱动&#xff1a; 访问达梦在线服务平台网站或通过其他官方渠道…

Matlab|基于遗传模拟退火算法的风电功率聚类分析

目录 主要内容 部分代码 结果一览 下载链接 主要内容 模糊C-均值聚类&#xff0c;也称FCM&#xff0c;是比较常用的一种聚类算法&#xff0c;该算法利用几何贴进度的概念将不同数据分配到不同聚类群中&#xff0c;但是作为局部搜索优化算法&#xff0c;初值选择不…

Conda虚拟环境配置常见问题记录

搞深度学习的&#xff0c;总有被虚拟环境搞得头大的时候&#xff0c;特别是涉及到CUDA&#xff0c;Torch &#xff0c;Torchvision 版本适配的问题。这两天因为在原来的环境中装了几个包&#xff0c;导致原来的环境崩了&#xff0c;搞了一天的时间又重新配了环境&#xff0c;中…

塑料瓶回收标志分级检测系统源码分享

塑料瓶回收标志分级检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Co…

Etcd权限认证管理

1 查看是否开启权限认证 ctl auth status 2 开启权限认证 ctl auth enable。开启后每一条命令都要加上用户 --userroot:root(root默认最高权限) 3 创建其他用户 ctl user add user1 --user用户名:密码 4 创建角色 ctl role add testR --user 5 为角色添加权限 ctl role g…

python和pyqt-tools安装位置

一.python的安装位置 1.查询安装的python的位置 先查询python&#xff0c;然后输入import sys和sys.path 二.python-tools的安装位置 找到python的文件后按下图路径即可查到tools的文件

OpenAI o1团队突破性论文:『过程推理』中数学推理能力大幅提升,从正确中学习的新方法

原创 超 近年来&#xff0c;大型语言模型(LLMs)在复杂的多步推理任务中取得了令人瞩目的进展。这些模型能够生成逐步的思维链&#xff0c;解决从小学数学到高等微积分的各种问题。然而&#xff0c;即使是最先进的模型也常常陷入逻辑陷阱&#xff0c;产生看似合理但实际错误的推…

PHP校园外卖跑腿小程序带后台(商业版)

有需要请加文章底部Q哦 可远程调试 PHP校园外卖跑腿小程序带后台(商业版) 一 介绍 此校园外卖跑腿小程序端基于原生开发&#xff0c;后端基于ThinkPHP5框架开发&#xff0c;数据库mysql&#xff0c;系统角色分为用户&#xff0c;商家(自配送)&#xff0c;跑腿员&#xff0c;管…

Python+requests+pytest+allure自动化测试框架

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、核心库 requests request请求 openpyxl excel文件操作 loggin 日志 smtplib 发送邮件 configparser unittest.mock mock服务 2、目录结构 base utils …

如何使用ssm实现社区流浪动物救助领养系统的设计与开发+vue

TOC ssm666社区流浪动物救助领养系统的设计与开发vue 第一章 课题背景及研究内容 1.1 课题背景 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安…

kafka 消费者线程安全问题详细探讨

内容概要 主要内容 常见错误案例 下面这段代码大概逻辑 初始化时 实例化KafkaConsumer, 开启线程拉取消息并且处理 资源释放回调 停止线程、调用kafkaConsumer.close进行资源释放 表面上没有问题&#xff0c;但实际上可能出现线程安全问题&#xff0c;因为poll 和 close 两…

python按照财年分组案例

有如下数据&#xff1a;需要按照如下要求进行分组。 需求是对Site进行分组 条件当值是Act得时候&#xff0c;分组名字就是 条件当值是Rebase*得时候&#xff0c;分组名字就是FY?1/?1 条件当值是FIRM 得时候&#xff0c;分组名字就是 每年得7月到次年得6月为一个财年&#xff…

C++之初识STL(概念)

STL&#xff08;标准模板库&#xff09; STL广义分类为&#xff1a;容器&#xff0c;算法&#xff0c;迭代器 * **容器**和**算法**之间通过**迭代器**进行无缝连接 意义&#xff1a;C的**面向对象**和**泛型编程**思想&#xff0c;目的就是**复用性的提升** STL六大组件 1. 容…

MODELS 2024:闪现奥地利,现场直击报道

周末出逃&#xff01;小编闪现至奥地利林茨&#xff0c;亲临第27届MODELS 2024国际会议&#xff0c;以第一视角引领你深入会议现场&#xff0c;领略其独特风采。利用午饭时间&#xff0c;小编紧急码字&#xff0c;只为第一时间将热点资讯呈现给你~ 会议介绍&#xff1a; MODEL…