FastDFS文件上传、下载、删除等。安装与搭建微服务工程

找到端口所在进程端口:netstat -ano| findstr 10001
在这里插入图片描述

删除进程: taskkill /f /pid 16340

把原来占用的进程删掉,使用docker部署
netstat -tunlp | grep 22122
tcp        0      0 0.0.0.0:22122           0.0.0.0:*               LISTEN      114901/fdfs_tracker 
 kill -9 114901

接下来进入正题:

安装FastDFS

在这里插入图片描述
结果:
在这里插入图片描述

配置nginx

由于docker容器中已经集成了Nginx,我们只需要修改docker中的nginx配置,进入storage的容器内部:
docker exec -it storage /bin/bash
找到nginx(无需配置均可):cd etc/nginx,里面的配置文件nginx.conf文件:
注意nginx的监听端口是8080
在这里插入图片描述

文件上传微服务

1.FastDFS文件上传微服务配置客户端配置文件:fdfs_client.conf

#fastDFS的客户端访问配置文件
connect_timeout=60
network_timeout=60
charset=UTF-8
#Tracker的Http请求端口
http.tracker_http_port=8080
tracker_server=101.200.240.33:22122

2.application.yml

spring:
  application:
    name: topgame-service-file
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
server:
  port: 10004
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:7001/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true

3.pom.xml

<dependencies>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.topgame</groupId>
            <artifactId>topgame-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

4.启动类

@EnableEurekaClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
// 需要关闭数据库的自动配置
public class FileMain1004 {
    public static void main(String[] args) {
        SpringApplication.run(FileMain1004.class,args);
    }
}

5.上传所需工具类

1.FastDFSFile : FastDFS文件工具类,用于封装上传的文件

**
 * @author liang
 * @version 1.0
 * @date 2020/4/22 10:49
 * 封装文件上传信息
 * 时间
 * author
 * type
 * content
 * ext
 * md5
 * 附加信息
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FastDFSFile implements Serializable {
    private String name ;// 文件名
    private byte[] content;// 内容:字节数组
    private String ext ;// 扩展名:jpg , gif ....没有.
    private String md5 ;// 文件MD5摘要值
    private String author;// 文件创建作者
}

2.实现FastDFS的工具类:上传、下载等操作

/**
 * @author liang
 * @version 1.0
 * @date 2020/4/22 10:54
 * 实现FastDFS文件管理
 * 文件上传
 * 删除
 * 下载
 * 文件信息获取
 * storage信息获取
 * tracker信息获取
 */
