fastdfs java整合,一步步完成FastDFS + Spring MVC上传下载整合示例

在上一篇博文【CentOS上安装分布式文件系统FastDFS & 配置和问题解决】,我们给出了CentOS上单机安装FastDFS和相关配置,为文件的上传、下载等操作做好了准备~

本文博文,我们将一步一步完成以FastDFS为文件存储,结合Spring MVC完成上传下载的整合示例

准备FastDFS连接jar包

下载代码

本文示例中,使用了两个代码库

将上述代码下载到本地,如

6d06b632f5c39d27a606792047ce0ea8.png

打包和Maven安装

将上述代码打包成一个jar包,如fastdfs-client-pool-java-0.0.1.jar

然后使用Maven完成从jar包安装~

mvn install:install-file -DgroupId=org.xxx -DartifactId=fastdfs-client-pool -Dversion=0.0.1 -Dpackaging=jar -Dfile=fastdfs-client-pool-java-0.0.1.jar

C:\Users\wangmengjun>mvn install:install-file -DgroupId=org.xxx -DartifactId=fastdfs-client-pool -Dversion=0.0.1 -Dpackaging=jar -Dfile=fastdfs-client-pool-java-0.0.1.jar

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building Maven Stub Project (No POM) 1

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom ---

[INFO] Installing C:\Users\wangmengjun\fastdfs-client-pool-java-0.0.1.jar to D:\java_tools\Reponsitories\Maven\org\xxx\fastdfs-client-pool\0.0.1\fastdfs-client-pool-0.0.1.jar

[INFO] Installing C:\Users\WANGME~1\AppData\Local\Temp\mvninstall6453901574382164817.pom to D:\java_tools\Reponsitories\Maven\org\xxx\fastdfs-client-pool\0.0.1\fastdfs-client-pool-0.0.1.pom

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 0.443 s

[INFO] Finished at: 2017-07-05T20:02:57+08:00

[INFO] Final Memory: 7M/244M

[INFO] ------------------------------------------------------------------------

成功之后,就可以直接在pom.xml中引用上述打包好的文件~ 如:

org.xxx

fastdfs-client-pool

0.0.1

搭建Spring MVC工程

一个简单的Spring MVC工程结构如下:

4bc4907941488df7f96ace8994a3e2ac.png

pom.xml添加依赖j包

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

4.0.0

com.xxx.tutorial.demo

fastdfs-springmvc-demo

war

0.0.1-SNAPSHOT

fastdfs-springmvc-demo Maven Webapp

http://maven.apache.org

UTF-8

4.3.6.RELEASE

javax.servlet

javax.servlet-api

3.1.0

jstl

jstl

1.2

taglibs

standard

1.1.2

org.springframework

spring-web

${spring.framework.version}

org.springframework

spring-webmvc

${spring.framework.version}

org.springframework

spring-core

${spring.framework.version}

org.springframework

spring-context-support

${spring.framework.version}

org.springframework

spring-context

${spring.framework.version}

org.springframework

spring-expression

${spring.framework.version}

org.springframework

spring-beans

${spring.framework.version}

org.springframework

spring-aspects

${spring.framework.version}

org.springframework

spring-aop

${spring.framework.version}

ch.qos.logback

logback-core

1.1.3

ch.qos.logback

logback-classic

1.1.3

com.alibaba

fastjson

1.2.28

org.slf4j

slf4j-log4j12

1.7.7

commons-pool

commons-pool

1.5.5

org.xxx

fastdfs-client-pool

0.0.1

commons-fileupload

commons-fileupload

1.3.3

fastdfs-springmvc-demo

创建xml配置文件

b9d5dc9d097fd8922ed4008e92793681.png

applicationContext.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"

xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop" xmlns:websocket="http://www.springframework.org/schema/websocket"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-4.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-4.0.xsd

http://www.springframework.org/schema/task

http://www.springframework.org/schema/task/spring-task-4.0.xsd">

class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

class="org.springframework.beans.factory.config.PropertiesFactoryBean">

classpath:fdfs_client.properties

class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">

spring-mvc.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

class="org.springframework.web.servlet.view.InternalResourceViewResolver">

