SpringBoot-FastDFS

SpringBoot-FastDFS

在学习前需要将FastDFS服务器搭建好…这方面我博客里有教程

FastDFS介绍

FastDFS是一款开源的轻量级分布式文件系统纯C实现,支持Linux、FreeBSD等UNIX系统类google FS,不是通用的文件系统,只能通过专有API访问,目前提供了C、Java和PHP API为互联网应用量身定做,解决大容量文件存储问题,追求高性能和高扩展性FastDFS可以看做是基于文件的key value pair存储系统,称作分布式文件存储服务更为合适。

tracker-server:

跟踪服务器, 主要做调度工作, 起负载均衡的作用。 在内存中记录集群中所有存储组和存储服务器的状态信息, 是客户端和数据服务器交互的枢纽。 相比GFS中的master更为精简, 不记录文件索引信息, 占用的内存量很少。

storage-server:

存储服务器( 又称:存储节点或数据服务器) , 文件和文件属性( metadata) 都保存到存储服务器上。 Storage server直接利用OS的文件系统调用管理文件。

group:

组, 也可称为卷。 同组内服务器上的文件是完全相同的 ,同一组内的storage server之间是对等的, 文件上传、 删除等操作可以在任意一台storage server上进行 。

meta data:

meta data:文件相关属性,键值对( Key Value Pair) 方式,如:width=1024,heigth=768 。

文件访问路径:

组名:文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。 (group1)

虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项store_path*对应。 默认store_path0 则是 M00

数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。(02/44) 这个一般好像是(00/00)

文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储 服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

以上所有信息结合起来就是文件的访问路径

单机文件和分布式文件系统的对比

单机文件系统: 低,依赖于单机服务器,只要服务器崩溃,完全不可用。 低,要扩容只能停机增加硬盘。 当文件数量多到一定的程度,磁盘IO寻址操作将会成为瓶颈,好处就是配置快

分布式文件系统: 一个group内的服务器崩溃后,group内的其他storage将接管服务。 可以不停机增加group机器 ,部署较复杂 通过集群或者分布式的方式分担服务器的压力。

适用场景:

特别适合以中小文件( 建议范围: 4KB 到 500MB ) 为载体的在线服务, 如相册网站、 视频网站等等。

Springboot 操作FastDFS (入门体验)

