一、文件上传微服务
1、微服务搭建
1、工程目录结构
2、添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <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-test</artifactId> </dependency>
3、配置文件
appliction.yml
server: port: 10002 spring: application: name: upload-service servlet: multipart: max-file-size: 5MB # 限制文件上传的大小 # Eureka eureka: client: service-url: defaultZone: http://127.0.0.1:5000/eureka instance: lease-renewal-interval-in-seconds: 5 # 每隔5秒发送一次心跳 lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期
4、主启动类
package com.linfinity.leyou; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class UploadMain { public static void main(String[] args) { SpringApplication.run(UploadMain.class, args); } }
5、controller
package com.linfinity.leyou.web; import com.linfinity.leyou.service.UploadService; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("upload") public class UploadController { @Autowired private UploadService uploadService; /** * 图片上传 * @param file * @return */ @PostMapping("image") public ResponseEntity<String> uploadImage(@RequestParam("file") MultipartFile file){ System.out.println(file); String url = this.uploadService.upload(file); if (StringUtils.isBlank(url)) { return ResponseEntity.badRequest().build(); } return ResponseEntity.status(HttpStatus.CREATED).body(url); } @GetMapping("test") public String test(){ return "test ok"; } }
6、service
package com.linfinity.leyou.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 public class UploadService { private static final List<String> CONTENT_TYPES = Arrays.asList("image/jpeg", "image/gif"); private static final Logger LOGGER = LoggerFactory.getLogger(UploadService.class); public String upload(MultipartFile file) { String originalFilename = file.getOriginalFilename(); // 校验文件的类型 String contentType = file.getContentType(); if (!CONTENT_TYPES.contains(contentType)){ // 文件类型不合法,直接返回null LOGGER.info("文件类型不合法:{}", originalFilename); return null; } try { // 校验文件的内容 BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); if (bufferedImage == null){ LOGGER.info("文件内容不合法:{}", originalFilename); return null; } // 保存到服务器 file.transferTo(new File("C:\\workspace\\leyou\\images\\" + originalFilename)); // 生成url地址,返回 return "http://image.leyou.com/" + originalFilename; } catch (IOException e) { LOGGER.info("服务器内部错误:{}", originalFilename); e.printStackTrace(); } return null; } }
7、配置nginx静态服务器(前端进行图片回访)
server { listen 80; server_name image.leyou.com; #charset koi8-r; #access_log logs/host.access.log main; location / { root C:\\workspace\\leyou\\images; } }
2、绕过网关
所以,我们上传文件的请求就不经过网关来处理了。
1、zuul的路由过滤
zuul.ignored-patterns: /upload/**
路径过滤会对一切微服务进行判定。
Zuul还提供了ignored-services
属性,进行服务过滤:
zuul.ignored-services: upload-servie
我们这里采用忽略服务:
zuul: ignored-services: - upload-service # 忽略upload-service服务
上面的配置采用了集合语法,代表可以配置多个。
2、配置nginx的rewrite
当我们访问http://api.leyou.com/api/upload/test时重写为http://localhost:10002/upload/test
server { listen 80; server_name api.leyou.com; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 上传路径的映射 location /api/upload { proxy_pass http://127.0.0.1:10002; proxy_connect_timeout 600; proxy_read_timeout 600; rewrite "^/api/(.*)$" /$1 break; } location / { proxy_pass http://127.0.0.1:10010; proxy_connect_timeout 600; proxy_read_timeout 600; } }
-
last:重写路径结束后,将得到的路径重新进行一次路径匹配
-
break:重写路径结束后,不再重新匹配路径。
3、跨域问题
package com.linfinity.leyou.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; /** * 使用CORS,用于解决ajax跨域访问问题 */ @Configuration public class GlobalCorsConfig { @Bean public CorsFilter corsFilter() { //1.添加CORS配置信息 CorsConfiguration config = new CorsConfiguration(); //1) 允许的域,不要写*,否则cookie就无法使用了 config.addAllowedOrigin("http://manage.leyou.com"); config.addAllowedOrigin("http://www.leyou.com"); //2) 是否发送Cookie信息 config.setAllowCredentials(true); //3) 允许的请求方式 config.addAllowedMethod("OPTIONS"); config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET"); config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH"); config.setMaxAge(3600L); // 4)允许的头信息 config.addAllowedHeader("*"); //2.添加映射路径,我们拦截一切请求 UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); configSource.registerCorsConfiguration("/**", config); //3.返回新的CorsFilter. return new CorsFilter(configSource); } }
4、文件上传的缺陷
上传本身没有任何问题,问题出在保存文件的方式,我们是保存在服务器机器,就会有下面的问题:
-
单机器存储,存储能力有限
-
无法进行水平扩展,因为多台机器的文件无法共享,会出现访问不到的情况
-
数据没有备份,有单点故障风险
-
并发能力差
这个时候,最好使用分布式文件存储来代替本地文件存储。