文章目录

  • 1 项目搭建
    • 1.1 引入依赖
    • 1.2 配置文件
    • 1.3 启动类
  • 2 实现文件上传功能
    • 2.1 分布式文件上传系统
      • 2.1.1 分布式文件系统
      • 2.1.2 FastDFS
      • 2.1.3 FastDFS架构
      • 2.1.4 上传文件
      • 2.1.5 引入FastDFS的依赖
      • 2.1.6 引入配置类
      • 2.1.7 配置FastDFS属性
    • 2.2 代码实现
      • 2.2.1 controller
      • 2.2.2 service

1 项目搭建

1.1 引入依赖

<?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.page.service</groupId><artifactId>ly-upload</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>com.leyou.common</groupId><artifactId>ly-common</artifactId><version>1.0.0-SNAPSHOT</version></dependency><dependency><groupId>com.github.tobato</groupId><artifactId>fastdfs-client</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

1.2 配置文件

ly-upload的配置文件:

server:port: 8082
spring:application:name: upload-serviceservlet:multipart:max-file-size: 5MB # 限制文件上传的大小
eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eurekainstance:prefer-ip-address: trueip-address: 127.0.0.1
fdfs:so-timeout: 2500connect-timeout: 600thumb-image: # 缩略图width: 60height: 60tracker-list: # tracker地址- 192.168.124.128:22122

当实现写好(此处的实现是指的上传到本地,代码省略)以后一跑代码发现报错,如下:

原因是没有在网关中配置路由。

但是
        网关捕获到upload之后页面的url只剩下/image(前缀会被剥离),例如:HTTP调用 “/user” 会转到 “user” 服务(例如:”/user/1”跳转到”/1”),但是controller里面是/upload/image,所以不能去除upload的前缀,有以下两种方法:

ly-gategay的配置文件:

  • 配置方式1(笔记中的方式,因为视频笔记不一致…):
zuul:prefix: /api # 添加路由前缀routes:item-service: /item/**search-service: /search/**user-service: /user/**auth-service: /auth/**cart-service: /cart/**order-service: /order/**ignored-services:- upload-service # 忽略upload-service服务add-host-header: truesensitive-headers:

忽略表达式并不是完全的忽略请求, 只是配置这个代理不处理这些请求,因此上述配置表示所有upload-service的服务都不会被处理,自然也不会自动剥离前缀。

  • 配置方式2(视频中的方式):
zuul:prefix: /api # 添加路由前缀routes:item-service: /item/**search-service: /search/**user-service: /user/**auth-service: /auth/**cart-service: /cart/**order-service: /order/**upload-service: /upload/**path: /upload/**serviceId: upload-servicestrip-prefix: falseadd-host-header: truesensitive-headers:

设置前缀不自动剥离。

以上相关参考资料:智能路由和过滤


但是还有一个问题:
        图片上传是文件的传输,如果也经过Zuul网关的代理,文件就会经过多次网路传输,造成不必要的网络负担。在高并发时,可能导致网络阻塞,Zuul网关不可用。这样我们的整个系统就瘫痪了,所以,上传文件的请求不经过网关来处理。

那怎么做呢?
方式一(笔记):

请求的地址不经过网关api:

修改nginx配置,将以/api/upload开头的请求拦截下来,转交到真实的服务地址,但是前面多了一个/api,此时利用Nginx提供了rewrite指令,用于对地址进行重写(并不是真的去掉api,而是重写路径结束后,不再重新匹配路径):

