概述

最近在想做个cloud项目,gitee上找了个模板项目,后端使用到 Nacos、Gateway、Security等技术,看到 文件上传 模板模式+策略模式 用得很好,再次分享一下。

什么是模板模式

一个抽象类中,有一个主方法,再定义1…n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用。

优点

  • 封装不变的部分,将不变的部分抽取出来;
  • 扩展可变部分,将可变的设置抽象方法,让具体子类来实现。
  • 抽取的公共代码,便于后期维护。
  • 行为有基类来控制,具体操作有子类实现。

缺点

  • 每一个不同的实现都需要有一个子类来实现,这样就会导致类的数量大大的增加,使得系统更加庞大。

模式实现及实践

需求

比如我们有一个文件上传功能,后端保存文件的方式很多,比如本地上传、阿里云OSS、华为、腾讯等等,根据模板模式 + 策略模式实现文件上传。

Spring Boot 实现

yml

storage:enabled: trueconfig:# 存储类型:local、aliyun、tencent、qiniu、huawei、miniotype: localdomain: http://localhost:8080local:# 存储地址path: /package/web_project/fast_shaking_cloud_package/

StorageProperties(yml映射)

*** 存储配置项** @author lanys*/
@Data
@ConfigurationProperties(prefix = "storage")
public class StorageProperties {/*** 是否开启存储*/private boolean enabled;/*** 通用配置项*/private StorageConfig config;/*** 本地配置项*/private LocalStorageProperties local;/*** 阿里云配置项*/private AliyunStorageProperties aliyun;@Datapublic static class StorageConfig {/*** 访问域名*/private String domain;/*** 配置路径前缀*/private String prefix;/*** 存储类型*/private StorageTypeEnum type;}@Bean@ConfigurationProperties(prefix = "storage.local")public LocalStorageProperties localStorageProperties() {return new LocalStorageProperties();}@Bean@ConfigurationProperties(prefix = "storage.aliyun")public AliyunStorageProperties aliyunStorageProperties() {return new AliyunStorageProperties();}
}

LocalStorageProperties(本地映射实体)

/*** 本地存储配置项** @author lanys*/
@Data
public class LocalStorageProperties {/*** 本地存储路径*/private String path;/*** 资源起始路径*/private String url = "upload";
}

AliyunStorageProperties(阿里云映射实体)

/*** 阿里云存储配置项** @author 阿沐 babamu@126.com*/
@Data
public class AliyunStorageProperties {private String endPoint;private String accessKeyId;private String accessKeySecret;private String bucketName;
}

StorageConfiguration (映射配置,策略模式)

@Configuration
@EnableConfigurationProperties(StorageProperties.class)
@ConditionalOnProperty(prefix = "storage", value = "enabled")
public class StorageConfiguration {@Beanpublic StorageService storageService(StorageProperties properties) {if (properties.getConfig().getType() == StorageTypeEnum.LOCAL) {return new LocalStorageService(properties);} else if (properties.getConfig().getType() == StorageTypeEnum.ALIYUN) {return new AliyunStorageService(properties);} return null;}}

StorageService (抽象模板)

/*** 存储服务** @author lanys*/
public abstract class StorageService {public StorageProperties properties;/*** 根据文件名,生成带时间戳的新文件名** @param fileName 文件名* @return 返回带时间戳的文件名*/public String getNewFileName(String fileName) {// 主文件名,不包含扩展名String prefix = FileNameUtil.getPrefix(fileName);// 文件扩展名String suffix = FileNameUtil.getSuffix(fileName);// 把当天HH:mm:ss,转换成秒long time = DateUtil.timeToSecond(DateUtil.formatTime(new Date()));// 新文件名return prefix + "_" + time + "." + suffix;}/*** 生成路径,不包含文件名** @return 返回生成的路径*/public String getPath() {// 文件路径String path = DateUtil.format(new Date(), "yyyyMMdd");// 如果有前缀,则也带上if (StringUtils.hasText(properties.getConfig().getPrefix())) {path = properties.getConfig().getPrefix() + "/" + path;}return path;}/*** 根据文件名,生成路径** @param fileName 文件名* @return 生成文件路径*/public String getPath(String fileName) {return getPath() + "/" + getNewFileName(fileName);}/*** 文件上传(抽象方法)** @param data 文件字节数组* @param path 文件路径,包含文件名* @return 返回http地址*/public abstract String upload(byte[] data, String path);/*** 文件上传(抽象方法)** @param inputStream 字节流* @param path        文件路径,包含文件名* @return 返回http地址*/public abstract String upload(InputStream inputStream, String path);
}

LocalStorageService(本地具体实现)

public class LocalStorageService extends StorageService {public LocalStorageService(StorageProperties properties) {this.properties = properties;}@Overridepublic String upload(byte[] data, String path) {return upload(new ByteArrayInputStream(data), path);}@Overridepublic String upload(InputStream inputStream, String path) {try {File file = new File(properties.getLocal().getPath() + File.separator + path);// 没有目录,则自动创建目录File parent = file.getParentFile();if (parent != null && !parent.mkdirs() && !parent.isDirectory()) {throw new IOException("目录 '" + parent + "' 创建失败");}FileCopyUtils.copy(inputStream, Files.newOutputStream(file.toPath()));} catch (Exception e) {throw new ServerException("上传文件失败:", e);}return properties.getConfig().getDomain() + "/" + properties.getLocal().getUrl() + "/" + path;}
}

AliyunStorageService(OSS具体实现)

public class AliyunStorageService extends StorageService {public AliyunStorageService(StorageProperties properties) {this.properties = properties;}@Overridepublic String upload(byte[] data, String path) {return upload(new ByteArrayInputStream(data), path);}@Overridepublic String upload(InputStream inputStream, String path) {OSS client = new OSSClientBuilder().build(properties.getAliyun().getEndPoint(),properties.getAliyun().getAccessKeyId(), properties.getAliyun().getAccessKeySecret());try {client.putObject(properties.getAliyun().getBucketName(), path, inputStream);} catch (Exception e) {throw new ServerException("上传文件失败:", e);} finally {if (client != null) {client.shutdown();}}return properties.getConfig().getDomain() + "/" + path;}}

测试

@RestController
@RequestMapping("file")
@Tag(name = "文件上传")
@AllArgsConstructor
public class SysFileUploadController {private final StorageService storageService;@PostMapping("upload")@Operation(summary = "上传")public Result<SysFileUploadVO> upload(@RequestParam("file") MultipartFile file) throws Exception {if (file.isEmpty()) {return Result.error("请选择需要上传的文件");}// 上传路径String path = storageService.getPath(file.getOriginalFilename());// 上传文件String url = storageService.upload(file.getBytes(), path);// 封装voSysFileUploadVO vo = new SysFileUploadVO();vo.setUrl(url);vo.setSize(file.getSize());vo.setName(file.getOriginalFilename());vo.setPlatform(storageService.properties.getConfig().getType().name());return Result.ok(vo);}
}

实现效果

设计模式-模板模式(清晰明了)相关推荐

