Spring Boot 技术探索

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

19、Spring Boot中文件的上传(使用FastDFS存储)

<p>平台环境:</p>

<table class="table table-sm">
    <tbody>
        <tr>
            <td>
            <p>名称</p>
            </td>
            <td>
            <p>版本号</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>Mac OS X</p>
            </td>
            <td>
            <p>10.14.6</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>JDK</p>
            </td>
            <td>
            <p>1.8.0_201</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>Apache Maven</p>
            </td>
            <td>
            <p>3.6.0</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>IntelliJ IDEA</p>
            </td>
            <td>
            <p>2019.1 (Ultimate Edition)</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>Spring Boot</p>
            </td>
            <td>
            <p>2.1.8.RELEASE</p>
            </td>
        </tr>
    </tbody>
</table>

<p>&nbsp;</p>

<p>  这个知识点只介绍了FastDFS客户端的使用,服务端搭建没有介绍。以后补充上。</p>

<p>&nbsp;</p>

<p>pom.xml引入依赖</p>

<pre>
<code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;!-- https://mvnrepository.com/artifact/org.csource/fastdfs-client-java --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.csource&lt;/groupId&gt;
    &lt;artifactId&gt;fastdfs-client-java&lt;/artifactId&gt;
    &lt;version&gt;1.27-SNAPSHOT&lt;/version&gt;
&lt;/dependency&gt;</code></pre>

<p>这一步遇到一个问题,fastdfs-client-java依赖引入的时候无法自动导入,红字错误。错误信息(Dependency &#39;org.csource:fastdfs-client-java:1.27-SNAPSHOT&#39; not found)</p>

<p>&nbsp;</p>

<p><strong>问题原因:</strong></p>

<p>因为fastdfs-client-java-1.27-SNAPSHOT.jar这个依赖包在maven中央仓库是没有的,需要自己编译源码成jar包并安装到maven的本地仓库,安装完以后就能正常引用了(注意:本地必须安装了Maven,并配置好Maven环境变量)</p>

<p>&nbsp;</p>

<p><strong>解决办法:</strong></p>

<p>1、复制fastdfs-client-java源码地址</p>

<p>访问地址https://github.com/happyfish100/fastdfs-client-java,点红圈中的图标,把地址复制到剪贴板。</p>

<p><img alt="" height="480" src="/pic/20191231162831881.jpeg" width="800" /></p>

<p>&nbsp;</p>

<p>2、在本机新建一个文件夹,名称不重要,例如fastdfs</p>

<p>打开&ldquo;终端&rdquo;工具,cd到新建文件夹下</p>

<pre>
<code class="language-xml">cd /Users/wang/Downloads/fastdfs</code></pre>

<p>输入命令,下载源码</p>

<pre>
<code>git clone https://github.com/happyfish100/fastdfs-client-java.git</code></pre>

<p>再cd到fastdfs-client-java目录</p>

<pre>
<code>cd fastdfs-client-java</code></pre>

<p>使用maven打包jar</p>

<pre>
<code>mvn clean install</code></pre>

<p>构建完成后会自动把fastdfs-client-java-1.27-SNAPSHOT.jar安装到本地的Maven仓库</p>

<pre>
<code>[INFO] Installing /Users/wang/Downloads/fastdfs/fastdfs-client-java/target/fastdfs-client-java-1.27-SNAPSHOT.jar to /Users/wang/.m2/repository/org/csource/fastdfs-client-java/1.27-SNAPSHOT/fastdfs-client-java-1.27-SNAPSHOT.jar
[INFO] Installing /Users/wang/Downloads/fastdfs/fastdfs-client-java/pom.xml to /Users/wang/.m2/repository/org/csource/fastdfs-client-java/1.27-SNAPSHOT/fastdfs-client-java-1.27-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  34.887 s
[INFO] Finished at: 2019-09-10T14:41:27+08:00
[INFO] ------------------------------------------------------------------------
wangdeMacBook-Pro:fastdfs-client-java wang$</code></pre>

<p>到此无法自动导入的问题就解决了。</p>

<p>&nbsp;</p>

<p>新建配置文件resources/fdfs_client.conf</p>

<pre>
<code># 连接超时时间
connect_timeout = 60


# 网络超时时间
network_timeout = 60


# 编码格式
charset = UTF-8


# tracker端口
http.tracker_http_port = 8080


# token防盗链功能
http.anti_steal_token = no
http.secret_key = 123456


# tracer server列表,多个tracer server的话,分行列出
tracker_server = 127.0.0.1:22122</code></pre>

<p>&nbsp;</p>

<p>新建工具类FastDFSFile</p>

<pre>
<code class="language-java">package com.example.demo.fastdfs;


public class FastDFSFile
{
    private String name;


    private byte[] content;


    private String ext;


    private String md5;


    private String author;


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


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


    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;
    }
}
</code></pre>

