1:首先配置pom依赖:
com.aliyun.ossaliyun-sdk-oss3.8.0com.qcloudcos_api5.6.75
2:application.yml:
# 上传模式 (本地 阿里云 腾讯云)
# 上传模式 (Window服务器,Linux服务器本地 阿里云 腾讯云)
upload:mode: windowsLocallinuxLocal:# nginx映射本地文件路径,无域名则为 ip:83url: https://上传子域名/# 本地文件存储路径path: /usr/local/blog/upload/# Windows环境下测试 这里路径对应config中mvc拦截器里面的路径windowsLocal:url: http://localhost:8080/upload/path: G:/桌面/博客/mongo-blog-master/springboot/src/main/resources/upload/oss:url: http://Bucket域名/endpoint: OSS配置endpointaccessKeyId: OSS配置accessKeyIdaccessKeySecret: OSS配置accessKeySecretbucketName: OSS配置bucketNamecos:url: https://ftz-1307097786.cos.ap-beijing.myqcloud.com/region: ap-beijingsecretId: AKIDhKqBJPN8mDWcWFm6oVBj4A2h7IF2lFUXsecretKey: tBLekcFi27yb3IJ6i7GCzYt2ymLgtwmtbucketName: ftz-1307097786
2.1:腾讯云信息查看:secretId+secretKey在访问密钥里面查看

2.2:url+region+bucketName在配置管理查看

3:Windows本地,Linux本地,阿里云,腾讯云的配置:
3.1 :Windows本地配置:
(1):首先配置application.yml:

(2***):重点:配置登录拦截器,设置虚拟路径,因为浏览器不可以直接访问电脑资源目录文件,所以需要设置虚拟路径!否则会报错:Not allowed to load local resource
;这里的路径要跟application.yml中的路径相匹配
@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/upload/**").addResourceLocations("file:G:/桌面/博客/mongo-blog-master/springboot/src/main/resources/upload/");}

(3):策略枚举层:

package com.jjhroy.blog.enums;import lombok.AllArgsConstructor;
import lombok.Getter;/*** 上传模式枚举** @author yezhiqiu* @date 2021/07/28*/
@Getter
@AllArgsConstructor
public enum UploadModeEnum {/*** oss*/OSS("oss", "ossUploadStrategyImpl"),/*** Linux本地*/LOCAL("linuxLocal", "localUploadStrategyImpl"),/*** Windows本地*/WINDOWS("windowsLocal","windowsUploadStrategyImpl"),/*** cos*/COS("cos", "cosUploadStrategyImpl");/*** 模式*/private final String mode;/*** 策略*/private final String strategy;/*** 获取策略** @param mode 模式* @return {@link String} 搜索策略*/public static String getStrategy(String mode) {for (UploadModeEnum value : UploadModeEnum.values()) {if (value.getMode().equals(mode)) {return value.getStrategy();}}return null;}}
(4):文件上传策略:

package com.jjhroy.blog.strategy.context;import com.jjhroy.blog.enums.UploadModeEnum;
import com.jjhroy.blog.strategy.UploadStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.util.Map;/*** 上传策略上下文** @author yezhiqiu* @date 2021/07/28*/
@Service
public class UploadStrategyContext {/*** 上传模式*/@Value("${upload.mode}")private String uploadMode;@Autowiredprivate Map uploadStrategyMap;/*** 执行上传策略** @param file 文件* @param path 路径* @return {@link String} 文件地址*/public String executeUploadStrategy(MultipartFile file, String path) {return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(file, path);}/*** 执行上传策略** @param fileName 文件名称* @param inputStream 输入流* @param path 路径* @return {@link String} 文件地址*/public String executeUploadStrategy(String fileName, InputStream inputStream, String path) {return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(fileName, inputStream, path);}}
(5):本地路径上传策略方法实现层:WindowsUploadStrategyImpl:

package com.jjhroy.blog.strategy.impl;import com.jjhroy.blog.enums.FileExtEnum;
import com.jjhroy.blog.exception.BizException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import java.io.*;
import java.nio.file.Files;
import java.util.Objects;/*** @author ftz** Windows本地上传策略**/
@Service("windowsUploadStrategyImpl")
public class WindowsUploadStrategyImpl extends AbstractUploadStrategyImpl {/*** 本地路径*/@Value("${upload.windowsLocal.path}")private String localPath;@Value("${upload.windowsLocal.url}")private String localUrl;@Overridepublic Boolean exists(String filePath) {return new File(localPath + filePath).exists();}@Overridepublic void upload(String path, String fileName, InputStream inputStream) throws IOException {// 判断目录是否存在File directory = new File(localPath + path);if (!directory.exists()) {if (!directory.mkdirs()) {throw new BizException("创建目录失败");}}// 写入文件File file = new File(localPath + path + fileName);String ext = "." + fileName.split("\\.")[1];switch (Objects.requireNonNull(FileExtEnum.getFileExt(ext))) {case MD:case TXT:BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));BufferedWriter writer = new BufferedWriter(new FileWriter(file));while (reader.ready()) {writer.write((char) reader.read());}writer.flush();writer.close();reader.close();break;default:BufferedInputStream bis = new BufferedInputStream(inputStream);BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(file.toPath()));byte[] bytes = new byte[1024];int length;while ((length = bis.read(bytes)) != -1) {bos.write(bytes, 0, length);}bos.flush();bos.close();bis.close();break;}inputStream.close();}@Overridepublic String getFileAccessUrl(String filePath) {return localUrl+filePath;}}
(6):controller层:更新用户头像为例:
/*** 更新用户头像** @param file 文件* @return {@link Result} 头像地址*/@ApiOperation(value = "更新用户头像")@ApiImplicitParam(name = "file", value = "用户头像", required = true, dataType = "MultipartFile")@PostMapping("/users/avatar")public Result updateUserAvatar(MultipartFile file) {return Result.ok(userInfoService.updateUserAvatar(file));}
(7):userInfoService.updateUserAvatar层及其实现:
@Transactional(rollbackFor = Exception.class)@Overridepublic String updateUserAvatar(MultipartFile file) {// 头像上传String avatar = uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.AVATAR.getPath());// 更新用户信息UserInfo userInfo = UserInfo.builder().id(UserUtils.getLoginUser().getUserInfoId()).avatar(avatar).build();userInfoDao.updateById(userInfo);return avatar;}
(8):uploadStrategyContext.executeUploadStrategy:

package com.jjhroy.blog.strategy.context;import com.jjhroy.blog.enums.UploadModeEnum;
import com.jjhroy.blog.strategy.UploadStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.util.Map;/*** 上传策略上下文** @author yezhiqiu* @date 2021/07/28*/
@Service
public class UploadStrategyContext {/*** 上传模式*/@Value("${upload.mode}")private String uploadMode;@Autowiredprivate Map uploadStrategyMap;/*** 执行上传策略** @param file 文件* @param path 路径* @return {@link String} 文件地址*/public String executeUploadStrategy(MultipartFile file, String path) {return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(file, path);}/*** 执行上传策略** @param fileName 文件名称* @param inputStream 输入流* @param path 路径* @return {@link String} 文件地址*/public String executeUploadStrategy(String fileName, InputStream inputStream, String path) {return uploadStrategyMap.get(UploadModeEnum.getStrategy(uploadMode)).uploadFile(fileName, inputStream, path);}}
(9):抽象上传模板

(10)文件上传工具类:
package com.jjhroy.blog.util;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Hex;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.Objects;/*** 文件md5工具类** @author yezhiqiu* @date 2021/07/28*/
@Log4j2
public class FileUtils {/*** 获取文件md5值** @param inputStream 文件输入流* @return {@link String} 文件md5值*/public static String getMd5(InputStream inputStream) {try {MessageDigest md5 = MessageDigest.getInstance("md5");byte[] buffer = new byte[8192];int length;while ((length = inputStream.read(buffer)) != -1) {md5.update(buffer, 0, length);}return new String(Hex.encodeHex(md5.digest()));} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {e.printStackTrace();}}}/*** 得到文件扩展名** @param fileName 文件名称* @return {@link String} 文件后缀*/public static String getExtName(String fileName) {if (StringUtils.isBlank(fileName)) {return "";}return fileName.substring(fileName.lastIndexOf("."));}/*** 转换file** @param multipartFile 多部分文件* @return {@link File} file*/public static File multipartFileToFile(MultipartFile multipartFile) {File file = null;try {String originalFilename = multipartFile.getOriginalFilename();String[] filename = Objects.requireNonNull(originalFilename).split("\\.");file = File.createTempFile(filename[0], filename[1]);multipartFile.transferTo(file);file.deleteOnExit();} catch (IOException e) {e.printStackTrace();}return file;}/*** 自动调节精度(经验数值)** @param size 源图片大小* @return 图片压缩质量比*/private static double getAccuracy(long size) {double accuracy;if (size < 900) {accuracy = 0.85;} else if (size < 2048) {accuracy = 0.6;} else if (size < 3072) {accuracy = 0.44;} else {accuracy = 0.4;}return accuracy;}}
3.2:其余三种类似,只需要改变一下application.yml就好