一、品牌新增功能(图片上传)
1、新建一个微服务:文件的上传的微服务
2、添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>leyou</artifactId>
<groupId>com.leyou.parent</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.leyou.service</groupId>
<artifactId>ly-upload</artifactId>
<dependencies>
<!--引入注册中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--引入web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入Test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
3、编写配置文件
4、编写启动类
5、分析文件上传
现在的文件上传与Servlet的文件上传不同,现在的文件上传是单独的一个微服务,测试演示
当选择文件后就会触发文件上传
- 完善一下提交的路径以及其他的参数
<v-flex>
<v-upload v-model="brand.image" url="/upload/image" :multiple="false" :pic-width="250" :pic-height="90"
/>
</v-flex>
- 返回结果,上传文件后表单需要得到对应的的文件的路径,即表单提交的的时候需要知道对应文件的路径
6、编写上传功能(校验文件)
(1)controller
编写controller需要知道4个内容:
- 请求方式:上传肯定是POST
- 请求路径:/upload/image
- 请求参数:文件,参教名是file,SpringMVvc会封装为一个接口:MultipleFile
- 返回结果:上传成功后得到的文件的url路径
代码如下:
package com.leyou.upload.web;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("upload")
public class UploadController {
/*
上传图片功能
*/
@PostMapping("image") //当做文件上传的时候SpringMVC会自动将上传的文件封装到MultipartFile当中
public ResponseEntity<String> uploadImage(@RequestParam("file")MultipartFile file){
}
}
(2)service
package com.leyou.upload.service;
import org.springframework.stereotype.Service;
@Service
public class UploadService {
}
(3)在控制层当中注入Service
package com.leyou.upload.web;
import com.leyou.upload.service.UploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("upload")
public class UploadController {
@Autowired
private UploadService uploadService;
/*
上传图片功能
*/
@PostMapping("image") //当做文件上传的时候SpringMVC会自动将上传的文件封装到MultipartFile当中
public ResponseEntity<String> uploadImage(@RequestParam("file")MultipartFile file){
String url = uploadService.uploadImage(file);
return ResponseEntity.ok(url);
}
}
(4)完善业务层
package com.leyou.upload.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@Service
public class UploadService {
public String uploadImage(MultipartFile file) {
//准备目标路径
File dest = new File("");
//保存文件到本地
//返回图片路径
return null;
}
}
(5)创建一个文件夹用于上传文件
在当工程的目录傍边下创建对应的文件路径
(6)完善上传文件的业务层
- 添加common的依赖
<dependency>
<groupId>com.leyou.common</groupId>
<artifactId>ly-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
- 编写文件上传失败对应的枚举
UPLOAD_FILE_ERROR(500,"文件上传失败"),
- 继续完善业务层,设置文件上传失败的时候抛出对应的异常信息
package com.leyou.upload.service;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
public class UploadService {
// Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");
public String uploadImage(MultipartFile file) {
try {
//校验文件类型
String contentType = file.getContentType();
if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
}
//准备目标路径
File dest = new File("D:/IDEAWORK/upload/"+file.getOriginalFilename());
//保存文件到本地
file.transferTo(dest);
return "http://image.leyou.com/" + file.getOriginalFilename();
} catch (IOException e) {
//如果上传失败,记录日志信息
log.error("上传文件失败",e);
//返回错误结果
throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
}
//返回图片路径
}
}
- 设置抛出的异常信息
INVALID_FILE_TYPE(400,"无效的文件类型"),
- 继续完善业务层,设置抛出异常信息
//校验文件类型
String contentType = file.getContentType();
if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
(7)校验文件内容(继续完善业务层内容)
//校验文件的内容
BufferedImage image = ImageIO.read(file.getInputStream());
if(image == null){
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
全部代码
package com.leyou.upload.service;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
public class UploadService {
// Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");
public String uploadImage(MultipartFile file) {
try {
//校验文件类型
String contentType = file.getContentType();
if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
//校验文件的内容
BufferedImage image = ImageIO.read(file.getInputStream());
if(image == null){
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
//准备目标路径
File dest = new File("D:/IDEAWORK/upload/"+file.getOriginalFilename());
//保存文件到本地
file.transferTo(dest);
return "http://image.leyou.com/" + file.getOriginalFilename();
} catch (IOException e) {
//如果上传失败,记录日志信息
log.error("上传文件失败",e);
//返回错误结果
throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
}
//返回图片路径
}
}
7、运行测试
重新启动项目
启动文件上传的微服务项目
打开测试工具
http://localhost:8084/upload/image
请求成功并返回对应的图片路径
并在对应的文件夹下找到对应上传的图片
上传其他错误文件
发送
8、完善网页文件上传功能(忽略路由前缀)
当点击图片的时候报404
(1)在网关当中配置文件上传微服务的路由(文件上传当中配置的前缀是)
upload-service :
path: /upload/** #设置对应微服务映射的路径的前缀upload不去除
serviceId : upload-service #upload-service对应微服务的名称代替了ip地址 10010地址映射到8084
strip-prefix: false
#由于网关捕获到upload之后页面的url只剩下/image,
#但是controller里面是/upload/image,所以不能去除upload的前缀
(2)重新启动运行测试项目
再次测试发送请求成功
9、绕过网关缓存
默认情况下,所有的请求经过Zuul网关的代理,默认会通过SpringMVC 预先对请求进行处理,缀存。
普通请求井不会有什么影响,但是对于文件上传,.就会造成遗成不必要的网络负担。
在高井发时,可能导致网络阻塞,Zuul网关不可用这拌我们的整个系统就瘫换了
所以,我们上传文件的请求需要绕过请求的缓存,直接通过路由到达目标微服务:
Zuul is implemented as a Servlet. For the general cases,
Zuul is embedded into the Spring Dispatch mechanism.
This lets Spring MVC be in control of the routing.
In this case, Zuul buffers requests.
If there is a need to go throughZuul without buffering requests
(for example, for large file uploads),
the Servlet is also installed outside of the
Spring Dispatcher. By default, the servlet has an address of /zuul .
This path can be changed with the zuul.servletpath property.
Zuul实现为一个Servlet。对于一般情况,Zuul被嵌入到Spring调度机制中,这使得Spring MVC能够控制路由。在这种情况下,Zuul缓冲请求。如果需要在不缓冲请求的情况下通过ZUUL(例如,对于大型文件上载),Servlet也会安装在
Spring 调度员。默认情况下,servlet的地址为/zuul。
可以使用zuul.servletpath属性更改此路径。
也就是说在请求路径的前面加上/zuul,就会跳过Zuul的缓存,不是不去网关,只是跳过了请求缓存
(1)现在修改页面的访问路径(需要在api前面加Zuul)修改Nginx的配置文件
但是不可以直接改变请求访问页面的路径
我们需要修改到以/zuul为前缀,
可以通过nginx的rewrite指令实现这一需求:
Nginx提供了rewrite指令,用于对地址进行重写,语法规则:
rewrite“用来匹配路径的正则”重写后的路径[指令];
通过cd linux指令找到对应nginx的配置文件当中conf当中的nginx.conf文件
vim 命令打开文件添加以下内容
location /api/upload {
rewrite "^/(.*)$" /zuul/$1;
}
重写reload nginx
nginx -s reload
(2)再次运行访问
看不出区别,但是在文件上传的时候,效率会提升
10、FastDFS(完善文件上传的保存功能以及显示图片)
(1)什么是分布式文件系统
分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。
通俗来讲;
- 传统文件系统管理的文件就存储在本机。
- 分布式文件系统管理的文件存储在很多机器,这些机器通过网络连接,要被统一管理。无论是上传或者访问文
件,都需要通过管理中心来访问
(2)什么是FastDFS
FastDFS是由淘宝的余庆先生所开发的一个轻量级、高性能的开源分布式文件系统。用纯c语言开发,功能丰富:
- 文件存储
- 文件同步
- 文件访问(上传、下载)
- 存取负载均衡
- 在线扩容
适合有大容量存储需求的应用或系统。同类的分布式文件系统有谷歌的GFS、HDFS (Hadoop)、TFS(淘宝〉等。
(3)FastDFS的结构
FastDFS两个主要的角色:Tracker Server和Storage Server .
-
Tracker Server:跟踪服务器,主要负责调度storage节点与client通信,在访问上起负载均衡的作用,和记录storage节点的运行状态,是连接client和storage节点的枢纽。
-
Storage Server:存储服务器,保存文件和文件的meta data (元数据),每个storage server会启动一个单独的线程主动向Tracker cluster中每个tracker server报告其状态信息,包括磁盘使用情况,文件同步情况及文件上传下载次数统计等信息
-
Group:文件组,多台Storage Server的集群。上传一个文件到同组内的一台机器上后,FastDFs会将该文件即时同步到同组内的其它所有机器上,起到备份的作用。不同组的服务器,保存的数据不同,而且相互独立,不进行通信。
-
Tracker Cluster:跟踪服务器的集群,有一组Tracker Server(跟踪服务器)组成。
-
Storage Cluster :存储集群,有多个Group组成。
(4)上传和下载的流程
最小化部署图
文件上传原理:
1.Client通过Tracker server查找可用的Storage server。
2.Tracker server向client返回一台可用的Storage server的IP地址和端口号。
3. Client直接通过Tracker server返回的IP地址和端口与其中一台Storage server建立连接并进行文件上传。
4.上传完成,Storage server返回Client一个文件ID,文件上传结束。
文件下载原理:
1.Client通过Tracker server查找要下载文件所在的的Storage server。
2. Tracker server向Client返回包含指定文件的某个Storage server的IP地址和端口号。
3. Client直接通过Tracker server返回的IP地址和端口与其中一台Storage server建立连接并指定要下载文件。4.下载文件成功。
(5)安装和使用(Centos下安装FastDFS)
1)上传
将以下内容上传到linux下的/home/leyou/fdfs
目录:
https://download.csdn.net/download/qq_44757034/20901739
2)安装依赖
FastDFS运行需要一些依赖,在课前资料提供的虚拟中已经安装好了这些依赖,如果大家想要从头学习,可以按下面方式安装:
a、安装GCC依赖
GCC用来对C语言代码进行编译运行,使用yum命令安装:
GCC用来对C语言代码进行编译运行,使用yum命令安装:
sudo yum -y install gcc
b、 安装unzip工具
unzip工具可以帮我们对压缩包进行解压
sudo yum install -y unzip zip
c、 安装libevent
sudo yum -y install libevent
d、 安装Nginx所需依赖
sudo yum -y install pcre pcre-devel zlib zlib-devel openssl openssl-devel
d、 安装libfastcommon-master
这个没有yum包,只能通过编译安装:
-
解压刚刚上传的
libfastcommon-master.zip
unzip libfastcommon-master.zip
-
进入解压完成的目录:
cd libfastcommon-master
-
编译并且安装:
sudo ./make.sh sudo ./make.sh install
到这里为止,所有依赖都已经安装完毕,接下来我们安装FastDFS:
3)安装FastDFS
a、 编译安装
这里我们也采用编译安装,步骤与刚才的编译安装方式一样:
发回上一级别目录
cd ../
-
解压
tar -xvf FastDFS_v5.08.tar.gz
-
进入目录
cd FastDFS
-
编译并安装
sudo ./make.sh sudo ./make.sh install
- 校验安装结果
1)安装完成,我们应该能在/etc/init.d/
目录,通过命令ll /etc/init.d/ | grep fdfs
看到FastDFS提供的启动脚本:
2)我们可以在 /etc/fdfs
目录,通过命令查看到以下配置文件模板:
其中:
tarcker.conf.sample
是tracker的配置文件模板storage.conf.sample
是storage的配置文件模板client.conf.sample
是客户端的配置文件模板
b、 启动tracker
FastDFS的tracker和storage在刚刚的安装过程中,都已经被安装了,因此我们安装这两种角色的方式是一样的。不同的是,两种需要不同的配置文件。
我们要启动tracker,就修改刚刚看到的tarcker.conf
,并且启动fdfs_trackerd
脚本即可。
- 编辑tracker配置
首先我们将模板文件进行赋值和重命名:
sudo cp tracker.conf.sample tracker.conf
sudo vim tracker.conf
打开tracker.conf
,修改base_path
配置:
base_path=/leyou/fdfs/tracker # tracker的数据和日志存放目录
- 创建目录
刚刚配置的目录可能不存在,我们创建出来
sudo mkdir -p /leyou/fdfs/tracker
-
启动tracker
我们可以使用
sh /etc/init.d/fdfs_trackerd
启动,不过安装过程中,fdfs已经被设置为系统服务,我们可以采用熟悉的服务启动方式:
sudo service fdfs_trackerd start # 启动fdfs_trackerd服务,停止用stop
另外,我们可以通过以下命令,设置tracker开机启动:
sudo chkconfig fdfs_trackerd on
c、启动storage
我们要启动tracker,就修改刚刚看到的tarcker.conf
,并且启动fdfs_trackerd
脚本即可。
- 编辑storage配置
首先我们将模板文件进行赋值和重命名:
sudo cp storage.conf.sample storage.conf
sudo vim storage.conf
打开storage.conf
,修改base_path
配置:
base_path=/leyou/fdfs/storage # storage的数据和日志存放目录
store_path0=/leyou/fdfs/storage # storage的上传文件存放路径
tracker_server=192.168.56.101:22122 # tracker的地址
- 创建目录
刚刚配置的目录可能不存在,我们创建出来
sudo mkdir -p /leyou/fdfs/storage
-
启动storage
我们可以使用
sh /etc/init.d/fdfs_storaged
启动,同样我们可以用服务启动方式:
sudo service fdfs_storaged start # 启动fdfs_storaged服务,停止用stop
另外,我们可以通过以下命令,设置tracker开机启动:
sudo chkconfig fdfs_storaged on
最后,通过ps -ef | grep fdfs
查看进程:
测试上传
将一张图片上传到/var/333.png
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /var/333.png
得到返回数据:group1/M00/00/00/rBEACmEPpcyAcBNZAAFkkXlaVjk629.png
4)安装Nginx及FastDFS模块
a、 FastDFS的Nginx模块
切换到
cd /home/leyou/fdfs
-
解压
tar -xvf fastdfs-nginx-module_v1.16.tar.gz
-
配置config文件
# 进入配置目录 cd /home/leyou/fdfs/fastdfs-nginx-module/src/ # 修改配置 vim config # 执行下面命令(将配置中的/usr/local改为/usr): :%s+/usr/local/+/usr/+g
保存退出
-
配置mod_fastdfs.conf
# 将src目录下的mod_fastdfs.conf复制到 /etc/fdfs目录: sudo cp mod_fastdfs.conf /etc/fdfs/ # 编辑该文件 sudo vim /etc/fdfs/mod_fastdfs.conf
-
修改一下配置:
connect_timeout=10 # 客户端访问文件连接超时时长(单位:秒) tracker_server=192.168.56.101:22122 # tracker服务IP和端口 url_have_group_name=true # 访问链接前缀加上组名 store_path0=/leyou/fdfs/storage # 文件存储路径
-
复制 FastDFS的部分配置文件到/etc/fdfs目录
cd /home/leyou/fdfs/FastDFS/conf/
cp http.conf mime.types /etc/fdfs/
b、 安装Nginx
切换回fdfs目录下
-
解压
tar -xvf nginx-1.10.0.tar.gz
-
配置
切换到
cd nginx-1.10.0
sudo ./configure --prefix=/opt/nginx --sbin-path=/usr/bin/nginx --add-module=/home/leyou/fdfs/fastdfs-nginx-module/src
- 编译安装
sudo make && sudo make install
-
配置nginx整合fastdfs-module模块
我们需要修改nginx配置文件,在/opt/nginx/config/nginx.conf文件中:
sudo vim /opt/nginx/conf/nginx.conf
将文件中,原来的server 80{ ...}
部分代码替换为如下代码:
server {
listen 80;
server_name image.leyou.com;
# 监听域名中带有group的,交给FastDFS模块处理
location ~/group([0-9])/ {
ngx_fastdfs_module;
}
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
- 启动
nginx # 启动
nginx -s stop # 停止
nginx -s reload # 重新加载配置
-
设置nginx开机启动
创建一个开机启动的脚本:
vim /etc/init.d/nginx
添加以下内容:
#!/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
访问浏览器对应的地址可以看到刚刚上传的图片
http://image.leyou.com/group1/M00/00/00/rBEACmEPpcyAcBNZAAFkkXlaVjk629.png
下面这是是刚刚上传的图片
11、文件上传Java代码的实现
余庆先生提供了一个Java客户端,但是作为一个c程序员,写的java代码可想而知。而且已经很久不维护了。这里推荐一个开源的FastDFS客户端,支持最新的SpringBoot2.0。
配置使用极为简单,支持连接池,支持自动生成缩略图,狂拽酷炫吊炸天啊,有木有。
https://github.com/tobato/FastDFS_Client
(1)在项目当中使用FastDFS-Client
1)引入依赖:修改ly-upload当中的pom.xml文件
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
</dependency>
2)引入Java的配置类
package com.leyou.upload.config;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
@Configuration
@Import(FdfsClientConfig.class)
//解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastClientImporter {
}
3)编写FastDFS属性,即编写FastDFS的配置文件
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #设置图片的缩略图
width: 60
height: 60
tracker-list: #tracker地址
- 192.168.58.101:22122
4)编写测试类(实现上传文件的测试以及其对应上传缩略图)
package com.leyou.upload;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.domain.ThumbImageConfig;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.leyou.upload.service.UploadService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@RunWith(SpringRunner.class) //测试启动器,可以加载Springboot测试注解。
@SpringBootTest //单元测试
public class FdfsTest {
@Autowired
private FastFileStorageClient storageClient;
@Autowired
private ThumbImageConfig thumbImageConfig;
@Test
public void testUpload() throws FileNotFoundException {
File file = new File("D:\\test\\1.png");
// 上传并且生成缩略图
StorePath storePath = this.storageClient.uploadFile(
new FileInputStream(file), file.length(), "png", null);
// 带分组的路径
System.out.println(storePath.getFullPath());
// 不带分组的路径
System.out.println(storePath.getPath());
}
@Test
public void testUploadAndCreateThumb() throws FileNotFoundException {
File file = new File("D:\\test\\baby.png");
// 上传并且生成缩略图
StorePath storePath = this.storageClient.uploadImageAndCrtThumbImage(
new FileInputStream(file), file.length(), "png", null);
// 带分组的路径
System.out.println(storePath.getFullPath());
// 不带分组的路径
System.out.println(storePath.getPath());
// 获取缩略图路径
String path = thumbImageConfig.getThumbImagePath(storePath.getPath());
System.out.println(path);
}
}
在D盘的test文件夹当中准备一张图片
运行测试类当中的测试方法
返回结果
用这个地址了浏览器当中访问
http://image.leyou.com/group1/M00/00/00/rBEACmEQz1iAJkXSAAiysGYAir4636.png
访问成功代表上传成功
运行第二个测试方法:上传并且生成缩略图
访问第三个图片的路径
http://image.leyou.com/group1/M00/00/00/rBEACmEQ0bCAJREiAAiysGYAir4857_60x60.png
图片已经被压缩
(2)改造:UploadService
1)UploadService完成文件的上传
package com.leyou.upload.service;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
public class UploadService {
@Autowired
private FastFileStorageClient storageClient;
// Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");
public String uploadImage(MultipartFile file) {
try {
//校验文件类型
String contentType = file.getContentType();
if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
//校验文件的内容
BufferedImage image = ImageIO.read(file.getInputStream());
if(image == null){
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
//上传到FastDFS
//获取后缀名,通过文件名称截取字符串的方式获取后缀名称
String extension = StringUtils.substringAfterLast(file.getOriginalFilename(),".");
StorePath storePath = storageClient.uploadFile(file.getInputStream(),file.getSize(), extension,null);
return "http://image.leyou.com/" + storePath.getFullPath();
} catch (IOException e) {
//如果上传失败,记录日志信息
log.error("上传文件失败",e);
//返回错误结果
throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
}
//返回图片路径
}
}
2)继续完善上述代码:(在配置文件当中配置相关属性)
UploadService当中的返回的路径是的地址是写死的地址因此我们需要将其抽取出来 ,需要配置一下允许访问数据的类型
ly:
upload:
baseUrl: http://image.leyou.com/
allowTypes:
- image/jpeg
- image/png
- image/jpg
3)读取上述的配置文件当中定义的数据
package com.leyou.upload.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@ConfigurationProperties(prefix = "ly.upload")
public class UploadProperties {
private String baseUrl;
private List<String> allowTypes;
}
继续完善
package com.leyou.upload.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@Data
@ConfigurationProperties(prefix = "ly.upload")
public class UploadProperties {
private String baseUrl;
private List<String> allowTypes;
}
4)在UploadService当中使用
@EnableConfigurationProperties(UploadProperties.class)
@EnableConfigurationProperties注解的作用是:
使用 @ConfigurationProperties注解的类生效。读取配置信息的类的注解生效
全部代码
package com.leyou.upload.service;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.upload.config.UploadProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
@EnableConfigurationProperties(UploadProperties.class)
public class UploadService {
@Autowired
private FastFileStorageClient storageClient;
// Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
@Autowired
private UploadProperties prop;
// private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");
public String uploadImage(MultipartFile file) {
try {
//校验文件类型
String contentType = file.getContentType();
if(!prop.getAllowTypes().contains(contentType)){//校验当前文件的后缀是否在上述集合当中
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
//校验文件的内容
BufferedImage image = ImageIO.read(file.getInputStream());
if(image == null){
throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
}
//上传到FastDFS
//获取后缀名,通过文件名称截取字符串的方式获取后缀名称
String extension = StringUtils.substringAfterLast(file.getOriginalFilename(),".");
StorePath storePath = storageClient.uploadFile(file.getInputStream(),file.getSize(), extension,null);
return prop.getBaseUrl() + storePath.getFullPath();
} catch (IOException e) {
//如果上传失败,记录日志信息
log.error("上传文件失败",e);
//返回错误结果
throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
}
//返回图片路径
}
}
(3)文件上传运行测试
http://manage.leyou.com/#/item/brand
上传成功
搜索以后发现显示太大
设置一下图片的大小
12、设置nginx上传文件大小的限制
vim /opt/nginx/ conf/nginx.con
client_max_body_size 100m
退出保存
从新加载nginx