• 文件上传


    一、文件上传微服务

    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、绕过网关

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

    所以,我们上传文件的请求就不经过网关来处理了。

    1、zuul的路由过滤

    Zuul中提供了一个ignored-patterns属性,用来忽略不希望路由的URL路径,示例:

    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;
            }
        }

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

    • 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、文件上传的缺陷

    先思考一下,现在上传的功能,有没有什么问题?

    上传本身没有任何问题,问题出在保存文件的方式,我们是保存在服务器机器,就会有下面的问题:

    • 单机器存储,存储能力有限

    • 无法进行水平扩展,因为多台机器的文件无法共享,会出现访问不到的情况

    • 数据没有备份,有单点故障风险

    • 并发能力差

    这个时候,最好使用分布式文件存储来代替本地文件存储。

  • 相关阅读:
    MySQL-5.6.xx-winx64 免安装版配置方法
    winForm窗体最大化的设置
    foreach内部做的一点事
    sqlserver创建同义词
    sql server 数据库创建链接服务器
    文件比对工具——WinMerge
    Devos病毒解决办法(转)
    设计模式学习笔记-单例模式
    Aspose.Word for DotNet 定位到每页,画笔 移动到某页。
    Word 固定文字或签名在底部
  • 原文地址:https://www.cnblogs.com/linfinity/p/13970128.html
Copyright © 2020-2023  润新知