/WEB-INF/jsp/

.jsp

cache-period="31556926" />

class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

classpath:fdfs_client.properties

fdfs_client.properties

connect_timeout = 2000

network_timeout = 30000

charset = UTF-8

http.tracker_http_port = 80

http.anti_steal_token = false

http.secret_key = FastDFS1234567890

tracker_server = :22122

#fasfdfs nginx port

tracker_nginx_port=19080

tracker_nginx_host=

#pool config

pool.maxActive = 20

pool.maxIdle = 5

pool.minIdle = 2

pool.maxWait = 100

pool.testOnBorrow = false

pool.testOnReturn = false

pool.testWhileIdle = true

配置web.xml

couchbaseRPC

contextConfigLocation

classpath:applicationContext.xml

org.springframework.web.context.ContextLoaderListener

Spring-MVC

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:spring-mvc.xml

2

Spring-MVC

/

encodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

UTF-8

forceEncoding

true

encodingFilter

/*

org.springframework.web.util.IntrospectorCleanupListener

index.jsp

60

Spring MVC工程基本的完成了,接下来,我们就要为操作FastDFS上的文件做准备工作了~

FastDFS操作类

FastDFSFile

FastDFS文件属性~

package com.xxx.tutorial.demo.fdfs;

import java.io.Serializable;

import java.util.Arrays;

public class FastDFSFile implements Serializable {

private static final long serialVersionUID = 1072167272807139878L;

private byte[] content;

private String name;

private String suffix;

private String length;

private String author;

/**

* @return the content

*/

public byte[] getContent() {

return content;

}

/**

* @param content

* the content to set

*/

public void setContent(byte[] content) {

this.content = content;

}

/**

* @return the name

*/

public String getName() {

return name;

}

/**

* @param name

* the name to set

*/

public void setName(String name) {

this.name = name;

}

/**

* @return the suffix

*/

public String getSuffix() {

return suffix;

}

/**

* @param suffix

* the suffix to set

*/

public void setSuffix(String suffix) {

this.suffix = suffix;

}

/**

* @return the length

*/

public String getLength() {

return length;

}

/**

* @param length

* the length to set

*/

public void setLength(String length) {

this.length = length;

}

/**

* @return the author

*/

public String getAuthor() {

return author;

}

/**

* @param author

* the author to set

*/

public void setAuthor(String author) {

this.author = author;

}

/*

* (non-Javadoc)

*

* @see java.lang.Object#toString()

*/

@Override

public String toString() {

return "FastDFSFile [content=" + Arrays.toString(content) + ", name=" + name + ", suffix=" + suffix

+ ", length=" + length + ", author=" + author + "]";

}

}

FastDFSConfig

FastDFS配置类~

package com.xxx.tutorial.demo.fdfs;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;

@Component

