08-微服务文件上传实战(2105~2106总结与练习)

191 阅读9分钟

项目简介

==============================================================

业务描述


基于Spring Cloud Alibaba解决方案实现文件上传,例如

在这里插入图片描述

初始架构设计


本次项目实践,整体上基于前后端分离架构,服务设计上基于spring cloud alibaba解决方案进行实现,例如:

在这里插入图片描述

说明,为了降低学习难度,这里只做了初始架构设计,后续会逐步基于这个架构进行演进,例如我们会加上网关工程,认证工程等.

工程创建及初始化

==================================================================

工程结构


参考如下工程结构,进行项目创建,例如:

在这里插入图片描述

创建父工程


创建项目父工程用来管理项目依赖.

在这里插入图片描述

在这里插入图片描述

创建文件服务工程


创建用于处理文件上传业务的工程,例如:

在这里插入图片描述

在这里插入图片描述

创建客户端服务工程


创建一个客户端工程,在此工程中定义一些静态页面,例如文件上传页面.

在这里插入图片描述

在这里插入图片描述

父工程初始化

================================================================

打开父工程的pom.xml文件,添加如下依赖:

org.springframework.boot

spring-boot-dependencies

2.3.2.RELEASE

pom

import

org.springframework.cloud

spring-cloud-dependencies

Hoxton.SR9

pom

import

com.alibaba.cloud

spring-cloud-alibaba-dependencies

2.2.6.RELEASE

pom

import

org.projectlombok

lombok

provided

文件资源服务实现

==================================================================

添加项目依赖


在sca-resource工程中添加如下依赖:

org.springframework.boot

spring-boot-starter-web

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-config

com.alibaba.cloud

spring-cloud-starter-alibaba-sentinel

org.springframework.boot

spring-boot-starter-actuator

服务初始化配置


在项目的resources目录下创建bootstrap.yml配置文件(假如后续配置信息要写到配置中心配置文件名必须为bootstrap.yml),并添加如下内容:

server:

port: 8881

spring:

application:

name: sca-resource

servlet:

multipart:

max-file-size: 100MB #控制上传文件的大小

max-request-size: 110MB #请求数据大小

resources: #定义可以访问到上传资源的路径

static-locations: file:d:/uploads #静态资源路径(原先存储到resources/static目录下的资源可以存储到此目录中)

cloud:

nacos:

discovery:

server-addr: localhost:8848

config:

server-addr: localhost:8848

jt: #这里的配置,后续会在一些相关类中通过@Value注解进行读取

resource:

path: d:/uploads #设计上传文件存储的根目录(后续要写到配置文件)

host: http://localhost:8881/ #定义上传文件对应的访问服务器

构建项目启动类


在当前工程中,创建项目启动类,例如:

package com.jt;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class FileApplication {

public static void main(String[] args) {

SpringApplication.run(FileApplication.class, args);

}

}

类创建以后,启动当前项目,检测是否可以启动成功,是否有配置错误.

Controller逻辑实现


定义处理上传请求的Controller对象,例如:

package com.jt.resource.controller;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.multipart.MultipartFile;

import java.io.File;

import java.io.IOException;

import java.time.LocalDate;

import java.time.format.DateTimeFormatter;

import java.util.UUID;

@Slf4j

@RestController

@RequestMapping("/resource/")

public class ResourceController {

//当了类的上面添加了@Slf4J就不用自己创建下面的日志对象了

// private static final Logger log=

// LoggerFactory.getLogger(ResourceController.class);

@Value("${jt.resource.path}")

private String resourcePath;//="d:/uploads/";

@Value("${jt.resource.host}")

private String resourceHost;//="http://localhost:8881/";

@PostMapping("/upload/")

public String uploadFile(MultipartFile uploadFile) throws IOException {

//1.创建文件存储目录(按时间创建-yyyy/MM/dd)

//1.1获取当前时间的一个目录

String dateDir = DateTimeFormatter.ofPattern("yyyy/MM/dd")

.format(LocalDate.now());

//1.2构建目录文件对象

File uploadFileDir=new File(resourcePath,dateDir);

if(!uploadFileDir.exists())uploadFileDir.mkdirs();

//2.给文件起个名字(尽量不重复)

//2.1获取原文件后缀

String originalFilename=uploadFile.getOriginalFilename();

String ext = originalFilename.substring(

originalFilename.lastIndexOf("."));

//2.2构建新的文件名

String newFilePrefix=UUID.randomUUID().toString();

String newFileName=newFilePrefix+ext;

//3.开始实现文件上传

//3.1构建新的文件对象,指向实际上传的文件最终地址

File file=new File(uploadFileDir,newFileName);

//3.2上传文件(向指定服务位置写文件数据)

uploadFile.transferTo(file);

String fileRealPath=resourceHost+dateDir+"/"+newFileName;

log.debug("fileRealPath {}",fileRealPath);

//后续可以将上传的文件信息写入到数据库?

return fileRealPath;

}

}