# 上传路径的映射
location /api/upload {  proxy_pass http://192.168.124.128:8082;proxy_connect_timeout 600;proxy_read_timeout 600;rewrite "^/api/(.*)$" /$1 break; }

rewrite "^/api/(.*)$" /$1 break,路径重写:

  • "^/api/(.*)$":匹配路径的正则表达式,用了分组语法,把/api/以后的所有部分当做1组

  • /$1:重写的目标路径,这里用$1引用前面正则表达式匹配到的分组(组编号从1开始),即/api/后面的所有。这样新的路径就是除去/api/以外的所有,就达到了去除/api前缀的目的

  • break:指令,常用的有2个,分别是:last、break

    • last:重写路径结束后,将得到的路径重新进行一次路径匹配
    • break:重写路径结束后,不再重新匹配路径

    我们这里不能选择last,否则以新的路径/upload/image来匹配,就不会被正确的匹配到8082端口了。

方式二(视频):
先来看一段官方文档的翻译:

zuul的底层是一个servlet,通常情况下zuul会将请求交给Spring Dispatch去处理,SpringMVC去控制路由。这种情况下,zuul就会去缓存这个请求,如果你有直接通过zuul但是不需要缓存的服务:比如大文件的上传服务,这时候你应该跳过Spring Dispatch。这时候你应该在你的地址前面加一个/zuul

​ 简而言之,当你的请求前面加上/zuul,就会跳过缓存服务,如下:

那么如何实现——还是依靠Nginx的rewrite指令!

# 上传路径的映射
location /api/upload {  write "^/(.*)$" /zuul/$1;
}

1.3 启动类

@SpringBootApplication
@EnableDiscoveryClient
public class LyUploadApplication {public static void main(String[] args) {SpringApplication.run(LyUploadApplication.class);}
}

2 实现文件上传功能

2.1 分布式文件上传系统

无论是保存在本地还是tomcat下都是有问题的

  • 文件越传越多,启动加载的速度会越来越慢
  • tomcat解析静态资源速度非常慢
  • 有单点故障问题,如果一台服务器挂了整体图片功能都会受到影响
  • 无法进行水平扩展,因为多台机器的文件无法共享,会出现访问不到的情况

因此图片地址需要使用另外的url + 分布式文件上传系统来解决!

2.1.1 分布式文件系统

分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。

通俗来讲:

  • 传统文件系统管理的文件就存储在本机。
  • 分布式文件系统管理的文件存储在很多机器,这些机器通过网络连接,要被统一管理。无论是上传或者访问文件,都需要通过管理中心来访问

2.1.2 FastDFS

FastDFS是一个轻量级、高性能的开源分布式文件系统,用纯C语言开发,功能如下:

  • 文件存储
  • 文件同步
  • 文件访问(上传、下载)
  • 存取负载均衡
  • 在线扩容

适合有大容量存储需求的应用或系统。同类的分布式文件系统有谷歌的GFS、HDFS(Hadoop)、TFS(淘宝)等。

2.1.3 FastDFS架构

每一个Storage启动以后都会向Tracker注册自己的信息,并且维持一个心跳

Storage:存储服务器。文件存储的地方,每个Storage Server存储的文件都不一样,数据分片
Tracker:跟踪服务器。顾名思义,他可以知道每个文件存储在哪个Storage,类似于仓库管理员

2.1.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,文件上传结束。

下载流程

5. Client通过Tracker server查找要下载文件所在的的Storage server。
6. Tracker server向Client返回包含指定文件的某个Storage server的IP地址和端口号。
7. Client直接通过Tracker server返回的IP地址和端口与其中一台Storage server建立连接并指定要下载文件。
8. 下载文件成功。

2.1.5 引入FastDFS的依赖

见前述pom.xml文件

2.1.6 引入配置类

注入FastDFS客户端:

@Configuration
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastClientImporter {}

2.1.7 配置FastDFS属性

见前述application.yml文件

2.2 代码实现

2.2.1 controller

@RestController
@RequestMapping("upload")
public class UploadController {@Autowiredprivate UploadService uploadService;@PostMapping("image")public ResponseEntity<String> uploadImage(@RequestParam("file")MultipartFile file){String url = uploadService.uploadImage(file);return ResponseEntity.ok(url);}
}

2.2.2 service

@Service
@Slf4j
public class UploadService {@Autowiredprivate FastFileStorageClient storageClient;//文件上传的最终地址private static final List<String> ALLOWTYPES = Arrays.asList("image/jpeg","image/png");public String uploadImage(MultipartFile file) {try {//校验格式String contentType = file.getContentType();if(!ALLOWTYPES.contains(contentType)){throw new LyException(ExceptionEnum.CONTENT_TYPE_ERROE);}//校验内容BufferedImage image = ImageIO.read(file.getInputStream());if(image == null){throw new LyException(ExceptionEnum.INVALID_IMAGE_ERROE);}/*//准备目标路径File dest = new File("D:/javacode/idea/upload/", file.getOriginalFilename());//保存到本地file.transferTo(dest);*///上传到FastDFSString extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extension, null);//System.out.println(storePath.getFullPath());//返回路径return "http://image.leyou.com/" + storePath.getFullPath();} catch (Exception e) {log.error("文件上传失败", e);throw new LyException(ExceptionEnum.UPLOAD_FAILED_ERROE);}}
}

这一篇写的也太乱了点…

乐优商城:笔记(六):上传微服务:LyUpload相关推荐

  1. 乐优商城笔记六:商品详情页

    使用模板引擎 Thymeleaf + nginx 完成商品详情页静态化 完成乐优商城商品详情页 搭建商品详情页微服务 创建子工程 GroupId:com.leyou.service ArtifactI ...

  2. 乐优商城day15(redis,短信微服务)

    所有代码发布在 [https://github.com/hades0525/leyou] Redis • 1.指令 • 1.1通用指令 o keys 获取符合规则的键名列表 keys pattern( ...

  3. 在项目开发时创建上传微服务,我们一些纠结的点

    微服务除了可以进行业务处理之外,也可以针对上传功能进行创建,所有的上传微服务依然需要向Eureka中注册,这样就可以在zuul中进行微服务代理操作.   注意:不建议构建上传微服务        在实 ...

  4. 3.从零开始搭建基于SpringCloud的京东整站_文件上传微服务

    本次目标 本次实现的目标:实现图片上传微服务. 文件上传在很多项目和很多模块都要用到,所以将其单独作为一个微服务. 如下图蓝色箭头所示:FileUploadMicroservice 静态资源 本案例图 ...

  5. 乐优商城笔记-商城系统功能编写

    索引数据库导入 创建搜索微服务 new module Group id:com.leyou.search Artifactid: leyou-search Module name:leyou-sear ...

  6. 乐优商城第六篇:域名访问与品牌查询

    域名访问与品牌查询 使用域名访问本地项目 统一环境 域名解析 解决域名解析问题 nginx解决端口问题 什么是Nginx nginx作为web服务器 nginx作为反向代理 安装和使用 反向代理配置 ...

  7. 乐优商城架构介绍(一)

    一.架构图 二.微服务模块 1 网关微服务ly-gateway:10010 不管是来自于客户端(PC或移动端)的请求,还是服务内部调用.一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴 ...

  8. 乐优商城源码/数据库及笔记总结

    文章目录 1 源码 2 笔记 2.1 项目概述 2.2 微服务 3 项目优化 4 项目或学习过程中涉及到的设计模式 5 安全问题 6 高内聚低耦合的体现 7 项目中待优化的地方 1 源码 Github ...

  9. 【javaWeb微服务架构项目——乐优商城day15】——会调用订单系统接口,实现订单结算功能,实现微信支付功能

    0.学习目标 会调用订单系统接口 实现订单结算功能 实现微信支付功能 源码笔记及资料: 链接:https://pan.baidu.com/s/1_opfL63P1pzH3rzLnbFiNw 提取码:v ...

最新文章

  1. python 如何查看模块所有方法-Python查看模块函数,查看函数方法的详细信息
  2. /dev、/sys/dev 和/sys/devices 和udev的关系
  3. 安装多个java后,java版本不对
  4. 一起来看流星雨剧情简介/剧情介绍/剧情分集介绍第六集
  5. 大佬!莫言获颁第13个荣誉博士学位
  6. php学习总结,PHP学习的技巧和学习的要素总结
  7. 95-10-132-启动-TransactionCoordinator-源码
  8. 无法为jsp编译类_《刺激战场》改名为《和平精英》,有2类玩家或可能无法登陆游戏...
  9. php公众号后台,微信公众号后台管理系统
  10. 图片转excel软件有哪些?这些软件你值得拥有
  11. django generic view - ListView
  12. 树莓派python摄像头文字识别_古德微树莓派摄像头文字识别
  13. Unity Editor 基础篇(三):自定义窗口
  14. Lab3:自行车码表
  15. 计算机视觉最新研究方向,计算机视觉的主要研究的内容是什么?,计算机视觉研究方向...
  16. pathon真的那么好用吗?
  17. 华硕主板M2N-电源跳线怎么接
  18. java-net-php-python-12ssm商家后台管理系统计算机毕业设计程序
  19. 蓝桥ROS之f1tenth简单PID沿墙跑起来(Python)
  20. Android WebView 精简Demo

热门文章

  1. squid 3 反向代理 缓存服务器 安装配置精华指南 by lbj
  2. 3.6 常用符号在数据输入中的使用 [原创Excel教程]
  3. 1.RecyclerView设置clipToPadding=“false“,scrollbars无法跟随列表滚动到底部的解决方案
  4. Shell显示系统时间的全年日
  5. (Tiled官方文档翻译)第四节:对象的编辑和使用
  6. 2D 游戏工具系列:unity自带Tilemap和地图编辑器Tiled的基本使用以及Super Tiled2Unity如何导入tmx到Unity中(2)
  7. 【硬件基础】舵机基础知识
  8. 小木虫好中的ei期刊图像处理
  9. 智能手表的突破和新发展机遇
  10. 清华大学计算机国际大赛,动态 | 清华大学超算团队摘得 SC 2018 总冠军,包揽三大国际大学生超算竞赛总冠军...