public class FastDFSConfig {

@Value("#{configProperties['pool.maxActive']}")

private int maxActive;

@Value("#{configProperties['pool.maxIdle']}")

private int maxIdle;

@Value("#{configProperties['pool.minIdle']}")

private int minIdle;

@Value("#{configProperties['pool.maxWait']}")

private int maxWait;

@Value("#{configProperties['pool.testOnBorrow']}")

private boolean testOnBorrow;

@Value("#{configProperties['pool.testOnReturn']}")

private boolean testOnReturn;

@Value("#{configProperties['pool.testWhileIdle']}")

private boolean testWhileIdle;

@Value("#{configProperties['tracker_nginx_host']}")

private String trackerNginxHost = "localhost";

@Value("#{configProperties['tracker_nginx_port']}")

private String trackerNginxPort = "80";

/**

* @return the maxActive

*/

public int getMaxActive() {

return maxActive;

}

/**

* @param maxActive

* the maxActive to set

*/

public void setMaxActive(int maxActive) {

this.maxActive = maxActive;

}

/**

* @return the maxIdle

*/

public int getMaxIdle() {

return maxIdle;

}

/**

* @param maxIdle

* the maxIdle to set

*/

public void setMaxIdle(int maxIdle) {

this.maxIdle = maxIdle;

}

/**

* @return the minIdle

*/

public int getMinIdle() {

return minIdle;

}

/**

* @param minIdle

* the minIdle to set

*/

public void setMinIdle(int minIdle) {

this.minIdle = minIdle;

}

/**

* @return the maxWait

*/

public int getMaxWait() {

return maxWait;

}

/**

* @param maxWait

* the maxWait to set

*/

public void setMaxWait(int maxWait) {

this.maxWait = maxWait;

}

/**

* @return the testOnBorrow

*/

public boolean isTestOnBorrow() {

return testOnBorrow;

}

/**

* @param testOnBorrow

* the testOnBorrow to set

*/

public void setTestOnBorrow(boolean testOnBorrow) {

this.testOnBorrow = testOnBorrow;

}

/**

* @return the testOnReturn

*/

public boolean isTestOnReturn() {

return testOnReturn;

}

/**

* @param testOnReturn

* the testOnReturn to set

*/

public void setTestOnReturn(boolean testOnReturn) {

this.testOnReturn = testOnReturn;

}

/**

* @return the testWhileIdle

*/

public boolean isTestWhileIdle() {

return testWhileIdle;

}

/**

* @param testWhileIdle

* the testWhileIdle to set

*/

public void setTestWhileIdle(boolean testWhileIdle) {

this.testWhileIdle = testWhileIdle;

}

/**

* @return the trackerNginxHost

*/

public String getTrackerNginxHost() {

return trackerNginxHost;

}

/**

* @param trackerNginxHost

* the trackerNginxHost to set

*/

public void setTrackerNginxHost(String trackerNginxHost) {

this.trackerNginxHost = trackerNginxHost;

}

/**

* @return the trackerNginxPort

*/

public String getTrackerNginxPort() {

return trackerNginxPort;

}

/**

* @param trackerNginxPort

* the trackerNginxPort to set

*/

public void setTrackerNginxPort(String trackerNginxPort) {

this.trackerNginxPort = trackerNginxPort;

}

}

FastDFSFileManager

文件管理,包含FastDFS文件的上传和下载等~

package com.xxx.tutorial.demo.service;

import org.csource.common.NameValuePair;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.fast.pool.FastdfsPool;

import com.fast.pool.FastdfsPoolConfig;

import com.fast.pool.StorageClient;

import com.xxx.tutorial.demo.fdfs.FastDFSConfig;

import com.xxx.tutorial.demo.fdfs.FastDFSFile;

@Service

public class FastDFSFileManager {

/** 协议 */

private static final String PROTOCOL = "http://";

/** 路径分隔符 */

private static final String SEPARATOR = "/";

@Autowired

private FastDFSConfig config;

/**

* 上传,附加属性

*

* @param file

* @param valuePairs

* @return

* @throws Exception

*/

public String[] upload(FastDFSFile file, NameValuePair[] valuePairs) throws Exception {

FastdfsPool pool = new FastdfsPool(initPoolConfig(), "fdfs_client.properties");

StorageClient storageClient = null;

String[] uploadResults = null;

try {

storageClient = pool.getResource();

uploadResults = storageClient.upload_file(file.getContent(), file.getSuffix(), valuePairs);

} catch (Exception e1) {

pool.returnResource(storageClient);

} finally {

pool.returnResource(storageClient);

}

return uploadResults;// getFileUrl(uploadResults);

}

/**

* 初始化配置

*

* @return

*/

private FastdfsPoolConfig initPoolConfig() {

FastdfsPoolConfig poolCfg = new FastdfsPoolConfig();

poolCfg.setMaxActive(config.getMaxActive());

poolCfg.setMaxIdle(config.getMaxIdle());

poolCfg.setMaxWait(config.getMaxWait());

poolCfg.setMinIdle(config.getMinIdle());

poolCfg.setTestOnBorrow(config.isTestOnBorrow());

poolCfg.setTestOnReturn(config.isTestOnReturn());

poolCfg.setTestWhileIdle(config.isTestWhileIdle());

return poolCfg;

}

/**

* 上传

*

* @param file

* @return

* @throws Exception

*/

public String[] upload(FastDFSFile file) throws Exception {

return upload(file, null);

}

/**

* 组装文件路径

*

* @param uploadResults

* @return

*/

private String getFileUrl(String[] uploadResults) {

if (uploadResults != null) {

String groupName = uploadResults[0];

String remoteFileName = uploadResults[1];

StringBuilder sb = new StringBuilder();

sb.append(PROTOCOL);

sb.append(config.getTrackerNginxPort());

sb.append(":");

sb.append(SEPARATOR);

sb.append(groupName);

sb.append(SEPARATOR);

sb.append(remoteFileName);

return sb.toString();

} else {

return null;

}

}

public byte[] downloadFile(String groupName, String remoteFileName) throws Exception {

FastdfsPool pool = new FastdfsPool(initPoolConfig(), "fdfs_client.properties");

StorageClient storageClient = null;

byte[] downloadResults = null;

try {

storageClient = pool.getResource();

downloadResults = storageClient.download_file(groupName, remoteFileName);

} catch (Exception e) {

e.printStackTrace();

} finally {

pool.returnResource(storageClient);

}

return downloadResults;

}

}