跨域配置实现


我们在通过客户端工程,访问文件上传服务时,需要进行跨域配置,在服务端的跨域配置中有多种方案,最常见是在过滤器的层面进行跨域设计,例如:

package com.jt.files.config;

/**

  • 跨域配置(基于过滤器方式进行配置,并且将过滤优先级设置高一些)

*/

@Configuration

public class CorsFilterConfig {

@Bean

public FilterRegistrationBean filterFilterRegistrationBean(){

//1.对此过滤器进行配置(跨域设置-url,method)

UrlBasedCorsConfigurationSource configSource=new UrlBasedCorsConfigurationSource();

CorsConfiguration config=new CorsConfiguration();

//允许哪种请求头跨域

config.addAllowedHeader("*");

//允许哪种方法类型跨域 get post delete put

config.addAllowedMethod("*");

// 允许哪些请求源(ip:port)跨域

config.addAllowedOrigin("*");

//是否允许携带cookie跨域

config.setAllowCredentials(true);

//2.注册过滤器并设置其优先级

configSource.registerCorsConfiguration("/**", config);

FilterRegistrationBean fBean= new FilterRegistrationBean(new CorsFilter(configSource));

fBean.setOrder(Ordered.HIGHEST_PRECEDENCE);

return fBean;

}

}

客户端工程逻辑实现

===================================================================

本次项目我们的客户端工程基于springboot工程进行设计,项目上线时可以将其静态资源直接放到一个静态资源目录中.

添加依赖


在sca-resource-ui工程的pom文件中添加web依赖,例如:

org.springframework.boot

spring-boot-starter-web

构建项目启动类


package com.jt;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class ClientApplication {

public static void main(String[] args) {

SpringApplication.run(ClientApplication .class, args);

}

}

创建文件上传页面


在工程的resources目录下创建static目录(假如这个目录已经存在则无需创建),然后在此目录创建fileupload.html静态页面,例如:

文件上载演示

上传文件

上传文件

启动服务访问测试


第一步:启动nacos服务(在这里做服务的注册和配置管理)

第二步:启动sca-resource服务,此服务提供文件上传功能

第三步:启动sca-resource-ui服务,此服务为客户端工程,提供静态资源的访问.所有页面放到此工程中.

第四步:打开浏览器,访问sca-resource-ui工程下的文件上传页面,例如:

在这里插入图片描述

API网关(Gateway)工程实践

============================================================================

概述


API 网关是外部资源对服务内部资源访问的入口,所以文件上传请求应该首先请求的是网关服务,然后由网关服务转发到具体的资源服务上。

服务调用架构


在这里插入图片描述

工程项目结构设计


在这里插入图片描述

创建网关工程及初始化


第一步:创建sca-resource-gateway工程,例如:

在这里插入图片描述

第二步:添加项目依赖,例如:

org.springframework.cloud

spring-cloud-starter-gateway

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-config

第三步:创建配置文件bootstrap.xml,然后进行初始配置,例如:

server:

port: 9000

spring:

application:

name: sca-resource-gateway

cloud:

nacos:

discovery:

server-addr: localhost:8848

config:

server-addr: localhost:8848

file-extension: yml

gateway:

discovery:

locator:

enabled: true

routes:

  • id: router01

uri: lb://sca-resource

predicates:

  • Path=/sca/resource/upload/**

filters:

  • StripPrefix=1

第四步:构建项目启动类,并进行服务启动,检测是否正确,例如:

package com.jt;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class ResourceApplication {

public static void main(String[] args) {

SpringApplication.run(ResourceApplication.class,args);

}

}

网关跨域配置


当我们基于Ajax技术访问网关时,需要在网关层面进行跨域设计,例如:

package com.jt.config;

import org.springframework.context.annotation.Bean;

import org.springframework.web.cors.CorsConfiguration;

import org.springframework.web.cors.reactive.CorsWebFilter;

import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

//@Configuration

public class CorsFilterConfig {

@Bean

public CorsWebFilter corsWebFilter(){

//1.构建基于url方式的跨域配置

UrlBasedCorsConfigurationSource source= new UrlBasedCorsConfigurationSource();

//2.进行跨域配置

CorsConfiguration config=new CorsConfiguration();

技术学习总结

学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。

最后面试分享

大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!

相关阅读docs.qq.com/doc/DSmxTbFJ1cmN1R2dB