1.创建Maven项目

  1. 需要的Maven依赖

    <dependencies>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    
  2. 配置文件fdfs_client.conf

       connect_timeout=60
       network_timeout=60
       charset=UTF-8
        #tracker访问nginx的反向代理端口号
       http.tracker_http_port=8021
       tracker_server=192.168.66.67:22122
    
  3. 测试文件FastdfsClientTest

    package com.fastdfs;
    
    import org.csource.common.MyException;
    import org.csource.fastdfs.*;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    
    
    public class FastdfsClientTest {
    
        StorageClient storageClient;
        TrackerClient trackerClient;
        TrackerServer trackerServer;
        @Before
        public  void Init() throws IOException, MyException {
            //加载全局的配置文件
            ClientGlobal.init("fdfs_client.conf");
    
            //创建TrackerClient客户端对象
            trackerClient = new TrackerClient();
            //通过TrackerClient对象获取TrackerServer信息
            trackerServer = trackerClient.getConnection();
            //获取StorageClient对象
            storageClient = new StorageClient(trackerServer, null);
        }
    	//文件路径
        public  String fileName="M00/00/00/wKhCR1_LGd6ACMUBAABdrZgsqUU452_big.jpg";
        //组
        public  String  group="group1";
    
    
        /**
         * 文件上传
         *
         * @throws Exception
         */
        @Test
        public void upload() throws Exception {
    
    
            //获取StorageClient对象
            StorageClient storageClient = new StorageClient(trackerServer, null);
    
            //执行文件上传  自己修改要上传文件的 路径
            String[] jpgs = storageClient.upload_file("C:\\Users\\12841\\Pictures\\test.jpg", "jpg", null);
    
            for (String jpg : jpgs) {
    
                System.out.println(jpg);
            }
    
        }
    
        //删除 文件
        @Test
        public void delete() throws Exception {
    
            //获取StorageClient对象
            StorageClient storageClient = new StorageClient(trackerServer, null);
            //执行文件删除
            int group1 = storageClient.delete_file(group, fileName);
            System.out.println(group1);
        }
    
        //下载 文件
        @Test
        public void download() throws Exception {
    
            //执行文件上传
            byte[] bytes = storageClient.download_file(group, fileName);
    
            File file = new File("D:\\1234.jpg");
    
            FileOutputStream fileOutputStream = new FileOutputStream(file);
    
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
    
            bufferedOutputStream.write(bytes);
    
            bufferedOutputStream.close();
    
            fileOutputStream.close();
        }
    
        //获取文件的信息数据
        @Test
        public void getFileInfo() throws Exception {
    
            //执获取文件信息
            FileInfo group1 = storageClient.get_file_info(group, fileName);
    
            System.out.println(group1);
    
        }
    
        //获取组相关的信息
        @Test
        public void getGroupInfo() throws Exception {
    
    
            StorageServer group1 = trackerClient.getStoreStorage(trackerServer, group);
            System.out.println(group1.getStorePathIndex());
    
            //组对应的服务器的地址  因为有可能有多个服务器.
            ServerInfo[] group1s = trackerClient.getFetchStorages(trackerServer, group, fileName);
            for (ServerInfo serverInfo : group1s) {
                System.out.println(serverInfo.getIpAddr());
                System.out.println(serverInfo.getPort());
            }
        }
    
        @Test
        public void getTrackerInfo() throws Exception {
    
    
            InetSocketAddress inetSocketAddress = trackerServer.getInetSocketAddress();
            System.out.println(inetSocketAddress);
    
        }
    
    
    }
    

自己测试就行了

Springboot集成Fastdfs(高级)

结构图:

需要的Maven
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

<dependencies>

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

    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>provided</scope>
    </dependency>

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

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
        <version>2.3.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.3</version>
    </dependency>

    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.1.5</version>
    </dependency>

</dependencies>
fdfs_client.conf
connect_timeout=60
network_timeout=60
charset=UTF-8
 #tracker文件上传是访问nginx的反向代理
http.tracker_http_port=8088
 #tracker服务器地址,如果有多个tracker可以配置多个tracker_server
tracker_server=192.168.66.67:22122
tracker_server=192.168.66.68:22122
tracker_server=192.168.66.69:22122
application.yml
server:
  port: 20210

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  application:
    name: file


mybatis:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.fastdfs.pojo
com.fastdfs.FileApplication
package com.fastdfs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class FileApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileApplication.class);
    }
}

com.fastdfs.controller.FileController
package com.fastdfs.controller;

import com.fastdfs.pojo.FastDFSFile;
import com.fastdfs.util.FastDFSClient;
import com.fastdfs.util.Result;
import com.fastdfs.util.StatusCode;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.ServerInfo;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

@RestController
@CrossOrigin
public class FileController {

    /***
     * 文件上传
     * @param  file  表单的name
     * @return  返回文件地址
     */
    @PostMapping(value = "/upload")
    public Result upload(@RequestParam("file") MultipartFile file) throws Exception {
        //封装一个FastDFSFile
        FastDFSFile fastDFSFile = new FastDFSFile(
                file.getOriginalFilename(), //文件名字
                file.getBytes(),            //文件字节数组
                StringUtils.getFilenameExtension(file.getOriginalFilename()));//文件扩展名

        String s=null;
        //文件上传
        String[] uploads = FastDFSClient.upload(fastDFSFile);
        if(FastDFSFile.vip_ip!=null){
            s = FastDFSClient.getTrackerUrl(FastDFSFile.vip_ip) + "/" + uploads[0] + "/" + uploads[1];  //拼接结果
        }else {
            s = FastDFSClient.getTrackerUrl() + "/" + uploads[0] + "/" + uploads[1];  //拼接结果
        }

        //组装文件上传地址
        return new Result<FastDFSClient>(true, StatusCode.OK,"文件上传成功",s ) ;

    }