文件上传

通过

org.xxx

fastdfs-client-pool

0.0.1

使用fastdfs连接工具包,其中,com.fast.pool.StorageClient提供了文件上传的多种方法,如:

34852b58e872f4c3c63d5f6c414de967.png

上传文件的方法可以在FastDFSFileManager类中找到,如:

public String[] upload(FastDFSFile file, NameValuePair[] valuePairs) throws Exception {

FastdfsPool pool = new FastdfsPool(initPoolConfig(), "fdfs_client.properties");

StorageClient storageClient = null;

String[] uploadResults = null;

try {

storageClient = pool.getResource();

uploadResults = storageClient.upload_file(file.getContent(), file.getSuffix(), valuePairs);

} catch (Exception e1) {

pool.returnResource(storageClient);

} finally {

pool.returnResource(storageClient);

}

return uploadResults;// getFileUrl(uploadResults);

}

文件上传后会返回一个String数组,其中,

第一个元素为GroupName,如group1

第二个元素为RemoteFileName, 如M00/00/00/rBcfylkawqaAbttWAAKucQftPc0621.jpg

文件控制器类

package com.xxx.tutorial.demo.controller;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.alibaba.fastjson.JSONObject;

import com.xxx.tutorial.demo.fdfs.FastDFSFile;

import com.xxx.tutorial.demo.service.FastDFSFileManager;

@Controller

@RequestMapping("/file")

public class FileController {

@Autowired

private FastDFSFileManager fdfsClient;

/**

* 转到文件上传页面

*/

@RequestMapping("/add")

public String login() {

return "file_add";

}

@RequestMapping(value = "/upload", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")

@ResponseBody

public String uploadFile(@RequestParam("file") CommonsMultipartFile uploadFile, HttpServletRequest request,

HttpServletResponse response) {

String originalFilename = uploadFile.getOriginalFilename();

String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);

JSONObject jsonObj = new JSONObject();

try {

FastDFSFile fdfsFile = new FastDFSFile();

fdfsFile.setContent(uploadFile.getBytes());

fdfsFile.setSuffix(fileSuffix);

String[] uploadResult = fdfsClient.upload(fdfsFile);

jsonObj.put("success", "Y");

jsonObj.put("groupName", uploadResult[0]);

jsonObj.put("remoteFileName", uploadResult[1]);

return jsonObj.toJSONString();

} catch (IOException e) {

e.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

}

return jsonObj.toJSONString();

}

}

编写文件上传jsp

pageEncoding="utf-8"%>

文件上传页面

id="J_upload_form">

id="J_file_ok" value="上传" />

下载

7641ec734b860800984a9a951112fc91.png

页面内容很简单,

“上传”按钮将提交选中的文件,然后,返回给页面FastDFS文件的groupName和remoteFileName~。

然后点击“下载”按钮就可以根据groupName和remoteFileName下载刚刚上传的文件~

编写上传文件的js

$(function() {

/**

* 上传按钮点击

*/

$('#J_file_ok').click(function() {

/**

* 文件上传表单处理

*/

$('#J_upload_form').ajaxForm({

beforeSend : function() {

// 表单提交前做表单验证

},

success : function(result) {

if (result.success == 'Y') {

var downloadURL = "download?groupName="+result.groupName+"&remoteFileName="+result.remoteFileName;

$('#J_download').attr('href',downloadURL);

}

},

dataType : 'json'

}).submit();

});

});