  1. 12. 星际争霸之php设计模式--模板模式

    题记 ============================================================================== 本php设计模式专辑来源于博客(jy ...

  2. Java设计模式-模板模式

    Java设计模式-模板模式 什么是模板模式? 模板模式,顾名思义,就是通过模板拓印的方式. 定义模板,就是定义框架.结构.原型.定义一个我们共同遵守的约定. 定义模板,我们的剩余工作就是对其进行充实. ...

  3. Java设计模式—模板模式(Template)

    模板模式 业务需求 编写豆浆制作程序 选材-添加配料-浸泡-豆浆机打碎 选材.浸泡.打碎这几步对于制作不同豆浆都是一样的 比较简单,这里不再使用传统方法,直接上设计模式 模板模式基本介绍 模板模式,在 ...

  4. 【设计模式】Java设计模式 - 模板模式

    [设计模式]Java设计模式 - 模板模式

  5. C语言实现设计模式—模板模式

    文章目录 C语言实现设计模式-模板模式 模板模式介绍 UML用例说明 实际场景使用 框架结构[共用框架]-通用的串口协议分析函数 不同实现-数据类型区别 C语言实现设计模式-模板模式 模板模式介绍 在 ...

  6. 16、Python与设计模式--模板模式

    一.股票查询客户端 投资股票是种常见的理财方式,我国股民越来越多,实时查询股票的需求也越来越大.今天,我们通过一个简单的股票查询客户端来认识一种简单的设计模式:模板模式. 根据股票代码来查询股价分为如 ...

  7. PHP设计模式——模板模式

    声明:本系列博客参考资料<大话设计模式>,作者程杰. 模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的 ...

  8. 设计模式 模板模式和策略模式

    模板模式和策略模式,有相识的地方,都是通过对钩子方法的调用,来实现一个业务的完整逻辑. 所以这里我将两种模式放在一起介绍,比较容易加深对这两种模式的理解. 模板模式 在模板模式(Template Pa ...

  9. java设计模式————模板模式,手撸一个JDBCTemplate

    模板模式(Template Method Pattern) 定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现. 模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤. 属于行为 ...

最新文章

  1. mysql v8 漏洞_mysql'密码安全 - osc_v8gts6gd的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. 沙雕记(1) 之 Land Grab
  3. (原创)VS2017 C# 运行 Javasrcipt RSA 加密用户名登录 Java开发的服务器
  4. Git笔记(13) 分支管理
  5. (1)H5实现音乐播放器【正在播放-歌词篇】
  6. 固态硬盘在线测试软件,SSD检测工具(SSDlife Pro)
  7. 切向量,法向量,梯度
  8. mysql多表格数据合并_mysql 如何实现两个表数据统计合并
  9. 看了这个你也可以做SYSLINUX启动光盘
  10. html中什么用来表示特殊字符引号,HTML特殊字符显示
  11. 论文(四):DTFD-MIL: Double-Tier Feature Distillation Multiple Instance Learning for Histopathology Whole
  12. 【ESP8266】ESP8266的MQTT客户端搭建教程(基于NONS_SDK_v2.0)
  13. [软件更新]SRS Audio Sandbox v1.9.0.4 汉化版
  14. 计算机配置ppt制作,做ppt.ps要用什么样的配置的手提电脑做
  15. AD的设计里面找不到生成PCB选项
  16. Sql语句的优化以及Sql语句优化工具
  17. web前端HTML_1(简单页面的实现)
  18. 强类型c语言 类型
  19. 微网站 源码 php,DIYWAP手机微网站内容管理系统 php版 v6.3
  20. SQLYog 数据连接配置的迁移

热门文章

  1. 北大本科转行计算机,北京教委公布本科跨省转学名单,两学霸为学计算机转出北大...
  2. 《塞尔达传说:荒野之息》开发者演讲
  3. Windows打开端口3306
  4. 亚马逊测评卖家实操提升review和转化率方式
  5. 回首“360”和“金山”的那次战役--小马哥“以彼之道还施彼身”
  6. R5 3600X和i5 10600K 对比哪个好
  7. 学python心得体会800字-终于领会学习python的心得体会
  8. Word控件Spire.Doc 【图像形状】教程(5) 如何在 C# 中将文本环绕在图像周围
  9. linux中ss命令
  10. linux send 失败_求助:sendto()发送UDP数据包失败:message too long该如何解决?