一、简介
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。下面将演示如何使用策略模式实现文件上传到本地和腾讯云cos。
二、使用步骤
1.创建一个接口
首先创建一个文件上传策略接口,定义文件上传方法。
public interface UploadStrategy {
/**
* 上传文件到指定路径
*/
String uploadFile(MultipartFile file, String path);
}
2.创建抽象模板类
创建一个抽象类,实现文件上传策略接口,拓展新的上传方式时,直接重写该抽象模板类即可,减少了代码量。
@Service
public abstract class AbstractUploadStrategy implements UploadStrategy {
/**
* 实现文件上传接口,配置文件名和上传路径
*/
@Override
public String uploadFile(MultipartFile file, String path) {
try {
// 生成文件名
String md5 = FileUtils.getMd5(file);
String extName = FileUtils.getExtension(file);
String fileName = md5 + "." + extName;
// 判断文件是否存在
if (!exists(path + fileName)) {
// 调用文件上传方法,由子类作具体实现
upload(path, fileName, file.getInputStream());
}
// 返回文件访问路径
return getFileAccessUrl(path + fileName);
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException("文件上传失败");
}
}
/**
* 判断文件是否存在
*/
public abstract Boolean exists(String filePath);
/**
* 上传
*/
public abstract void upload(String path, String fileName, InputStream inputStream) throws IOException;
/**
* 获取文件访问url
*/
public abstract String getFileAccessUrl(String filePath);
}
3.重写抽象模板类
第一个实现类,文件上传到腾讯云cos
@Service("cosUploadStrategyImpl")
public class CosUploadStrategy extends AbstractUploadStrategy {
@Autowired
private CosProperties cosProperties;
@Override
public void upload(String path, String fileName, InputStream inputStream) {
COSClient cosClient = getCosClient();
try {
ObjectMetadata objectMetadata = new ObjectMetadata();
// 上传的流如果能够获取准确的流长度,则推荐一定填写 content-length
objectMetadata.setContentLength(inputStream.available());
// 调用cos方法上传
cosClient.putObject(cosProperties.getBucketName(), path + fileName, inputStream, objectMetadata);
} catch (CosServiceException e) {
log.error("Error Message:" + e.getErrorMessage());
} finally {
cosClient.shutdown();
}
}
@Override
public Boolean exists(String filePath) {
return getCosClient().doesObjectExist(cosProperties.getBucketName(), filePath);
}
@Override
public String getFileAccessUrl(String filePath) {
return cosProperties.getUrl() + filePath;
}
/**
* 获取cosClient
*/
private COSClient getCosClient() {
// 1 初始化用户身份信息(secretId, secretKey)。
COSCredentials cred = new BasicCOSCredentials(cosProperties.getSecretId(), cosProperties.getSecretKey());
// 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
Region region = new Region(cosProperties.getRegion());
ClientConfig clientConfig = new ClientConfig(region);
clientConfig.setHttpProtocol(HttpProtocol.https);
// 3 生成 cos 客户端。
return new COSClient(cred, clientConfig);
}
}
第二个实现类,文件上传到本地
@Service("localUploadStrategyImpl")
public class LocalUploadStrategy extends AbstractUploadStrategy {
/**
* 本地路径
*/
@Value("${upload.local.path}")
private String localPath;
/**
* 访问url
*/
@Value("${upload.local.url}")
private String localUrl;
@Override
public Boolean exists(String filePath) {
return new File(localPath + filePath).exists();
}
@Override
public void upload(String path, String fileName, InputStream inputStream) throws IOException {
// 判断目录是否存在
File directory = new File(localPath + path);
if (!directory.exists()) {
//创建文件目录
boolean isMkdir = directory.mkdirs();
if (!isMkdir) {
throw new ServiceException("创建目录失败");
}
}
// 写入文件
File file = new File(localPath + path + fileName);
if (file.createNewFile()) {
try (BufferedInputStream bis = new BufferedInputStream(inputStream);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
byte[] bytes = new byte[4096];
int length;
while ((length = bis.read(bytes)) != -1) {
bos.write(bytes, 0, length);
}
}
}
}
@Override
public String getFileAccessUrl(String filePath) {
return localUrl + filePath;
}
}
4.创建context类
@Service
public class UploadStrategyContext {
/**
* yml文件中配置的上传模式,local,cos
*/
@Value("${upload.strategy}")
private String uploadMode;
/**
* key:上传上传策略名 value:上传策略
* UploadStrategy接口有多个实现类,无法直接注入,这里采用用Map方式获取
*/
@Autowired
private Map<String, UploadStrategy> uploadStrategyMap;
/**
* 上传文件
*/
public String executeUploadStrategy(MultipartFile file, String path) {
//根据上传模式获取上传策略名
String uploadStrategy= UploadModeEnum.getStrategy(uploadMode);
//根据上传策略名获取上传策略
UploadStrategy uploadStrategyImpl = uploadStrategyMap.get(uploadStrategy);
//上传文件,并返回上传路径
return uploadStrategyImpl.uploadFile(file,path);
}
}
5.测试
调用文件上传方法,实现文件上传
@Autowired
private UploadStrategyContext uploadStrategyContext;
、、、
//调用文件上传方法
String url=uploadStrategyContext.executeUploadStrategy(file,path);