场景
众所周知,视频类文件size比较大,不适合存在本地,适合存在阿里云OSS,向图片这些小文件,存在本地即可(不展示阿里云和本地文件上传,只展示代理模式的逻辑)。
分布式文件代理服务器实现
实现分析
基于代理模式,我画了一个例图:
具体实现:
1、FileUpload抽象接口,定义了文件上传方法,分别给它写了2种实现。
2、AliyunOSSFileUpload是将文件上传到aliyunOSS,主要上传mp4和avi的视频大文件。
3、FastdfsFileUpoad是将文件上传到FastDFS,主要上传png/jpg等图片小文件。
4、FileUploadProxy是代理对象,供用户访问,调用了FileUpload的文件上传方法,为用户提供不同文件上传调用。
5、FileController是控制器,用于接收用户提交的文件,并调用代理FileUploadProxy实现文件上传。
因为这里没有购买阿里云服务,所以这里就象征性的实现一下,知道原理就行了,以后遇到了,使用公司的就好了。
实现步骤
yml文件
server:
port: 88888
#指定服务处理指定的文件类型
upload:
filemap:
aliyunOSSFileUpload: mp4,avi
fastdfsFileUpload: png,jpg
#FastDFS配置
fastdfs:
url: http://localhost:788888/
#aliyun
aliyun:
oss:
FileUpload接口定义:
AliyunOSSFileUpload实现:
endpoint: oss-cn-shanghia.aliyuncs.com
accessKey: xxxxx
accessKeySecret: xxxxxxxx
bucketName: xxx
key: video/
backurl: xxxxxxxx
#访问地址配置
spring:
servlet:
multipart:
max-file-size: 100MB #上传文件大小配置
FileUpload接口:
public interface FileUpload {
/**
* 上传方法
* @param bytes 文件字节数组
* @param extName 文件后缀名
* @return
*/
String upload(byte[] bytes,String extName);
}
上传阿里云一系列操作:
工具类私信
/**
* 阿里云上传
*/
@Component(value = "aliyunOSSFileUpload")
public class AliyunOSSFileUpload implements FileUpload {
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKey}")
private String accessKey;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.oss.key}")
private String key;
@Value("${aliyun.oss.bucketName}")
private String bucketName;
@Value("${aliyun.oss.backurl}")
private String backurl;
@Override
public String upload(byte[] bytes, String extName) {
// 获取随机数
String fileName = ResultUtil.uuid() + "." + extName;
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, accessKeySecret);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key + fileName,
new ByteArrayInputStream(bytes));
// 上传字符串。
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(FileUtil.getContentType("." + extName));
putObjectRequest.setMetadata(objectMetadata);
ossClient.putObject(putObjectRequest);
// 关闭OSSClient。
ossClient.shutdown();
return backurl + fileName;
}
}
本地上传
@Component(value = "fastdfsFileUpoad")
public class FastdfsFileUpoad implements FileUpload {
@Value("${fastdfs.url}")
private String url;
/***
* 初始化tracker信息
*/
static {
try {
//获取tracker的配置文件fdfs_client.conf的位置
String filePath = new ClassPathResource("fdfs_client.conf").getPath();
//加载tracker配置信息
ClientGlobal.init(filePath);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String upload(byte[] bytes, String extName) {
String[] uploadResults = null;
try {
//获取StorageClient对象
StorageClient storageClient = getStorageClient();
//执行文件上传
uploadResults = storageClient.upload_file(bytes, extName, null);
return url+uploadResults[0]+"/"+uploadResults[1];
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* 获取StorageClient
* @return
* @throws Exception
*/
public static StorageClient getStorageClient() throws Exception {
//创建TrackerClient对象
TrackerClient trackerClient = new TrackerClient();
//通过TrackerClient获取TrackerServer对象
TrackerServer trackerServer = trackerClient.getConnection();
//通过TrackerServer创建StorageClient
StorageClient storageClient = new StorageClient(trackerServer, null);
return storageClient;
}
}
代理类
/**
* 代理实现
*/
@Data
@Component
@ConfigurationProperties(prefix = "upload")
public class FileUploadProxy implements ApplicationContextAware {
@Autowired
private FileUpload aliyunOSSFileUpload;
@Autowired
private FileUpload fastdfsFileUpoad;
private ApplicationContext act;
// String 方式 list 需要上传的文件类型 例如: 本地 -》 jpg,png
private Map<String, List<String>> filemap;
public String upload(MultipartFile file) throws IOException {
// 文件名字
String filename = file.getOriginalFilename();
// 获取文件拓展名
String extName = StringUtils.getFilenameExtension(filename);
for (Map.Entry<String, List<String>> entry : filemap.entrySet()){
List<String> values = entry.getValue();
for(String value : values){
if(extName.equalsIgnoreCase(value)){
return act.getBean(entry.getKey(),FileUpload.class).upload(file.getBytes(),extName);
}
}
}
return null;
}
//注入容器对象
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException {
this.act=applicationContext;
}
}
控制器
@RestController
@RequestMapping(value = "/file")
public class FileController {
@Autowired
private FileUploadProxy fileUploadProxy;
/***
* 文件上传
* @param file
* @return
* @throws IOException
*/
@PostMapping(value = "/upload")
public String upload(MultipartFile file) throws Exception {
return fileUploadProxy.upload(file);
}
}
差不多就完成了,明天会更新享元模式,策略模式,状态模式,工厂模式等。
本人才疏学浅,难免有疏漏,如有疏漏,请大佬指出本人必虚心改正。有一些JAVA初学者或者自学者在路上遇到问题,可以私信,我会竭力为你解决一些基本的困惑。谢谢大家观看。