<p>&nbsp;</p>

<p>新建工具类FastDFSClient</p>

<pre>
<code class="language-java">package com.example.demo.fastdfs;


import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;


import java.io.*;


public class FastDFSClient
{
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);


    static
    {
        try
        {
            String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
            ClientGlobal.init(filePath);
        } catch (Exception e)
        {
            logger.error("FastDFS Client Init Fail!", e);
        }
    }


    public static String[] upload(FastDFSFile file)
    {
        logger.info("File Name: " + file.getName() + "File Length:" + file.getContent().length);


        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] = new NameValuePair("author", file.getAuthor());


        long startTime = System.currentTimeMillis();
        String[] uploadResults = null;
        StorageClient storageClient = null;
        try
        {
            storageClient = getStorageClient();
            uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
        } catch (IOException e)
        {
            logger.error("IO Exception when uploadind the file:" + file.getName(), e);
        } catch (Exception e)
        {
            logger.error("Non IO Exception when uploadind the file:" + file.getName(), e);
        }
        logger.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms");


        if (uploadResults == null &amp;&amp; storageClient != null)
        {
            logger.error("upload file fail, error code:" + storageClient.getErrorCode());
        }
        logger.info("upload file successfully!!!" + "group_name:" + uploadResults[0] + ", remoteFileName:" + " " + uploadResults[1]);
        return uploadResults;
    }


    public static FileInfo getFile(String groupName, String remoteFileName)
    {
        try
        {
            StorageClient storageClient = getStorageClient();
            return storageClient.get_file_info(groupName, remoteFileName);
        } catch (IOException e)
        {
            logger.error("IO Exception: Get File from Fast DFS failed", e);
        } catch (Exception e)
        {
            logger.error("Non IO Exception: Get File from Fast DFS failed", e);
        }
        return null;
    }


    public static InputStream downFile(String groupName, String remoteFileName)
    {
        try
        {
            StorageClient storageClient = getStorageClient();
            byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
            InputStream ins = new ByteArrayInputStream(fileByte);
            return ins;
        } catch (IOException e)
        {
            logger.error("IO Exception: Get File from Fast DFS failed", e);
        } catch (Exception e)
        {
            logger.error("Non IO Exception: Get File from Fast DFS failed", e);
        }
        return null;
    }


    public static void deleteFile(String groupName, String remoteFileName) throws Exception
    {
        StorageClient storageClient = getStorageClient();
        int i = storageClient.delete_file(groupName, remoteFileName);
        logger.info("delete file successfully!!!" + i);
    }


    public static StorageServer[] getStoreStorages(String groupName) throws IOException
    {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getStoreStorages(trackerServer, groupName);
    }


    public static ServerInfo[] getFetchStorages(String groupName, String remoteFileName) throws IOException
    {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
    }


    public static String getTrackerUrl() throws IOException
    {
        return "http://" + getTrackerServer().getInetSocketAddress().getHostString() + ":" + ClientGlobal.getG_tracker_http_port() + "/";
    }


    private static StorageClient getStorageClient() throws IOException
    {
        TrackerServer trackerServer = getTrackerServer();
        StorageClient storageClient = new StorageClient(trackerServer, null);
        return storageClient;
    }


    private static TrackerServer getTrackerServer() throws IOException
    {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerServer;
    }
}</code></pre>

<p>&nbsp;</p>

<p>新建上传页面upload.html</p>

<pre>
<code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Spring Boot file upload example&lt;/h1&gt;
    &lt;form method="POST" action="/uploadFile" enctype="multipart/form-data"&gt;
        &lt;input type="file" name="file" /&gt;&lt;br/&gt;&lt;br/&gt;
        &lt;input type="submit" value="Submit" /&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>

<p>&nbsp;</p>

