当前位置: 首页 > news >正文

上传文件相关业务,采用策略模式+模版方法模式进行动态解耦

service 里面是注入的策略上下文

我们用策略上下文去调对应的方法

    public String uploadPhoto(MultipartFile file) {// 上传文件String url = uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.PHOTO.getPath());blogFileService.saveBlogFile(file, url, FilePathEnum.PHOTO.getFilePath());return url;}

策略上下文(StrategyContext)中我们把策略定义成常量,从配置中装载

这个是我们在 yml 里面定义的常量

除了这个常量,策略上下文里面还有一个 map

这个 map 的 key 是 string 策略名称,value 是对应的下载策略

我们通过 我们写在配置文件里面的配置去 map 去调对应的策略

UploadStrategy 是一个接口

这边采用模版方法设计模式

即采用接口+抽象类的方式

我们在接口中定义统一规范

应对当前上传业务,我们只需要一个 uploadFile 方法即可

接着是模版

我们想一下我们的模版应该怎么去写

我们想到每一个实现类,都要写一个上传方法

这对应着我们调不同的客户端去执行相应的方法,uploadFile()这个方法里面会调取这个方法

然后我们就应该能想到,还有一个检查文件是否存在的方法

接着我们还要有一个出口,就是获取文件的路径

毕竟客户端的自己实现逻辑都不同,所以我们都要进行重写

package com.ican.strategy.impl;import com.ican.exception.ServiceException;
import com.ican.strategy.UploadStrategy;
import com.ican.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;/*** 抽象上传模板** @author Dduo*/
@Slf4j
@Service
public abstract class AbstractUploadStrategyImpl implements UploadStrategy {@Overridepublic String uploadFile(MultipartFile file, String path) {try {// 获取文件md5值String md5 = FileUtils.getMd5(file.getInputStream());// 获取文件扩展名String extName = FileUtils.getExtension(file);// 重新生成文件名String fileName = md5 + "." + extName;// 判断文件是否已存在Boolean exists = exists(path + fileName);if (!exists) {// 不存在则继续上传upload(path, fileName, file.getInputStream());}// 返回文件访问路径return getFileAccessUrl(path + fileName);} catch (Exception e) {log.info("uploadFile fail, error is {}", e.getMessage());throw new ServiceException("文件上传失败");}}/*** 判断文件是否存在** @param filePath 文件路径* @return {@link Boolean}*/public abstract Boolean exists(String filePath);/*** 上传** @param path        路径* @param fileName    文件名* @param inputStream 输入流* @throws IOException io异常*/public abstract void upload(String path, String fileName, InputStream inputStream) throws IOException;/*** 获取文件访问url** @param filePath 文件路径* @return {@link String} 文件url*/public abstract String getFileAccessUrl(String filePath);}

这边有一个 cos 实现逻辑

仅仅供参考

package com.ican.strategy.impl;import com.ican.config.properties.CosProperties;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.region.Region;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.io.InputStream;/*** cos上传策略** @author Dduo*/
@Slf4j
@Service("cosUploadStrategyImpl")
public class CosUploadStrategyImpl extends AbstractUploadStrategyImpl {@Autowiredprivate CosProperties cosProperties;@Overridepublic Boolean exists(String filePath) {return getCosClient().doesObjectExist(cosProperties.getBucketName(), filePath);}@Overridepublic void upload(String path, String fileName, InputStream inputStream) {COSClient cosClient = getCosClient();try {ObjectMetadata objectMetadata = new ObjectMetadata();// 上传的流如果能够获取准确的流长度,则推荐一定填写 content-lengthobjectMetadata.setContentLength(inputStream.available());// 调用cos方法上传cosClient.putObject(cosProperties.getBucketName(), path + fileName, inputStream, objectMetadata);} catch (CosServiceException e) {log.error("Error Message:" + e.getErrorMessage());log.error("Error Code:" + e.getErrorCode());log.info("Request ID:" + e.getRequestId());} catch (CosClientException e) {log.error("Caught an CosClientException, Error Message:" + e.getMessage());} catch (IOException e) {log.error("Caught an IOException, Error Message:" + e.getMessage());} finally {cosClient.shutdown();}}@Overridepublic String getFileAccessUrl(String filePath) {return cosProperties.getUrl() + filePath;}/*** 获取cosClient** @return {@link COSClient} 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/6224Region region = new Region(cosProperties.getRegion());ClientConfig clientConfig = new ClientConfig(region);// 这里建议设置使用 https 协议// 从 5.6.54 版本开始,默认使用了 httpsclientConfig.setHttpProtocol(HttpProtocol.https);// 3 生成 cos 客户端。return new COSClient(cred, clientConfig);}
}

http://www.dtcms.com/a/481801.html

相关文章:

  • Unity3d中Tab控件的实现
  • 桥梁主动防撞预警系统方案
  • 【node】运行windows7下的高版本node.js
  • 解密NLP:从入门到精通
  • 如何说课网站建设当地公交建设公司的官网
  • 哪里有网站开发服务器西安关键词排名提升
  • npx 与 npm 区别
  • diffusion model(0.5) score-SDE 关于score function与noise的关系
  • leetcode724 寻找数组的中心下标
  • AI用户洞察新纪元:atypica.AI如何重塑商业决策逻辑
  • 彻底解决 Zip4j 解压中文文件名乱码问题(含混合编码与 Mac 特殊情况)
  • 河北农业网站建设公司凡科互动官网登录
  • 企业网站建设的成本构成吉林市网站建设招标
  • git push 报错 push rejected (一文读懂并解决)
  • 从缓存到分库分表:MySQL 高并发海量数据解决方案全解析
  • 苍穹外卖-缓存套餐 Spring Cache day07
  • 垂直电商网站建设方案wordpress主题开发时间
  • 报告工具更新!Word附注一键期末转期初
  • 优化A7M4相机直播图像传输:避免质量损失,实现端到端高保真
  • 平替MongoDB金仓多模数据库在电子证照国产化中的实践与优势
  • AWS WAF 深度体验:全新控制台,开启云原生WAF与CloudFront无缝联防新纪元
  • 【统计字母出现最多次数不分大小写按字典顺序输出】2022-11-9
  • 怎么查自己的网站备案编号本人已履行网站备案信息
  • 电子商务网站建设结论谷歌查询关键词的工具叫什么
  • Ubuntu 安装 SSH,并开启 root 远程登录
  • python学习之路(一)
  • 电源唐大师
  • QT-常用控件(四)-输入类
  • newstar2025 web week1week2题解(少一道)
  • 【C++】vector常用接口的使用