    /***
     * 文件信息查询
     * @param groupName 组名称
     * @param fileName  文件名称
     * @return 返回文件详细信息
     */
    @GetMapping(value = "/selectFileName")
    @ResponseBody
    public Result selectFileName(String groupName, String fileName) {


        FileInfo file = FastDFSClient.getFile(groupName, fileName);
        //组装文件上传地址
        return new Result<FastDFSClient>(true, StatusCode.OK,"文件信息查询成功",file.toString() ) ;
    }


    /***
     * 文件下载
     * @param groupName:组名
     * @param fileName:文件存储完整名
     * @return
     */
    @GetMapping(value = "/downFile")
    public static InputStream downFile(String groupName, String fileName){
        try {

            InputStream inputStream = FastDFSClient.downFile(groupName, fileName);
            //将字节数组转换成字节输入流
            return inputStream;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }


    }
    /***
     * 文件删除实现
     * @param groupName:组名
     * @param fileName:文件存储完整名
     */
    @GetMapping(value = "/deleteFile")
    public static Result deleteFile(String groupName, String fileName){
        try {
            FastDFSClient.deleteFile(groupName,fileName);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false,StatusCode.ERROR,"文件删除失败");
        }
        return new Result(true,StatusCode.OK,"文件删除成功");
    }



    /***
     * 根据文件组名和文件存储路径获取Storage服务的IP、端口信息
     * @param groupName :组名
     * @param fileName :文件存储完整名
     * @return
     */
    @GetMapping(value = "/getServerInfo")
    @ResponseBody
    public static Result getServerInfo(String groupName, String fileName){
        try {

            ServerInfo[] serverInfo = FastDFSClient.getServerInfo(groupName, fileName);

            return new Result<FastDFSClient>(true, StatusCode.OK,"根据文件组名和文件存储路径查询Storage服务的IP端口信息成功",serverInfo) ;
        } catch (Exception e) {
            e.printStackTrace();
            return new Result<FastDFSClient>(false, StatusCode.ERROR,"根据文件组名和文件存储路径查询Storage服务的IP端口信息失败",e.getMessage()) ;
        }
    }

}

com.changgou.file.FastDFSFile
package com.fastdfs.pojo;

import java.io.Serializable;
import java.util.Arrays;

public class FastDFSFile implements Serializable {

    //文件名字
    private String name;
    //文件内容
    private byte[] content;
    //文件扩展名
    private String ext;
    //文件MD5摘要值
    private String md5;
    //文件创建作者
    private String author;

   public  final static  String vip_ip="192.168.66.70";

    public FastDFSFile(String name, byte[] content, String ext, String md5, String author) {
        this.name = name;
        this.content = content;
        this.ext = ext;
        this.md5 = md5;
        this.author = author;
    }

    public FastDFSFile(String name, byte[] content, String ext) {
        this.name = name;
        this.content = content;
        this.ext = ext;
    }