jsp和js的目录结构如下~

6fb66aa6b284b82506fee3820fea7d84.png

其中,文件上传使用了jquey.form.js来做~

注意,

文件上传需要配置multipartResolver,如:

class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

上传一个文件,然后debug一下试试~

db616dc9db4f54bdf30fb267e06e6e02.png

可以看出上传后已经成功返回groupName和remoteFileName~

至此,上传部分已经完成了~

文件下载

FastDFS的文件下载还是采用com.fast.pool.StorageClient类来完成~,其包含的download方法如下:

343f7ef8ee59e44fc81a52f0c1cb9437.png

下载文件的方法可以在FastDFSFileManager类中找到,如:

public byte[] downloadFile(String groupName, String remoteFileName) throws Exception {

FastdfsPool pool = new FastdfsPool(initPoolConfig(), "fdfs_client.properties");

StorageClient storageClient = null;

byte[] downloadResults = null;

try {

storageClient = pool.getResource();

downloadResults = storageClient.download_file(groupName, remoteFileName);

} catch (Exception e) {

e.printStackTrace();

} finally {

pool.returnResource(storageClient);

}

return downloadResults;

}

页面添加FastDFS文件下载链接

下载

其中,下载的路径是通过上传文件表单提交成功后,返回拼凑的,如~

$('#J_upload_form').ajaxForm({

beforeSend : function() {

// 表单提交前做表单验证

},

success : function(result) {

if (result.success == 'Y') {

var downloadURL = "download?groupName="+result.groupName+"&remoteFileName="+result.remoteFileName;

$('#J_download').attr('href',downloadURL);

}

},

dataType : 'json'

}).submit();

控制器编写下载方法

@RequestMapping(value = "/download", method = RequestMethod.GET)

public ResponseEntity downloadFile(String groupName, String remoteFileName, HttpServletResponse response)

throws Exception {

String fileName = remoteFileName.substring(remoteFileName.lastIndexOf("/") + 1);

response.setCharacterEncoding("utf-8");

response.setContentType("multipart/form-data");

response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);

try {

OutputStream os = response.getOutputStream();

byte[] b = fdfsClient.downloadFile(groupName, remoteFileName);

os.write(b, 0, b.length);

os.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

至此,使用FastDFS存储文件,使用Spring MVC完成文件上传和下载的整合示例就全部完成了,具体的Maven工程结构如下图所示:

9c6cd53cccc8cbce582b10ecad859856.png

上传下载功能验证

运行工程,来测试一下上传下载的功能~

访问文件上传页面

b45b89a68f3059d8fa8dc3d5add853f3.png

选择一个图片文件,点击“上传”按钮上传文件

点击“选择文件”按钮,选择要上传的文件

ada53ebcfd58a426359a185fa7950bd4.png

然后,

558a66aad0a2abb0b65fdda821fef799.png

并点击“上传”按钮~

点击“下载”链接下载刚刚上传的图片

2a2ae879f090e15c0ca28f1411aed1bc.png

可以从上图左下角看出,文件已经下载~ 点击打开,看到和我们上传的图片是一样的~

c39c598cc580940ec108de7f850f9ded.png

至此,一个简单的FastDFS存储文件,并使用Spring MVC完成上传下载的整合示例就完成了~

小结

本文我们一步一步完成以FastDFS为文件存储,结合Spring MVC完成上传下载的整合示例。

本文给出的示例比较简单,采用com.fast.pool.StorageClient类还可以完成其它操作,

如“删除文件” --【删除文件和下载文件一样,也使用了groupName和remoteFileName】

0548eadea67dc98111e4bcad96dc04fa.png

文件追加等功能~

cc40c819dc3db4ce0b2da8ac53ec3a74.png

分片上传、分片下载等功能将不再本文给出~

有兴趣的读者,可以自己玩玩并做些更加深入的研究~

f73f69bd3c59bad1708ca783638260a3.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值