1.1 业务背景
当今互联网项目,需求日渐增多,并且应用服务器的压力也日渐增大,这时就引入了分布式系统的概念,然后又有了动静分离,即动态资源与静态资源分开,使后端的应用服务器专注业务请求的处理,并降低因为请求静态资源而为应用服务器带来的压力。
1.2 文件上传的实现方式有哪些?
- 直接上传到应用服务器(缺点:增加应用服务器的压力)。
- 通过搭建私有云,比如通过FASTDFS搭建一个分布式文件系统。
- 使用第三方云存储(阿里云OSS、七牛云等)。
1.3 文件上传的实现
1.3.1 前置准备
1. 创建一个枚举类FileSourceEnum
(用于后期实例化指定文件上传业务实现类)
package com.qingyun.farm.enums;
import lombok.Getter;
@Getter
public enum FileSourceEnum {
LOCAL(1L,"LOCAL"),
ALIYUN(2L,"ALIYUN"),
FAST_DFS(3L,"FAST_DFS");
private Long code;
private String desc;
FileSourceEnum(Long code, String desc) {
this.code=code;
this.desc=desc;
}
}
2. 创建一个文件上传业务实现类创建实例工厂类FileServiceFactory
package com.qingyun.farm.factory;
import com.qingyun.farm.enums.FileSourceEnum;
import com.qingyun.farm.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
/**
* Created with IntelliJ IDEA.
* User: 李敷斌.
* Date: 2020-04-02
* Time: 11:20
* Explain: 文件业务工厂类
*/
@Component
public class FileServiceFactory {
private HashMap<FileSourceEnum, FileService> fileServiceMap=new HashMap<>();
@Autowired
private FileService localFileServiceImpl;
@Autowired
private FileService aliyunFileServiceImpl;
@Autowired
private FileService fastdfsFileServiceImpl;
@PostConstruct
private void initFileService(){
fileServiceMap.put(FileSourceEnum.LOCAL,localFileServiceImpl);
fileServiceMap.put(FileSourceEnum.ALIYUN,aliyunFileServiceImpl);
fileServiceMap.put(FileSourceEnum.FAST_DFS,fastdfsFileServiceImpl);
}
public FileService getFileService(Long fileSourceCode) {
if (fileSourceCode.equals(FileSourceEnum.FAST_DFS.getCode())){
return fileServiceMap.get(FileSourceEnum.FAST_DFS);
}else if (fileSourceCode.equals(FileSourceEnum.ALIYUN.getCode())){
return fileServiceMap.get(FileSourceEnum.ALIYUN);
}
return fileServiceMap.get(FileSourceEnum.LOCAL);
}
}
3. 创建一个文件上传业务实现接口类FileService
package com.qingyun.farm.service;
import java.io.IOException;
import com.qingyun.farm.model.FileInfo;
import org.springframework.web.multipart.MultipartFile;
public interface FileService {
FileInfo upload(MultipartFile file) throws Exception;
void delete(FileInfo fileInfo);
}
4. 创建一个文件上传业务实现抽象父类AbstractFileService
package com.qingyun.farm.service.impl;
import com.qingyun.farm.dao.FileInfoDao;
import com.qingyun.farm.enums.FileSourceEnum;
import com.qingyun.farm.model.FileInfo;
import com.qingyun.farm.service.FileService;
import com.qingyun.farm.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
@Slf4j
public abstract class AbstractFileService implements FileService {
protected abstract FileInfoDao getFileDao();
@Override
public FileInfo upload(MultipartFile file) throws Exception {
FileInfo fileInfo = FileUtil.getFileInfo(file);
FileInfo oldFileInfo = getFileDao().getById(fileInfo.getId());
if (oldFileInfo != null) {
return oldFileInfo;
}
if (!fileInfo.getName().contains(".")) {
throw new IllegalArgumentException("缺少后缀名");
}
uploadFile(file, fileInfo);
fileInfo.setSource(fileSource().name());// 设置文件来源
getFileDao().save(fileInfo);// 将文件信息保存到数据库
log.info("上传文件:{}", fileInfo);
return fileInfo;
}
/**
* 文件来源
*
* @return
*/
protected abstract FileSourceEnum fileSource();
/**
* 上传文件
*
* @param file
* @param fileInfo
*/
protected abstract void uploadFile(MultipartFile file, FileInfo fileInfo) throws Exception;
@Override
public void delete(FileInfo fileInfo) {
deleteFile(fileInfo);
getFileDao().delete(fileInfo.getId());
log.info("删除文件:{}", fileInfo);
}
/**
* 删除文件资源
*
* @param fileInfo
* @return
*/
protected abstract boolean deleteFile(FileInfo fileInfo);
}
5 .创建一个文件上传请求控制器FileController
package com.qingyun.farm.controller;
import java.io.IOException;
import java.util.List;
import com.qingyun.farm.dao.FileInfoDao;
import com.qingyun.farm.dto.LayuiFile;
import com.qingyun.farm.factory.FileService