SpringBoot 策略模式 切换上传文件方式
策略模式
策略模式是指有一定行动内容的相对稳定的策略名称。
- 我们定义一个接口(就比如接下来要实现的文件上传接口)
- 我们定义所需要实现的策略实现类 A、B、C、D(也就是项目中所使用的四种策略阿里云Oss上传、腾讯云Cos上传、七牛云Kodo上传、本地上传)
- 我们通过策略上下文来调用策略接口,并选择所需要使用的策略
策略接口
1 2 3 4 5 6 7 8 9 10 11 12 | public interface UploadStrategy { /** * 上传文件 * * @param file 文件 * @param filePath 文件上传露肩 * @return {@link String} 文件上传的全路径 */ String uploadFile(MultipartFile file, final String filePath); } |
策略实现类内部实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | @Getter @Setter public abstract class AbstractUploadStrategyImpl implements UploadStrategy { @Override public String uploadFile(MultipartFile file, String filePath) { try { //region 获取文件md5值 -> 获取文件后缀名 -> 生成相对路径 String fileMd5 = XcFileUtil.getMd5(file.getInputStream()); String extName = XcFileUtil.getExtName(file.getOriginalFilename()); String fileRelativePath = filePath + fileMd5 + extName; //endregion //region 初始化 initClient(); //endregion //region 检测文件是否已经存在,不存在则进行上传操作 if (!checkFileIsExisted(fileRelativePath)) { executeUpload(file, fileRelativePath); } //endregion return getPublicNetworkAccessUrl(fileRelativePath); } catch (IOException e) { throw new XcException( "文件上传失败" ); } } /** * 初始化客户端 */ public abstract void initClient(); /** * 检查文件是否已经存在(文件MD5值唯一) * * @param fileRelativePath 文件相对路径 * @return true 已经存在 false 不存在 */ public abstract boolean checkFileIsExisted(String fileRelativePath); /** * 执行上传操作 * * @param file 文件 * @param fileRelativePath 文件相对路径 * @throws IOException io异常信息 */ public abstract void executeUpload(MultipartFile file, String fileRelativePath) throws IOException; /** * 获取公网访问路径 * * @param fileRelativePath 文件相对路径 * @return 公网访问绝对路径 */ public abstract String getPublicNetworkAccessUrl(String fileRelativePath); } |
本地上传策略具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | @Slf4j @Getter @Setter @RequiredArgsConstructor @Service ( "localUploadServiceImpl" ) public class LocalUploadStrategyImpl extends AbstractUploadStrategyImpl { /** * 本地项目端口 */ @Value ( "${server.port}" ) private Integer port; /** * 前置路径 ip/域名 */ private String prefixUrl; /** * 构造器注入bean */ private final ObjectStoreProperties properties; @Override public void initClient() { try { prefixUrl = ResourceUtils.getURL( "classpath:" ).getPath() + "static/" ; } catch (FileNotFoundException e) { e.printStackTrace(); throw new XcException( "文件不存在" ); } log.info( "initClient Init Success..." ); } @Override public boolean checkFileIsExisted(String fileRelativePath) { return new File(prefixUrl + fileRelativePath).exists(); } @Override public void executeUpload(MultipartFile file, String fileRelativePath) throws IOException { File dest = checkFolderIsExisted(fileRelativePath); try { file.transferTo(dest); } catch (IOException e) { e.printStackTrace(); throw new XcException( "文件上传失败" ); } } @Override public String getPublicNetworkAccessUrl(String fileRelativePath) { try { String host = InetAddress.getLocalHost().getHostAddress(); if (StringUtils.isEmpty(properties.getLocal().getDomainUrl())) { return String.format( "http://%s:%d%s" , host, port, fileRelativePath); } return properties.getLocal().getDomainUrl() + fileRelativePath; } catch (UnknownHostException e) { throw new XcException( "HttpCodeEnum.UNKNOWN_ERROR" ); } } /** * 检查文件夹是否存在,若不存在则创建文件夹,最终返回上传文件 * * @param fileRelativePath 文件相对路径 * @return {@link File} 文件 */ private File checkFolderIsExisted(String fileRelativePath) { File rootPath = new File(prefixUrl + fileRelativePath); if (!rootPath.exists()) { if (!rootPath.mkdirs()) { throw new XcException( "文件夹创建失败" ); } } return rootPath; } } |
策略上下文实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Component @RequiredArgsConstructor public class UploadStrategyContext { private final Map<String, UploadStrategy> uploadStrategyMap; /** * 执行上传策略 * * @param file 文件 * @param filePath 文件上传路径前缀 * @return {@link String} 文件上传全路径 */ public String executeUploadStrategy(MultipartFile file, final String filePath, String uploadServiceName) { // 执行特定的上传策略 return uploadStrategyMap.get(uploadServiceName).uploadFile(file, filePath); } } |
上传测试controller代码
1 2 3 4 5 6 7 8 9 10 11 12 | @RestController @RequiredArgsConstructor public class UploadController { private final UploadStrategyContext uploadStrategyContext; @PostMapping ( "/upload" ) public SingleResponse<?> upload(MultipartFile file) { String cosUploadServiceImpl = uploadStrategyContext.executeUploadStrategy(file, "/blog/avatar" , "localUploadServiceImpl" ); return SingleResponse.of( "文件上传成功!" + cosUploadServiceImpl); } } |
上传测试
文章来源:https://mp.weixin.qq.com/s/Bi7tFfKHXpBkXNpbTMR2lg
案例代码: https://gitcode.net/nanshen__/store-object
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-11-20 spring boot junit controller
2018-11-20 tomcat logs目录下 日志文件含义及配置位置