<p>新建上传成功页面uploadStatus.html</p>

<pre>
<code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en" xmlns:th="http://www.thymeleaf.org"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Spring Boot - Upload Status&lt;/h1&gt;
    &lt;div th:if="${message}"&gt;
        &lt;h2 th:text="${message}"/&gt;
    &lt;/div&gt;


    &lt;div th:if="${path}"&gt;
        &lt;h2 th:text="${path}"/&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>

<p>&nbsp;</p>

<p>新建UploadController</p>

<pre>
<code class="language-java">package com.example.demo;


import com.example.demo.fastdfs.FastDFSClient;
import com.example.demo.fastdfs.FastDFSFile;
import org.csource.fastdfs.ClientGlobal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;


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


@Controller
public class UploadController
{
    private static Logger logger = LoggerFactory.getLogger(UploadController.class);


    @GetMapping("/upload")
    public String index()
    {
        System.out.println("ClientGlobal.configInfo(): " + ClientGlobal.configInfo());
        return "upload";
    }


    @PostMapping("/uploadFile")
    public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes)
    {
        if (file.isEmpty() &amp;&amp; file.getName().equals(""))
        {
            redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
            return "redirect:uploadStatus";
        }
        try
        {
            String path = saveFile(file);
            redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + file.getOriginalFilename() + "'");
            redirectAttributes.addFlashAttribute("path", "file path url '" + path + "'");
        } catch (Exception e)
        {
            logger.error("upload file failed", e);
        }
        return "redirect:/uploadStatus";
    }


    @GetMapping("/uploadStatus")
    public String uploadStatus()
    {
        return "uploadStatus";
    }


    /**
     * @param multipartFile
     * @return
     * @throws IOException
     */
    public String saveFile(MultipartFile multipartFile) throws IOException
    {
        String[] fileAbsolutePath = {};
        String fileName = multipartFile.getOriginalFilename();
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
        byte[] file_buff = null;
        InputStream inputStream = multipartFile.getInputStream();
        if (inputStream != null)
        {
            int len1 = inputStream.available();
            file_buff = new byte[len1];
            inputStream.read(file_buff);
        }
        inputStream.close();
        FastDFSFile file = new FastDFSFile(fileName, file_buff, ext);
        try
        {
            fileAbsolutePath = FastDFSClient.upload(file);  //upload to fastdfs
        } catch (Exception e)
        {
            logger.error("upload file Exception!", e);
        }
        if (fileAbsolutePath == null)
        {
            logger.error("upload file failed,please upload again!");
        }
        String path = FastDFSClient.getTrackerUrl() + fileAbsolutePath[0] + "/" + fileAbsolutePath[1];
        return path;
    }
}</code></pre>

<p>&nbsp;</p>

<p><strong>这个Demo由于缺少服务端暂时无法测试。</strong></p>

<p><strong>未完待续。</strong></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><strong>最后补充:</strong></p>

<p>在实际使用过程中如果想查看fastdfs的源码,则由于缺少源码文件导致IDEA给出的只有class反编译格式。这是由于我们在fastdfs-client-java的jar包制作过程中缺少了打包源码的步骤。</p>

<p><strong>解决办法是:</strong></p>

<p>1、打开之前建好的fastdfs文件夹,找到fastdfs-client-java里的pom.xml,打开后在&lt;build&gt;&lt;plugins&gt;标签内加入如下代码</p>

<pre>
<code class="language-xml">      &lt;!-- Source attach plugin --&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-source-plugin&lt;/artifactId&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;id&gt;attach-sources&lt;/id&gt;
            &lt;goals&gt;
              &lt;goal&gt;jar&lt;/goal&gt;
            &lt;/goals&gt;
          &lt;/execution&gt;
        &lt;/executions&gt;
      &lt;/plugin&gt;</code></pre>

<p>&nbsp;</p>

<p>2、打开&ldquo;终端&rdquo;,cd到fastdfs-client-java目录下,输入命令</p>

<pre>
<code>mvn clean install</code></pre>

<p>&nbsp;</p>

<p>3、此时就可以查看源码了。</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>
 

Bootstrap Thumbnail Second
MySQL

MySQL is the world's most popular open source database.

GO

Bootstrap Thumbnail Third
算法基础

本书介绍了什么是计算机算法,如何描述它们,以及如何来评估它们。

GO