==============================================================
基于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对象,例如:
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 网关是外部资源对服务内部资源访问的入口,所以文件上传请求应该首先请求的是网关服务,然后由网关服务转发到具体的资源服务上。
第一步:创建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