public class FastDFSUtil {
    /**
     * 加载tracker连接信息
     */
    static {
        try {
            // 加载类路径下的文件
            ClassPathResource resource = new ClassPathResource("fdfs_client.conf");
            ClientGlobal.init(resource.getPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件上传
     * @param fastDFSFile : 封装的文件上传对象
     */
    public static String[] upload(FastDFSFile fastDFSFile) throws Exception {
        try {
            //附加参数
            NameValuePair[] metaList = new NameValuePair[1];
            metaList[0] = new NameValuePair("author",fastDFSFile.getAuthor());
            System.out.println("author:"+metaList[0].getValue()); //author:lxw成功获取
            //访问track1er:需要客户端
//        TrackerClient trackerClient = new TrackerClient();
//        //获取Tracker server连接信息
//        TrackerServer trackerServer = trackerClient.getConnection();//NullPointerException
            TrackerServer trackerServer = getTrackerServer();
//        //通过tracker获取storage
//        StorageClient storageClient = new StorageClient(trackerServer,null);
            StorageClient storageClient = getStorageClient(trackerServer);
            //Storage连接信息:创建出对象
            //操作:上传
            return storageClient.upload_file(fastDFSFile.getContent(),fastDFSFile.getExt(),metaList);
        }catch (Exception e){
            e.printStackTrace();
            return  null ; // 上传失败
        }
    }

    /**
     * 获取文件信息
     * @param groupName :文件的组名--group1
     * @param remoteFileName : 文件的存储路径的名名字
     */
    public static FileInfo getFileInfo(String groupName,String remoteFileName)throws Exception{
        try {
            //创建TrackerClient,建议卸写在公共方法中
            TrackerServer trackerServer = getTrackerServer();
            StorageClient storageClient = getStorageClient(trackerServer);
            return storageClient.get_file_info(groupName, remoteFileName);
        }catch (Exception e){
            e.printStackTrace();
            return  null ;
        }
    }

    /**
     * 文件下载
     * @return : 字节输入流
     * @throws Exception
     */
    public static InputStream download(String groupName,String remoteFileName)throws Exception{
        System.out.println(groupName+","+remoteFileName);
        try {
            TrackerServer trackerServer = getTrackerServer();
            StorageClient storageClient = new StorageClient(trackerServer, null);
            //String group_name, String remote_filename :下载参数
            byte[] buffer = storageClient.download_file(groupName, remoteFileName);
            return new ByteArrayInputStream(buffer);//字节转输入流
        }catch (Exception e){
            e.printStackTrace();
            return  null ;
        }
    }

    /**
     * 根据文件的url找出组名:group1
     * @param url
     * @return
     */
    @Deprecated
    public static String getGroupNameByUrl(String url){
        String groupName = "" ;
        for (int i = 0 ; i < 2; i++){
            url = url.substring(url.indexOf("/")+1);
        }
        // 剩下:group1/M00/00/00/rBEeK17yq3SAfeLoAAI2WkTnmt4230.jpg",最后一部分是错误的
        groupName = url.substring(url.indexOf("/")+1);
        groupName = groupName.substring(0,groupName.indexOf("/"));
        return groupName ;
    }

    /**
     * 根据url获取文件名: M00/00/dASDASDA.jpg
     * @param url
     * @return
     */
    @Deprecated
    public static String getRemoteFileNameByUrl(String url){
        String origin = url ;
        String groupName = getGroupNameByUrl(url);
        return url.substring(origin.indexOf(groupName)+1+groupName.length());
    }

    /**
     * 删除文件
     * 注意清除nginx的缓存:add_header Cache-control no-store
     * 记载nginx.conf中的 location ~ /M00 中,再重启storage
     */
    public static boolean deleteFile(String groupName,String remoteFileName) throws Exception {
        TrackerServer trackerServer = getTrackerServer();
        StorageClient storageClient = new StorageClient(trackerServer, null);
        int i = storageClient.delete_file(groupName, remoteFileName);
        System.out.println(i);//2,删除成功返回的0,失败返回2
        return i == 0;
    }
    /**
     * 获取Storage信息
     */
    public static StorageServer getStorageServer() throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getStoreStorage(trackerServer);
    }
    /**
     * 获取Storage的IP和端口信息
     */
    public static ServerInfo[] getServerInfo(String groupName,String remoteFileName) throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
    }
    /**
     * 获取Tracker信息
     */
    public static String getTackerInfo()throws Exception{
        TrackerServer trackerServer = getTrackerServer();
        int port = ClientGlobal.getG_tracker_http_port();// 配置文件信息:端口
        String ip = trackerServer.getInetSocketAddress().getHostString();
        return "http://"+ip+":"+port ;
    }

    /**
     * 代码优化1:获取trackerServer
     * @return
     * @throws Exception
     */
    public static TrackerServer getTrackerServer()throws Exception{
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerServer ;
    }
    /**
     * 代码优化2:获取StorageClient,方便直接操作文件
     * @return
     */
    private static StorageClient getStorageClient(TrackerServer trackerServer) throws IOException {
        //通过tracker获取storage
        return new StorageClient(trackerServer,null);
    }
    public static void main(String[] args) throws Exception {
        //写错了group名也行,但是其他的上传下载不行
//        FileInfo info = getFileInfo("xxx", "M00/00/00/rBEeK16f8QaAMbrLAABnrjUmJ9I081.jpg");
//        //最前面不要加上/
//        System.out.println(info);
        //得到的是内网ip,不是公网的
        //source_ip_addr = 172.17.30.43, file_size = 144986, create_timestamp = 2020-04-22 12:53:31, crc32 = 1156029150

        /*=======================文件下载测试=======================*/
        //将文件写入D:盘
//        InputStream is = null;
//        FileOutputStream fos = null ;
//         is = download("group1", "M00/00/00/rBEeK16fzcuADk8PAAI2WkTnmt4362.jpg");
//        fos = new FileOutputStream("D://1.jpg");
//        byte[] bytes = new byte[1024];
//        while (is.read(bytes) != -1){
//            fos.write(bytes);
//        }
//        fos.flush();
//        fos.close();
//        is.close();

        /*========================删除测试===============================*/
//        boolean flag = deleteFile("group1", "M00/00/00/rBEeK16f8QaAMbrLAABnrjUmJ9I081.jpg");
//        System.out.println(flag);
        /*==================获取storage信息======================*/
//        StorageServer storageServer = getStorageServer();
//        System.out.println(storageServer.getStorePathIndex());//存储路径索引
        /*=======================Storage组信息=====================*/
//        ServerInfo[] group1s = getServerInfo("group1", "M00/00/00/rBEeK16fzZaANHeOAAO8ZFZwros117.jpg");
//        for (ServerInfo group1 : group1s) {
//            System.out.println(group1.getPort()+":"+group1.getIpAddr());
//        }
        /*====================tracker信息=======================*/
        // System.out.println(getTackerInfo());
        System.out.println("monkeykeykey".indexOf("key"));// 3
        System.out.println("monkeykeykey".lastIndexOf("key"));// 9
    }

6.controller示例

package com.topgame.file.controller;

import cn.hutool.core.img.ImgUtil;
import com.github.pagehelper.PageInfo;
import com.topgame.entity.Result;
import com.topgame.entity.StatusCode;
import com.topgame.file.service.HeadPicService;
import com.topgame.file.util.FastDFSFile;
import com.topgame.file.util.FastDFSUtil;
import com.topgame.user.pojo.HeadPic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.swing.*;
import java.io.InputStream;

/**
 * @author liang
 * @version 1.0
 * @date 2020/6/21 23:09
 * 用户头像上传微服务
 */
@RestController
@RequestMapping("headpic")
@CrossOrigin
public class HeadPicController {
    @Autowired
    private HeadPicService headPicService ;
    /**
     * 文件上传
     * @param headPic : 用户名
     * @param file : 图片文件
     */
    @PostMapping(value = "upload")
    public Result upload(@RequestParam(value = "file") MultipartFile file, HeadPic headPic, HttpServletRequest request)  {
//        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//        MultipartFile multipartFile = multipartRequest.getFile("imageFile");
        String originalFilename = file.getOriginalFilename();
        String ext = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
        if (!isImage(ext)){
            return new Result(false,StatusCode.ERROR,"您上传的文件不是图片类型,请重新上传!");
        }
        long size = file.getSize();
        System.out.println("size:"+size);// 5526 2084
        System.out.println(size > 10485760);// true
        if(size > 10485760){
            return new Result(false,StatusCode.ERROR,"文件大小超过10MB,上传失败!");
        }
        System.out.println(file+","+headPic);
        Result result = uploadUtil(file, headPic.getUsername());
        if (result.isFlag()){// 上传成功
            headPic = headPicService.add(headPic,file, (String) result.getData());
            return headPic == null ? result:new Result(true,StatusCode.OK,"上传成功!",headPic) ;
        }
        return result ;
    }

    /**
     * 判断是否为图片
     * @param ext : 文件后缀名
     * @return
     */
    private boolean isImage(String ext){
        if (ext.equalsIgnoreCase(ImgUtil.IMAGE_TYPE_BMP)||ext.equalsIgnoreCase(ImgUtil.IMAGE_TYPE_GIF)||
        ext.equalsIgnoreCase(ImgUtil.IMAGE_TYPE_JPEG)|| ext.equalsIgnoreCase(ImgUtil.IMAGE_TYPE_JPG)||
        ext.equalsIgnoreCase(ImgUtil.IMAGE_TYPE_PNG)||ext.equalsIgnoreCase(ImgUtil.IMAGE_TYPE_PSD)){
            return true ;
        }
        return false ;
    }
    // 文件上传,FastDFSFile和用户名
    public Result uploadUtil(MultipartFile file,String username)  {
        FastDFSFile fastDFSFile = new FastDFSFile();
        fastDFSFile.setName(file.getOriginalFilename());
        String url="" ;//上传成功后的访问路径
        fastDFSFile.setAuthor(username);
        try {
            fastDFSFile.setContent(file.getBytes());
            fastDFSFile.setExt(StringUtils.getFilenameExtension(file.getOriginalFilename()));
            String[] uploads = FastDFSUtil.upload(fastDFSFile); // 为什么是null?
            /*成功的案例路径:http://topgamelxw.top:8080/group1/M00/00/00/ASJDKLJ4X.jpg
             * [0]:group1
             * [1]:后面剩下的
             * */
            url = FastDFSUtil.getTackerInfo()+"/"+uploads[0]+"/"+uploads[1];
            // 调用头像文件
            return new Result(true, StatusCode.OK,"文件上传成功",url);//访问成功
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new Result(false, StatusCode.OK,"文件上传失败");
    }

    /**
     * 根据用户名查询出历史使用过的图片:按照上传时间排序并分页
     */
    @GetMapping("/{username}/{page}")
    public Result<PageInfo<HeadPic>> findHistory(@PathVariable("username") String username,@PathVariable("page") Integer page){
        PageInfo<HeadPic> headPicPageInfo = headPicService.findByUsername(username, page);
        return new Result<>(true,StatusCode.OK,"查询成功!",headPicPageInfo);
    }
    // 根据用户名查询出当前用使用的头像
    @GetMapping("{username}")
    public Result<HeadPic> getCurrHeadPic(@PathVariable("username") String username){
        return headPicService.findCurrHeadPicByUsername(username) ;
    }
    // 更新用户当前使用的
    @PutMapping("{username}")
    public Result<HeadPic> updateUsed(@PathVariable("username")String username, String path){
        System.out.println(username+path);
        return headPicService.updateUsed(username,path) ;
    }
    /**
     * 头像图片下载 : 根据url进行下载
     * @return
     * 下载未完成
     */
    @GetMapping("download")
    public Result download(String url){
        try {
            InputStream download = FastDFSUtil.download(FastDFSUtil.getGroupNameByUrl(url), FastDFSUtil.getRemoteFileNameByUrl(url));
            return new Result<>(true,StatusCode.OK,"可以进行下载!",download);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result<>(true,StatusCode.OK,"可以进行下载!");
//            return null ;
        }

    }

    public static void main(String[] args) {
        System.out.println(55262084L>10485760L);
    }
}

以上的HeadPic类:

package com.topgame.user.pojo;

import lombok.Data;
import org.hibernate.validator.constraints.br.CPF;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
 * @author liang
 * @version 1.0
 * @date 2020/6/21 22:55
 * 用户头像实体类
 */
@Table(name = "tb_headpic")
@Data
public class HeadPic implements Serializable {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id ; //编号
    @Column(name = "username")
    private String username ;// 用户名
    @Column(name = "upload_time")
    private Date uploadTime ;// 上传时间
    @Column(name = "upload_location")
    private String uploadLocation ; // 上传图片的客户端位置
    @Column(name = "upload_ip")
    private String uploadIp ; // 上传图片公网ip
    @Column(name = "type")
    private String type ;// 图片类型
    @Column(name = "path")
    private String path ; // 访问路径
    @Column(name = "used")
    private String used ; // 当前是否被使用:0未被使用,1被使用
}

fastDFS配置文件:不是application.yml,application.yml中只需要配置文件大小即可。
在这里插入图片描述
fdfs_client.conf

#fastDFS的客户端访问配置文件
connect_timeout= 60
network_timeout= 60
charset= UTF-8
#Tracker的Http请求端口
http.tracker_http_port= 8080
tracker_server= 101.200.240.33:22122
# org.csource.common.MyException: getStoreStorage fail, errno code: 2 :
#原因:就是storage容器中ip地址错了
# vim会保存一个 swap,上次修改未保存的就出出现提示,删除swap文件就正常了

注意:项目上传文件连接超时很可能是因为没开放端口:22122和23000. 我的是阿里云服务器,特别还需要手动去阿里控制台去开放这两个端口才能生效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值