下载
https://github.com/happyfish100/FastDFS
https://github.com/happyfish100/libfastcommon
https://github.com/happyfish100/fastdfs-nginx-module
fastdfs-5.11.tar.gz
libfastcommon-1.0.39.tar.gz
fastdfs-nginx-module-1.20.tar.gz
安装依赖
GCC libevent Nginx所需依赖
yum install -y gcc
yum install -y libevent
yum install -y pcre pcre-devel zlib zlib-devel openssl openssl-devel
安装libfastcommon (需要先安装它再安装fastdfs)
tar -xvf libfastcommon-1.0.39.tar.gz
cd libfastcommon-1.0.39/
./make.sh && ./make.sh install
同理,解压和编译安装一下fastdfs。
修改配置文件,默认在/etc/fdfs/
下
先把配置文件名中的sample去了。
然后修改tracker的存放数据和日志的目录。
并创建该目录:mkdir -p
加上路径
同理,修改storage的配置文件:
修改storage存储数据和日志的目录bath_path :base_path=/home/learn/fastdfs/storage
修改上传文件存储的目录store_path0:store_path0=/home/learn/fastdfs/storage
配置tracker的地址:tracker_server=192.168.58.129:22122
创建配置的目录文件夹。
启动:service fdfs_storaged start
解压:tar -xvf fastdfs-nginx-module-1.20.tar.gz
进入到解压后的目录下的src,修改config:
执行下面命令(将配置中的/usr/local改为/usr)
:%s+/usr/local/+/usr/+g
将mod_fastdfs.conf移动至fdfs运行的配置文件目录下
cp mod_fastdfs.conf /etc/fdfs/
并修改:
connect_timeout
超时时间选择修改tracker_server=192.168.58.129:22122
url_have_group_name = true
url中需要group组名store_path0=/home/learn/fastdfs/storage
之前配置的存储目录配置:
./configure --prefix=/opt/nginx --sbin-path=/usr/bin/nginx --add-module=/home/orcas/software/fastdfs/fastdfs-nginx-module-1.20/src
编译安装:
make && make install
然而它报错:
/usr/include/fastdfs/fdfs_define.h:15:27: fatal error: common_define.h: No such file or directory #include "common_define.h"
通过 http://blog.opstest.cn/?p=741 该文章解决问题。
修改fastdfs-nginx-module-1.20/src/config文件,修改如下:
ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/"
CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"
再重新执行 配置、编译、安装。
PS:如果之前已安装好nginx,就配置再编译,不用安装。
将nginx-1.12.2目录下的objs下的nginx脚本替换 /usr/bin/nginx
vim /etc/init.d/nginx
添加如下内容:
(注意两点:
nginx="/usr/bin/nginx"
, NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf"
要与之前配置的路径相同)
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig: - 85 15
# description: NGINX is an HTTP(S) server, HTTP(S) reverse \
# proxy and IMAP/POP3 proxy server
# processname: nginx
# config: /etc/nginx/nginx.conf
# config: /etc/sysconfig/nginx
# pidfile: /var/run/nginx.pid
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/bin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
make_dirs() {
# make required directories
user=`$nginx -V 2>&1 | grep "configure arguments:.*--user=" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
if [ -n "$user" ]; then
if [ -z "`grep $user /etc/passwd`" ]; then
useradd -M -s /bin/nologin $user
fi
options=`$nginx -V 2>&1 | grep 'configure arguments:'`
for opt in $options; do
if [ `echo $opt | grep '.*-temp-path'` ]; then
value=`echo $opt | cut -d "=" -f 2`
if [ ! -d "$value" ]; then
# echo "creating" $value
mkdir -p $value && chown -R $user $value
fi
fi
done
fi
}
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
sleep 1
start
}
reload() {
configtest || return $?
echo -n $"Reloading $prog: "
killproc $nginx -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
修改权限:
chmod 777 /etc/init.d/nginx
添加到服务列表:
chkconfig --add /etc/init.d/nginx
设置开机启动:
chkconfig nginx on
(本地hosts添加域名解析)
1、先便捷测试一下
同样修改client.conf配置文件中的base_path和tracker_server
在创建的那个目录中放一张图
然后上传,成功会返回文件id
group1/M00/00/00/wKg6gVw7FhqAWsRWAAKgjAHcRjA150.jpg
group1是group_name配置的组名
M00 是store_path0 (store_path1就是M01)
2、使用fastdfs的java客户端
依赖:
<dependency>
<groupId>net.oschina.zcx7878groupId>
<artifactId>fastdfs-client-javaartifactId>
dependency>
配置:
fastdfs:
connect_timeout_in_seconds: 5
network_timeout_in_seconds: 30
charset: UTF-8
tracker_servers: 192.168.58.129:22122 #多个 trackerServer中间以逗号分隔
代码参考:
@Value("${fastdfs.tracker_servers}")
private String tracker_servers;
@Value("${fastdfs.connect_timeout_in_seconds}")
private int connect_timeout;
@Value("${fastdfs.network_timeout_in_seconds}")
private int network_timeout;
@Value("${fastdfs.charset}")
private String charset;
@Override
public UploadFileResult upload(MultipartFile multipartFile) {
if (multipartFile == null) {
ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_FILE_IS_NULL);
}
// 上传至fastDFS, 返回文件id
String fileId = this.fdfsUpload(multipartFile);
if (StringUtils.isEmpty(fileId)) {
ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_SERVER_FAIL);
}
return new UploadFileResult(CommonCode.SUCCESS, fileId);
}
/**
* 上传至fastDFS
* @param multipartFile
* @return 文件id
*/
private String fdfsUpload(MultipartFile multipartFile) {
// 1. 初始化fastDFS的环境
initFdfsConfig();
// 2. 获取trackerClient服务
TrackerClient trackerClient = new TrackerClient();
try {
TrackerServer trackerServer = trackerClient.getConnection();
// 3. 获取storage服务
StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
// 4. 获取storageClient
StorageClient1 storageClient1 = new StorageClient1(trackerServer, storeStorage);
// 5. 上传文件 (文件字节, 文件扩展名, )
// 5.1 获取文件扩展名
String originalFilename = multipartFile.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
// 5.2 上传
String fileId = storageClient1.upload_file1(multipartFile.getBytes(), extName, null);
return fileId;
} catch (Exception e) {
ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_SERVERFAIL);
return null;
}
}
/**
* 初始化fastDFS的环境
*/
private void initFdfsConfig() {
try {
ClientGlobal.initByTrackers(tracker_servers);
ClientGlobal.setG_connect_timeout(connect_timeout);
ClientGlobal.setG_network_timeout(network_timeout);
ClientGlobal.setG_charset(charset);
} catch (Exception e) {
ExceptionCast.cast(FileSystemCode.FS_INIT_FDFS_ERROR);
}
}
启动项目,上传图片时报错连接超时,通过关闭centos的防火墙解决。
前端:
注意name这个属性的值是后端Controller层的@RequestParam值。
3、下面这个FastDFS客户端使用起来更简洁些。
依赖:
<dependency>
<groupId>com.github.tobatogroupId>
<artifactId>fastdfs-clientartifactId>
dependency>
配置:
fdfs:
so-timeout: 2500 # 读取时间
connect-timeout: 600 # 连接超时时间
thumb-image: # 缩略图
width: 100
height: 100
tracker-list: # tracker服务配置地址列表
- 192.168.58.129:22122
导入配置:
@Configuration
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastClientImporter {
}
注入FastFileStorageClient
后,可以直接调用其uploadFIle()
,比上一种方法省去了手动设置配置信息,也不需要自己建立tracker连接、获取storage、再获得storageClient这些准备工作。
/**
* @author Orcas
* @version V1.0.0
* @date 2018/11/7 6:50
*/
@Slf4j
@Service
@EnableConfigurationProperties(UploadProperties.class)
public class UploadService {
@Autowired
private FastFileStorageClient storageClient;
@Autowired
private UploadProperties prop;
public String uploadImage(MultipartFile file) {
// 1、校验文件类型
String contentType = file.getContentType();
if (!prop.getAllowTypes().contains(contentType)) {
ExceptionCast.cast(ExceptionEnum.INVALID_FILE_TYPE);
}
// 2、校验文件内容
try {
BufferedImage image = ImageIO.read(file.getInputStream());
if (image == null || image.getWidth() == 0 || image.getHeight() == 0) {
ExceptionCast.cast(ExceptionEnum.INVALID_FILE_TYPE);
}
} catch (IOException e) {
log.error("校验文件内容失败....{}", e);
ExceptionCast.cast(ExceptionEnum.INVALID_FILE_TYPE);
}
try {
// 3、上传到FastDFS
// 3.1、获取扩展名
String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
// 3.2、上传
StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extension, null);
// 返回路径
return prop.getBaseUrl() + storePath.getFullPath();
} catch (IOException e) {
log.error("【文件上传】上传文件失败!....{}", e);
ExceptionCast.cast(ExceptionEnum.UPLOAD_FILE_ERROR);
}
}
}
其中返回路径拼接从配置文件中读取
将下面的配置文件类注入
@ConfigurationProperties(prefix = "upload")
@Getter
@Setter
public class UploadProperties {
private String baseUrl;
private List<String> allowTypes;
}
upload:
base-url: http://img.orcas.com/
allow-types:
- image/jpeg
- image/png
- image/bmp