    public FastDFSFile() {
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public byte[] getContent() {
        return content;
    }

    public void setContent(byte[] content) {
        this.content = content;
    }

    public String getExt() {
        return ext;
    }

    public void setExt(String ext) {
        this.ext = ext;
    }

    public String getMd5() {
        return md5;
    }

    public void setMd5(String md5) {
        this.md5 = md5;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }


    @Override
    public String toString() {
        return "FastDFSFile{" +
                "name='" + name + '\'' +
                ", content=" + Arrays.toString(content) +
                ", ext='" + ext + '\'' +
                ", md5='" + md5 + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}
com.fastdfs.util.FastDFSClient
package com.fastdfs.util;

import com.fastdfs.pojo.FastDFSFile;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FastDFSClient {

    /***
     * 初始化tracker信息
     */
    static {
        try {
            //获取tracker的配置文件fdfs_client.conf的位置
            String filePath = new ClassPathResource("fdfs_client.conf").getPath();
            //加载tracker配置信息
            ClientGlobal.init(filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /****
     * 文件上传
     * @param file : 要上传的文件信息封装->FastDFSFile
     * @return String[]
     *          1:文件上传所存储的组名
     *          2:文件存储路径
     */
    public static String[] upload(FastDFSFile file){
        //获取文件作者
        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] =new NameValuePair(file.getAuthor());

        /***
         * 文件上传后的返回值
         * uploadResults[0]:文件上传所存储的组名,例如:group1
         * uploadResults[1]:文件存储路径,例如:M00/00/00/wKjThF0DBzaAP23MAAXz2mMp9oM26.jpeg
         */
        String[] uploadResults = null;
        try {
            //获取StorageClient对象
            StorageClient storageClient = getStorageClient();
            //执行文件上传
            uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return uploadResults;
    }


    /***
     * 获取文件信息
     * @param groupName:组名
     * @param remoteFileName:文件存储完整名
     */
    public static FileInfo getFile(String groupName,String remoteFileName){
        try {
            //获取StorageClient对象
            StorageClient storageClient = getStorageClient();
            //获取文件信息
            return storageClient.get_file_info(groupName,remoteFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 文件下载
     * @param groupName:组名
     * @param remoteFileName:文件存储完整名
     * @return
     */
    public static InputStream downFile(String groupName,String remoteFileName){
        try {
            //获取StorageClient
            StorageClient storageClient = getStorageClient();
            //通过StorageClient下载文件
            byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
            //将字节数组转换成字节输入流
            return new ByteArrayInputStream(fileByte);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 文件删除实现
     * @param groupName:组名
     * @param remoteFileName:文件存储完整名
     */
    public static void deleteFile(String groupName,String remoteFileName){
        try {
            //获取StorageClient
            StorageClient storageClient = getStorageClient();
            //通过StorageClient删除文件
            storageClient.delete_file(groupName,remoteFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /***
     * 根据文件组名和文件存储路径获取Storage服务的IP、端口信息
     * @param groupName :组名
     * @param remoteFileName :文件存储完整名
     */
    public static ServerInfo[] getServerInfo(String groupName, String remoteFileName){
        try {
            //创建TrackerClient对象
            TrackerClient trackerClient = new TrackerClient();
            //通过TrackerClient获取TrackerServer对象
            TrackerServer trackerServer = trackerClient.getConnection();
            //获取服务信息
            return trackerClient.getFetchStorages(trackerServer,groupName,remoteFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 获取Tracker服务地址
     */
    public static String getTrackerUrl(){
        try {
            //创建TrackerClient对象
            TrackerClient trackerClient = new TrackerClient();
            //通过TrackerClient获取TrackerServer对象
            TrackerServer trackerServer = trackerClient.getConnection();
            //获取Tracker地址
            return "http://"+trackerServer.getInetSocketAddress().getHostString()+":"+ClientGlobal.getG_tracker_http_port();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String getTrackerUrl(String vip_ip){
        //获取Tracker地址
        return "http://"+vip_ip+":"+ClientGlobal.getG_tracker_http_port();
    }

    /***
     * 获取TrackerServer
     */
    public static TrackerServer getTrackerServer() throws Exception{
        //创建TrackerClient对象
        TrackerClient trackerClient = new TrackerClient();
        //通过TrackerClient获取TrackerServer对象
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerServer;
    }

    /***
     * 获取StorageClient
     * @return
     * @throws Exception
     */
    public static StorageClient getStorageClient() throws Exception{
        //获取TrackerServer
        TrackerServer trackerServer = getTrackerServer();
        //通过TrackerServer创建StorageClient
        StorageClient storageClient = new StorageClient(trackerServer,null);
        return storageClient;
    }
}

com.fastdfs.util.Result
package com.fastdfs.util;

import java.io.Serializable;

/**
 * 描述
 *
 * @author 三国的包子
 * @version 1.0
 * @package entity *
 * @since 1.0
 */
public class Result<T> implements Serializable {
    private boolean flag;//是否成功
    private Integer code;//返回码
    private String message;//返回消息
    private T data;//返回数据

    public Result(boolean flag, Integer code, String message, Object data) {
        this.flag = flag;
        this.code = code;
        this.message = message;
        this.data = (T) data;
    }

    public Result(boolean flag, Integer code, String message) {
        this.flag = flag;
        this.code = code;
        this.message = message;
    }

    public Result() {
        this.flag = true;
        this.code = StatusCode.OK;
        this.message = "操作成功!";
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

com.fastdfs.util.StatusCode
package com.fastdfs.util;

/**
 * 返回码
 */
public class StatusCode {
    public static final int OK = 20000;//成功
    public static final int ERROR = 20001;//失败
    public static final int LOGINERROR = 20002;//用户名或密码错误
    public static final int ACCESSERROR = 20003;//权限不足
    public static final int REMOTEERROR = 20004;//远程调用失败
    public static final int REPERROR = 20005;//重复操作
    public static final int NOTFOUNDERROR = 20006;//没有对应的抢购数据
}

测试

使用Postman 测试

选择post请求方式,输入请求地址 http://localhost:20210/upload

填写Headers

Key:Content-Type               Value:multipart/form-data

然后选择Body

或者form表单

<form action="http://localhost:18082/upload" method="post" enctype="multipart/form-data">
   <input type="file" name="file">
    <input type="submit">
</form>

除了自己搭建FastDFS外我们还可以使用阿里云的OSS (收费)

阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全、低成本、高可靠的云存储服务。您可以通过本文档提供的简单的REST接口,在任何时间、任何地点、任何互联网设备上进行上传和下载数据。基于OSS,您可以搭建出各种多媒体分享网站、网盘、个人和企业数据备份等基于大规模数据的服务。

帮助文档: https://help.aliyun.com/document_detail/31947.html

还有要提醒的就是超时问题 不要 一 出现 Read timed out 或者 connect timed out 等 超时的问题 你就慌了

你先自己ping 一下 ip看看能不能通 如果能那么就代表 不是 你的问题

不要总是想是不是配置有问题 是不是代码写错误了 这里告诉你 一般正常情况默认配置能满足百分之90以上的需求的 所以基本就是 是网络问题 比如网络波动 或者 服务器突然卡死又恢复了

特别是上传大文件的时候突然网络一波动 呵呵连接就断开了 这一断开 那么就会出现 超时

所以在上传的时候 尽量限制 上传文件的大小

特别是批量上传 如果网络不好 一波动 那么部分就会导致上传失败

我觉得游览器上传文件一次总量不要超过20mb最好 如果服务器稍微好点这个可以调整高点

如果服务器不是很好 那么 10mb 就行 文件图片上传前尽量先使用本地工具压缩后在上传 这样也能提高速度

相册管理(SpringBoot)

相册是用于存储图片的管理单元 就好比是垃圾分类 把相同类型的图片放在一个相册里 这样比较好找 比较好管理

需要的Maven

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

<dependencies>

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

    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>provided</scope>
    </dependency>

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


    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
        <version>2.3.0.RELEASE</version>
    </dependency>


    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.1.5</version>
    </dependency>


    <!--分页插件-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.4</version>
    </dependency>
    <dependency>
        <groupId>com.github.jsqlparser</groupId>
        <artifactId>jsqlparser</artifactId>
        <version>0.9.5</version>
    </dependency>



    <!--http 服务-->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpmime</artifactId>
        <version>4.5</version>
    </dependency>


    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>


    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>


    <!--        模板引擎  -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>



    <!--    处理图片-->
    <dependency>
        <groupId>com.drewnoakes</groupId>
        <artifactId>metadata-extractor</artifactId>
        <version>2.15.0</version>
    </dependency>


     <!-- 配置gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>

</dependencies>

    <!--    自动查找主类  用于打包-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

表结构

imageitems表 (图片仓库) 所有图片都在此表中

字段名称字段含义字段类型备注
id编号 (IdWorker 生成)VARCHAR(100)主键
name图片名称VARCHAR(100)
image图片路径VARCHAR(100)
image_describe图片描述text
image_type图片类型VARCHAR(20)
image_size图片大小(mb)int(100)
image_px图片像素VARCHAR(100)
image_data图片上传的时间data
image_group图片对应fastDFS的组VARCHAR(50)
image_path图片全路径VARCHAR(100)
CREATE TABLE `imageitems` (
  `id` varchar(100) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `image` varchar(255) DEFAULT NULL,
  `image_describe` text,
  `image_type` varchar(20) DEFAULT NULL,
  `image_size` int(100) DEFAULT NULL,
  `image_px` varchar(100) DEFAULT NULL,
  `image_data` datetime DEFAULT NULL,
  `image_group` varchar(100) DEFAULT NULL,
  `image_path` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `id` (`id`) USING BTREE,
  KEY `image` (`image`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

图片仓库表 和 相册表 的 中间表 (将对应的图片关联到相册里)

album_imageitems

字段名称字段含义字段类型备注
id编号 (IdWorker 生成)VARCHAR(100)主键
album_id相册名称int(70)
imageitems_id相册封面图片路径int(70)
CREATE TABLE `album_imageitems` (
  `id` varchar(100) NOT NULL,
  `album_id` varchar(70) DEFAULT NULL,
  `imageitems_id` varchar(70) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `album_id` (`album_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

album 表(相册表

字段名称字段含义字段类型备注
id编号(IdWorker 生成)VARCHAR(100)主键
title相册名称VARCHAR(100)
image相册封面图片路径VARCHAR(100)
image_describe相册描述text
image_data创建相册的时间data
CREATE TABLE `album` (
  `id` varchar(100) NOT NULL,
  `title` varchar(255) DEFAULT NULL,
  `image` varchar(255) DEFAULT NULL,
  `image_describe` text,
  `image_data` datetime DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `id` (`id`) USING BTREE,
  KEY `title` (`title`) USING BTREE,
  KEY `image` (`image`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

resources

application.yml

server:
  port: 20210
  tomcat:
    max-http-post-size: -1

spring:
  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB
  application:
    name: file
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: root
  thymeleaf:
    cache: false

mybatis:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.fastdfs.pojo

fdfs_client.conf

connect_timeout=60
network_timeout=60
charset=UTF-8

#tracker文件上传是访问nginx的反向代理
http.tracker_http_port=80
 #tracker服务器地址  会自动轮询
tracker_server=192.168.66.67:22122
tracker_server=192.168.66.68:22122
tracker_server=192.168.66.69:22122

… 代码省略 自己根据业务情况 写

效果

我自己写的一个类似 图床的项目 管理图片的 前端没怎么写 后端代码基本能干的都实现了

本来是 集群的3个 FasDFS+3个nginx+3个Keepalived + 分布式SpringCloud 因为服务器太贵没钱买

变成了 一个FasDFS +SpringBoot 后果就是 响应的效率 以及上传图片的时间都大大的增加了

而且我买的 服务器也是最垃圾的 1核 1CPU 40G硬盘 5Mbps宽带 可想而知速度是有多慢

主页相册

鼠标点击效果

进入到相册里

查看图片

可直接查看和体验效果 http://fastdfs.huitoushian.cn/image.html 服务器有点小,响应图片有点慢 耐心点,毕竟图片这么多,加载是需要时间的

点赞 -收藏-关注-便于以后复习和收到最新内容
有其他问题在评论区讨论-或者私信我-收到会在第一时间回复
如有侵权,请私信联系我
感谢,配合,希望我的努力对你有帮助^_^
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡安民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值