两种上传图片的方式——91张先生
上传图片的两种方式
`
文章目录
- 上传图片的两种方式
 - 前言
 - 一、直接上传到项目jar包根目录
 - 工具类的方法
 - Untils
 
- 二、上传到MinIo
 - 搭建MinIo服务就跳过了,宝塔直接一分钟搭建,然后创建Bruck
 - Controller
 - Service
 
- 总结
 - 两种方式都可以,第一种更倾向于小数量,在项目下存储,第二种更倾向于大数据量存储,使用OSS上传
 
前言
每个程序员貌似对上传图片都有一种执念,感觉一个项目有了上传图片上传文件的功能就很难,今天就给大家分享一下怎么上传图片,直接上干货
一、直接上传到项目jar包根目录
工具类的方法
/**/*** 获取上传路径*/public static String getUploadPath(){return getProfile() + "/upload";}* 通用上传请求(单个)*/@PostMapping("/upload")public AjaxResult uploadFile(MultipartFile file) throws Exception{try{// 上传文件路径String filePath = getUploadPath();// 上传并返回新文件名称String fileName = FileUploadUtils.upload(filePath, file);String url = serverConfig.getUrl() + fileName;AjaxResult ajax = AjaxResult.success();ajax.put("url", url);ajax.put("fileName", fileName);ajax.put("newFileName", FileUtils.getName(fileName));ajax.put("originalFilename", file.getOriginalFilename());return ajax;}catch (Exception e){return AjaxResult.error(e.getMessage());}}
 
Untils
 public static final String[] DEFAULT_ALLOWED_EXTENSION = {// 图片"bmp", "gif", "jpg", "jpeg", "png",// word excel powerpoint"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",// 压缩文件"rar", "zip", "gz", "bz2",// 视频格式"mp4", "avi", "rmvb",// pdf"pdf" };/*** 根据文件路径上传** @param baseDir 相对应用的基目录* @param file 上传的文件* @return 文件名称* @throws IOException*/public static final String upload(String baseDir, MultipartFile file) throws IOException{try{return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);}catch (Exception e){throw new IOException(e.getMessage(), e);}}/*** 默认的文件名最大长度 100*/public static final int DEFAULT_FILE_NAME_LENGTH = 100;
/*** 文件上传** @param baseDir 相对应用的基目录* @param file 上传的文件* @param allowedExtension 上传文件类型* @return 返回上传成功的文件名* @throws FileSizeLimitExceededException 如果超出最大大小* @throws FileNameLengthLimitExceededException 文件名太长* @throws IOException 比如读写文件出错时* @throws InvalidExtensionException 文件校验异常*/public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,InvalidExtensionException{return upload(baseDir, file, allowedExtension, false);}/*** 文件上传** @param baseDir 相对应用的基目录* @param file 上传的文件* @param useCustomNaming 系统自定义文件名* @param allowedExtension 上传文件类型* @return 返回上传成功的文件名* @throws FileSizeLimitExceededException 如果超出最大大小* @throws FileNameLengthLimitExceededException 文件名太长* @throws IOException 比如读写文件出错时* @throws InvalidExtensionException 文件校验异常*/public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension, boolean useCustomNaming)throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,InvalidExtensionException{int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH){throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);}assertAllowed(file, allowedExtension);String fileName = useCustomNaming ? uuidFilename(file) : extractFilename(file);String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));return getPathFileName(baseDir, fileName);}/*** 默认大小 50M*/public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };public static final String[] FLASH_EXTENSION = { "swf", "flv" };public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg","asf", "rm", "rmvb" };public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };/*** 文件大小校验** @param file 上传的文件* @return* @throws FileSizeLimitExceededException 如果超出最大大小* @throws InvalidExtensionException*/public static final void assertAllowed(MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, InvalidExtensionException{long size = file.getSize();if (size > DEFAULT_MAX_SIZE){throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);}String fileName = file.getOriginalFilename();String extension = getExtension(file);if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)){if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION){throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION){throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION){throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION){throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,fileName);}else{throw new InvalidExtensionException(allowedExtension, extension, fileName);}}}/*** 编编码文件名(日期格式目录 + UUID + 后缀)*/public static final String uuidFilename(MultipartFile file){return StringUtils.format("{}/{}.{}", DateUtils.datePath(), IdUtils.fastSimpleUUID(), getExtension(file));}public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException{File desc = new File(uploadDir + File.separator + fileName);if (!desc.exists()){if (!desc.getParentFile().exists()){desc.getParentFile().mkdirs();}}return desc;}/*** 编码文件名(日期格式目录 + 原文件名 + 序列值 + 后缀)*/public static final String extractFilename(MultipartFile file){return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));}public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException{File desc = new File(uploadDir + File.separator + fileName);if (!desc.exists()){if (!desc.getParentFile().exists()){desc.getParentFile().mkdirs();}}return desc;}/*** 资源映射路径 前缀*/public static final String RESOURCE_PREFIX = "/profile";public static final String getPathFileName(String uploadDir, String fileName) throws IOException{int dirLastIndex = getProfile().length() + 1;String currentDir = StringUtils.substring(uploadDir, dirLastIndex);return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;} 
二、上传到MinIo
搭建MinIo服务就跳过了,宝塔直接一分钟搭建,然后创建Bruck
Controller
/*** 上传OSS对象存储** @param file 文件*/@SaCheckPermission("system:oss:upload")@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public R<SysOssUploadVo> upload(@RequestPart("file") MultipartFile file) {if (ObjectUtil.isNull(file)) {return R.fail("上传文件不能为空");}SysOssVo oss = ossService.upload(file);SysOssUploadVo uploadVo = new SysOssUploadVo();uploadVo.setUrl(oss.getUrl());uploadVo.setFileName(oss.getOriginalName());uploadVo.setOssId(oss.getOssId().toString());return R.ok(uploadVo);}/*** 下载OSS对象** @param ossId OSS对象ID*/@SaCheckPermission("system:oss:download")@GetMapping("/download/{ossId}")public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {ossService.download(ossId, response);} 
Service
@Overridepublic SysOssVo upload(MultipartFile file) {String originalfileName = file.getOriginalFilename();String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());OssClient storage = OssFactory.instance();UploadResult uploadResult;try {uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());} catch (IOException e) {throw new ServiceException(e.getMessage());}SysOssExt ext1 = new SysOssExt();ext1.setFileSize(file.getSize());ext1.setContentType(file.getContentType());// 保存文件信息return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult, ext1);} 
 /*** 上传 byte[] 数据到 Amazon S3,使用指定的后缀构造对象键。** @param data   要上传的 byte[] 数据* @param suffix 对象键的后缀* @return UploadResult 包含上传后的文件信息* @throws OssException 如果上传失败,抛出自定义异常*/public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), contentType);}
 
public static final String SLASH = "/";/*** 上传 InputStream 到 Amazon S3** @param inputStream 要上传的输入流* @param key         在 Amazon S3 中的对象键* @param length      输入流的长度* @param contentType 文件内容类型* @return UploadResult 包含上传后的文件信息* @throws OssException 如果上传失败,抛出自定义异常*/public UploadResult upload(InputStream inputStream, String key, Long length, String contentType) {// 如果输入流不是 ByteArrayInputStream,则将其读取为字节数组再创建 ByteArrayInputStreamif (!(inputStream instanceof ByteArrayInputStream)) {inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));}try {// 创建异步请求体(length如果为空会报错)BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder().contentLength(length).subscribeTimeout(Duration.ofSeconds(120)).build();// 使用 transferManager 进行上传Upload upload = transferManager.upload(x -> x.requestBody(body).addTransferListener(LoggingTransferListener.create()).putObjectRequest(y -> y.bucket(properties.getBucketName()).key(key).contentType(contentType)// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)//.acl(getAccessPolicy().getObjectCannedACL()).build()).build());// 将输入流写入请求体body.writeInputStream(inputStream);// 等待文件上传操作完成CompletedUpload uploadResult = upload.completionFuture().join();String eTag = uploadResult.response().eTag();// 提取上传结果中的 ETag,并构建一个自定义的 UploadResult 对象return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build();} catch (Exception e) {throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]");}} 
@NotNullprivate SysOssVo buildResultEntity(String originalfileName, String suffix, String configKey, UploadResult uploadResult, SysOssExt ext1) {SysOss oss = new SysOss();oss.setUrl(uploadResult.getUrl());oss.setFileSuffix(suffix);oss.setFileName(uploadResult.getFilename());oss.setOriginalName(originalfileName);oss.setService(configKey);oss.setExt1(JsonUtils.toJsonString(ext1));baseMapper.insert(oss);SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class);return this.matchingUrl(sysOssVo);} 
package org.dromara.common.oss.factory;import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.oss.constant.OssConstant;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.properties.OssProperties;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.redis.utils.RedisUtils;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;/*** 文件上传Factory** @author ZZW*/
@Slf4j
public class OssFactory {/*** 全局 redis key (业务无关的key)*/String GLOBAL_REDIS_KEY = "global:";/*** 默认配置KEY*/String DEFAULT_CONFIG_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss:default_config";private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>();private static final ReentrantLock LOCK = new ReentrantLock();/*** 获取默认实例*/public static OssClient instance() {// 获取redis 默认类型String configKey = RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY);if (StringUtils.isEmpty(configKey)) {throw new OssException("文件存储服务类型无法找到!");}return instance(configKey);}/*** 根据类型获取实例*/public static OssClient instance(String configKey) {String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);if (json == null) {throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");}OssProperties properties = JsonUtils.parseObject(json, OssProperties.class);// 使用租户标识避免多个租户相同key实例覆盖String key = configKey;if (StringUtils.isNotBlank(properties.getTenantId())) {key = properties.getTenantId() + ":" + configKey;}OssClient client = CLIENT_CACHE.get(key);// 客户端不存在或配置不相同则重新构建if (client == null || !client.checkPropertiesSame(properties)) {LOCK.lock();try {client = CLIENT_CACHE.get(key);if (client == null || !client.checkPropertiesSame(properties)) {CLIENT_CACHE.put(key, new OssClient(configKey, properties));log.info("创建OSS实例 key => {}", configKey);return CLIENT_CACHE.get(key);}} finally {LOCK.unlock();}}return client;}} 
@Overridepublic void init() {List<SysOssConfig> list = baseMapper.selectList();// 加载OSS初始化配置for (SysOssConfig config : list) {String configKey = config.getConfigKey();if ("0".equals(config.getStatus())) {RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey);}CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));}}
 
package org.dromara.common.oss.constant;import org.dromara.common.core.constant.GlobalConstants;import java.util.Arrays;
import java.util.List;/*** 对象存储常量** @author ZZW*/
public interface OssConstant {/*** 默认配置KEY*/String DEFAULT_CONFIG_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss:default_config";/*** 预览列表资源开关Key*/String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource";/*** 系统数据ids*/List<Long> SYSTEM_DATA_IDS = Arrays.asList(1L, 2L, 3L, 4L);/*** 云服务商*/String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"};/*** https 状态*/String IS_HTTPS = "Y";} 
