MInIO
MinIO是一个轻量级的适用于存储文件的存储服务,可以轻易的和NodeJS、Redis或MySQL结合
项目中文件服务流程
由其他服务处理请求后,对于上传文件的请求交给独立的文件服务来执行,对应的文件存储到文件服务器上,而非tomcat容器
minio的启动
通过命令minio.exe server 路径 -address ip+port,来启动服务器,然后通过指定的端口访问
文件服务实现
- 导入依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.0.2</version>
</dependency>
- 配置minio链接参数
minio:
end-point: http://localhost:9000
access-key: minioadmin
secret-key: minioadmin
package com.demo.file;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/***
* @author shaofan
* @Description
* @Date 2021-8-12
* @Time 20:24
*/
@Component
@ConfigurationProperties("minio")
public class MinioProp {
private String endPoint;
private String accessKey;
private String secretKey;
public String getEndPoint() {
return endPoint;
}
public void setEndPoint(String endPoint) {
this.endPoint = endPoint;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
@Override
public String toString() {
return "MinioProp{" +
"endPoint='" + endPoint + '\'' +
", accessKey='" + accessKey + '\'' +
", secretKey='" + secretKey + '\'' +
'}';
}
}
- 文件上传
@Controller
@RequestMapping("file")
@ResponseBody
public class FileController {
@Autowired
private MinioClient minioClient;
@PostMapping("upload")
public ResponseVO upload(MultipartFile file){
String objectName = null;
try {
boolean isExist = minioClient.bucketExists("images");
if(isExist) {
System.out.println("Bucket already exists.");
} else {
minioClient.makeBucket("images");
minioClient.setBucketPolicy("picture","{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \t\"Principal\":\"*\",\n" +
" \"Action\": [\n" +
" \"s3:GetBucketLocation\",\n" +
" \"s3:GetObject\"\n" +
" ],\n" +
" \"Resource\": [\n" +
" \"arn:aws:s3:::*\"\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}" );
}
objectName = UUID.randomUUID().toString().replace("-","");
minioClient.putObject("images", objectName, file.getInputStream(), new PutObjectOptions(file.getInputStream().available(),-1));
} catch(MinioException e) {
System.out.println("Error occurred: " + e);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}catch (InvalidKeyException e) {
e.printStackTrace();
}
return new ResponseVO(200,objectName);
}
}
putObject方法参数
桶名
文件名
上传的文件流
上传的选项,第一个参数为上传文件流大小,第二个参数为用于上传的part大小,-1表示与前一个参数相同
访问策略
minio默认是私有访问,无法预览信息,设置访问策略principal字段为*即可使全部用户都可访问
访问策略的json字符串是iam访问策略,不太了解,在minio的图形化界面可以找到几个常用的访问策略
注意
这里为了测试方便存储桶直接写死了,实际开发中存储桶也要像其他参数一样放到yml中,文件后缀的获取也直接写死为jpg
Zuul
概述
Zuul是spring cloud中的微服务api网关,所有请求都会先通过zuul在到达后端的Netflix应用程序,zuul通常用来做四件事情:路由,鉴权,限流,日志
使用网关后,应用向外部暴露一个端口,即网关的端口,剩余服务的端口在局域网中访问,不暴露在外部,外部请求都只能通过网关
没有使用网关时,每一个服务都要考虑到跨域问题,使用网关后就只用在网关考虑跨域问题即可
环境搭建
- 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
由于zuul已经被官方弃用,新版的spring boot是没办法使用的,会报错NoSuchMethod,经测试一下版本可以:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 在入口类上添加注解
@EnableZuulProxy
,开启zuul网关 - 配置文件,讲zuul注册到注册中心
模块建好后只通过zuul的主机和端口就可以访问到所有其他的服务的资源,zuul的默认路由是其他服务注册的服务名
路由
zuul:
routes:
order:
path: /order/**
serviceId: service-order
user:
path: /user/**
serviceId: service-user
ignored-services:
- service-user
- service-order
path表示路由的映射路径,**通配符表示所有资源,比如默认的映射路径就是
/service-order/**
serviceId表示注册的服务名
ignored-services可以禁用默认的路由规则
认证与鉴权
实现Zuul的请求过滤操作,需要自定义类继承ZuulFilter类,并实现几个方法
@Component
public class AuthFilter extends ZuulFilter {
/**
* 过滤器的类型
* @return
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;//前置过滤器
}
/**
* 过滤器的优先级,越小则越先调用
* @return
*/
@Override
public int filterOrder() {
return -4;//默认配置中最小到-3,返回-4保证在所有过滤器之前调用
}
/**
* 是否使用过滤器,可在这里对使用过滤器的请求进行判断
* @return
*/
@Override
public boolean shouldFilter() {
/*
* 通过这样的方法可以获得HttpServletRequest,即可通过请求头信息来判断是否使用该过滤器,认证
*/
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
return true;
}
/**
* 过滤器的逻辑方法,这里执行过滤器的逻辑
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
if(request.getHeader("token")==null||request.getHeader("token").equals("")){
requestContext.setSendZuulResponse(false);//设置是否进行路由,传参为false为不进行路由
requestContext.setResponseBody("no login");//返回的数据
requestContext.setResponseStatusCode(HttpStatus.SC_FORBIDDEN);//状态码
}
return null;
}
}
- filterType:该方法用于指定过滤器的类型,如前置过滤器(在请求通过之前执行),后置过滤器(在请求通过之后执行)等等
- filterOrder:该方法指定执行顺序,返回值越小表示越早执行
- FilterConstrants:该类指定了方法的约束条件,使用静态字符串约定好了如filterType,filterOrder的返回值对应的效果
- shouldFilter:该方法的返回值决定是否调用接下来的run方法,即是否使用该过滤器,可以通过请求头信息来对指定类型的请求进行过滤
- run:该方法用于实现过滤器的逻辑,返回值表示同时执行的额外操作,可以不用管
这里只简单的实现了认证操作,鉴权和这里差不太多,将shiro+jwt那一套拿来在这里写就行了
限流
- 导入依赖
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
- 限流配置
ratelimit:
#开启限流
enabled: true
#存储方式,推荐使用redis,这里使用in_memory存在内存中方便测试
repository: in_memory
#策略
policies:
#限流的服务
user:
#每个周期内限定请求次数
limit: 3
#单位周期内允许访问的总时间
quota: 30 #表示一个周期内即使请求次数没有达到3次,如果一次请求时间超过30秒也会被限流
#周期时间
refresh-interval: 60
#限流方式:USER(根据用户),ORIGIN(请求源),URL(请求路径)
type: ORIGIN
如果配置了路由,那么这里的服务名应当是设置的路由的名称