Java Springboot使用阿里云oss对图片进行等质量压缩,转换成webp格式的压缩图。

一、需求

使用阿里云oss对图片进行等质量压缩,转换成webp格式的压缩图。

二、引入依赖

xml 复制代码
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <optional>true</optional>
</dependency>

<dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>fastjson</artifactId>
 <version>1.2.83</version>
</dependency>
<dependency>
 <groupId>com.aliyun.oss</groupId>
 <artifactId>aliyun-sdk-oss</artifactId>
 <version>3.9.1</version>
</dependency>

三、配置文件

yaml 复制代码
spring:
  application:
    name: infra-server
  # Servlet 配置
  servlet:
    # 文件上传相关配置项
    multipart:
      max-file-size: 200MB # 单个文件大小
      max-request-size: 200MB # 设置总上传的文件大小
server:
  port: 8081

# 阿里云OSS配置
aliyun:
  oss:
    endpoint: oss-cn-beijing.aliyuncs.com    # 例如:oss-cn-hangzhou.aliyuncs.com
    accessKeyId: KJSDH5tRKWIJHSBhc8WKKB17PO
    accessKeySecret: ri7KJSDH5tRKISJH87hc8WKKB17POxD
    bucketName: oss-prod
    cyjBucketName: oss-bigdata-cyj-prod
    directory: dir
    apkBucketName: oss-prod-apk
    apkEndpoint: prod.oss.com
    domain: https://oss-prod.oss-cn-beijing.aliyuncs.com  # OSS访问域名
    original-image: original_image/ # 原始图片
    thumbnail-image: thumbnail_image/ # 缩略图
    webp-quality: 90 #质量分

四、文件相关实体类

1、系统文件关联实体类

java 复制代码
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 系统文件关联实体类
 */
@Data
public class SysFileRelationVo implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 文件关联ID
     */
    private String id;

    /**
     * 文件名称
     */
    private String fileName;
    /**
     * 文件ID
     */
    private String fileId;

    /**
     * 文件路径
     */
    private String filePath;
    /**
     *关联文件ID
     */
    private String relatedFileId;
    /**
     *关联类型
     */
    private String relationType;

    /**
     * 文件大小(字节)
     */
    private Long fileSize;

    /**
     *关联名称
     */
    private String relationName;
    /**
     *关联描述
     */
    private String description;

    /**
     * 文件类型
     */
    private String fileType;
    /**
     * 文件类型
     */
    private String mimeType;

    /**
     * OSS文件ID
     */
    private String ossFileId;

    /**
     * 业务类型
     */
    private String businessType;

    /**
     * 业务ID
     */
    private String businessId;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 创建人
     */
    private String createBy;

    /**
     * 更新人
     */
    private String updateBy;
    /**
     * 文件路径
     */
    private String ossPath;
    /**
     * 状态:0-禁用,1-启用
     */
    private Integer status;

    private String avatarUrl;
} 

2、批量获取文件实体类

java 复制代码
import lombok.Data;

@Data
public class FileBatchUrlsVO {

    private String id;

    private String url;

}

3、上传文件并压缩实体类

java 复制代码
import lombok.Data;

@Data
public class OssFileRespVO {

    private String originalUrl;
    private String originalPath;

    private String thumbnailUrl;
    private String thumbnailPath;
    private String originalFilename;
    private String thumbnailFilename;
}

五、工具类

java 复制代码
import com.alibaba.fastjson.JSON;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.ResponseMessage;
import com.aliyun.oss.model.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * OSS工具类
 */
@Slf4j
@Data
@Component
@RefreshScope
public class OssUtil {

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    @Value("${aliyun.oss.cyjBucketName}")
    private String cyjBucketName;
    @Value("${aliyun.oss.directory}")
    private String directory;

    @Value("${aliyun.oss.apkBucketName}")
    private String apkBucketName;

    @Value("${aliyun.oss.apkEndpoint}")
    private String apkEndpoint;

    @Value("${aliyun.oss.original-image}")
    private String originalImage;

    @Value("${aliyun.oss.thumbnail-image}")
    private String thumbnailImage;

    @Value("${aliyun.oss.domain}")
    private String domain;

    @Value("${aliyun.oss.webp-quality:92}")
    private int webpQuality;

    private static final int THREAD_POOL_SIZE = 10; // 线程池大小
    private static final long URL_EXPIRE_TIME = 3600 * 1000; // 签名URL有效期(毫秒)

    /**
     * 上传文件
     *
     * @param file 文件
     * @param dir  目录
     * @return OSS路径
     */
    public String upload(MultipartFile file, String dir) {
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
        String objectName = dir + "/" + fileName;

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            InputStream inputStream = file.getInputStream();
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            metadata.setContentLength(file.getSize());
            ossClient.putObject(bucketName, objectName, inputStream, metadata);
            return objectName;
        } catch (IOException e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传文件失败");
        } finally {
            ossClient.shutdown();
        }
    }

    public String uploadByBase64(byte[] bytes, String bucketName, String dir, String originalFilename) {
        String suffix = ".png";
        String fileName = StringUtils.isBlank(originalFilename) ? UUID.randomUUID().toString().replace("-", "") + suffix : originalFilename + suffix;
        String objectName = dir + "/" + fileName;

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 转换为InputStream
            InputStream inputStream = new ByteArrayInputStream(bytes);
            ObjectMetadata metadata = new ObjectMetadata();
            // 这里假设所有文件都有标准的Content-Type,如果需要更精确控制可以增加参数
            metadata.setContentType("application/octet-stream");
            metadata.setContentLength(bytes.length);
            ossClient.putObject(bucketName, objectName, inputStream, metadata);
            return objectName;
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传文件失败");
        } finally {
            ossClient.shutdown();
        }
    }

    public String uploadByBase64(byte[] bytes, String dir) {
        return uploadByBase64(bytes, bucketName, dir, null);
    }

    /**
     * 获取文件URL
     *
     * @param objectName 对象名称
     * @param expiration 过期时间(秒)
     * @return 文件URL
     */
    public String getFileUrl(String objectName, long expiration) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            Date expireDate = new Date(System.currentTimeMillis() + expiration * 1000);
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
            request.setExpiration(expireDate);
            URL url = ossClient.generatePresignedUrl(request);
            return url.toString();
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 删除文件
     *
     * @param objectName 对象名称
     */
    public void deleteFile(String objectName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.deleteObject(bucketName, objectName);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 从OSS下载文件到本地
     *
     * @param objectName OSS对象名称
     * @param localFilePath 本地文件保存路径
     * @return 是否下载成功
     */
   /* public boolean downloadFile(String objectName, String localFilePath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.getObject(bucketName, objectName, new java.io.File(localFilePath));
            return true;
        } catch (Exception e) {
            log.error("从OSS下载文件失败: {}", e.getMessage(), e);
            return false;
        } finally {
            ossClient.shutdown();
        }
    }*/

    /**
     * 获取OSS文件的输入流
     *
     * @param objectName OSS对象名称
     * @return 文件输入流,如果获取失败则返回null
     */
    public InputStream getFileInputStream(String objectName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            return ossClient.getObject(bucketName, objectName).getObjectContent();
        } catch (Exception e) {
            log.error("获取OSS文件输入流失败: {}", e.getMessage(), e);
            return null;
        }
        // 注意:这里不关闭ossClient,因为关闭后输入流也会被关闭
        // 调用方需要负责在使用完输入流后关闭它,并调用ossClient.shutdown()
    }

    /**
     * 获取OSS文件的字节数组
     *
     * @param objectName OSS对象名称
     * @return 文件字节数组,如果获取失败则返回null
     */
    public byte[] getFileBytes(String objectName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        InputStream inputStream = null;
        try {
            inputStream = ossClient.getObject(bucketName, objectName).getObjectContent();
            return inputStream.readAllBytes();
        } catch (Exception e) {
            log.error("获取OSS文件字节数组失败: {}", e.getMessage(), e);
            return null;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                log.error("关闭输入流失败", e);
            }
            ossClient.shutdown();
        }
    }

    /**
     * 将OSS文件转换为MultipartFile对象
     *
     * @param objectName OSS对象名称
     * @return MultipartFile对象,如果获取失败则返回null
     */
    public MultipartFile getOssFileAsMultipartFile(String objectName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 获取文件元数据
            ObjectMetadata metadata = ossClient.getObjectMetadata(bucketName, objectName);
            // 获取文件内容
            byte[] content = getFileBytes(objectName);
            if (content == null) {
                return null;
            }

            // 获取文件名(从objectName中提取)
            String fileName = objectName;
            if (objectName.contains("/")) {
                fileName = objectName.substring(objectName.lastIndexOf("/") + 1);
            }

            // 创建自定义的MultipartFile实现
            String finalFileName = fileName;
            return new MultipartFile() {
                @Override
                public String getName() {
                    return "file";
                }

                @Override
                public String getOriginalFilename() {
                    return finalFileName;
                }

                @Override
                public String getContentType() {
                    return metadata.getContentType();
                }

                @Override
                public boolean isEmpty() {
                    return content.length == 0;
                }

                @Override
                public long getSize() {
                    return content.length;
                }

                @Override
                public byte[] getBytes() throws IOException {
                    return content;
                }

                @Override
                public InputStream getInputStream() throws IOException {
                    return new ByteArrayInputStream(content);
                }

                @Override
                public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
                    try (java.io.FileOutputStream fos = new java.io.FileOutputStream(dest)) {
                        fos.write(content);
                    }
                }
            };
        } catch (Exception e) {
            log.error("将OSS文件转换为MultipartFile失败: {}", e.getMessage(), e);
            return null;
        } finally {
            ossClient.shutdown();
        }
    }


    /**
     * 将文字内容上传到 OSS
     *
     * @param text 要上传的文字内容
     */
    public String uploadTextToOSS(String text, String dir, String fileName) {
        // 创建 OSSClient 实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String objectName = dir + "/" + fileName;
        try {
            // 将文字内容转换为字节数组输入流
            ByteArrayInputStream inputStream = new ByteArrayInputStream(text.getBytes());

            // 创建 PutObjectRequest 对象
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 上传文件
            ossClient.putObject(putObjectRequest);
            System.out.println("文字内容已成功上传到 OSS。");
            return objectName;
        } catch (Exception e) {
            throw new RuntimeException("上传过程中出现错误: " + e.getMessage());
        } finally {
            // 关闭 OSSClient
            ossClient.shutdown();
        }
    }

    /**
     * 将文字内容以 Word 文件形式上传到 OSS
     *
     * @param text 要上传的文字内容
     * @throws IOException 可能的 IO 异常
     */
    public String uploadTextAsWordToOSS(String text, String dir, String fileName) {

        // 创建 OSSClient 实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 创建 Word 文档
            XWPFDocument document = new XWPFDocument();
            XWPFParagraph paragraph = document.createParagraph();
            XWPFRun run = paragraph.createRun();
            run.setText(text);

            // 将文档内容写入字节数组输出流
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.write(outputStream);
            byte[] wordBytes = outputStream.toByteArray();


            String objectName = dir + "/" + fileName;
            // 将字节数组转换为字节数组输入流
            ByteArrayInputStream inputStream = new ByteArrayInputStream(wordBytes);

            // 创建 PutObjectRequest 对象
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);

            // 上传文件
            ossClient.putObject(putObjectRequest);
            System.out.println("文字内容已成功以 Word 文件形式上传到 OSS。");
            return objectName;
        } catch (Exception e) {
            throw new RuntimeException("上传过程中出现错误: " + e.getMessage());
        } finally {
            // 关闭 OSSClient
            ossClient.shutdown();
        }
    }

    public String uploadRichTextToOSS(String richText, String dir, String fileName) throws IOException, InvalidFormatException {
        // 创建 Word 文档
        XWPFDocument document = new XWPFDocument();

        // 解析富文本
        Document htmlDoc = Jsoup.parse(richText);
        Elements elements = htmlDoc.body().children();
        for (Element element : elements) {
            if (element.tagName().equals("p")) {
                // 处理段落文本
                String text = element.text();
                XWPFParagraph paragraph = document.createParagraph();
                XWPFRun run = paragraph.createRun();
                run.setText(text);
            } else if (element.tagName().equals("img")) {
                // 处理图片
                String imgUrl = element.attr("src");
                addImageToDocument(document, imgUrl);
            }
        }

        // 将文档内容写入字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        document.write(outputStream);
        byte[] wordBytes = outputStream.toByteArray();

        // 创建 OSSClient 实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String objectName = dir + "/" + fileName;
        try {
            // 将字节数组转换为字节数组输入流
            ByteArrayInputStream inputStream = new ByteArrayInputStream(wordBytes);

            // 创建 PutObjectRequest 对象
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);

            // 上传文件
            ossClient.putObject(putObjectRequest);
            return objectName;
        } catch (Exception e) {
            throw new RuntimeException("上传过程中出现错误: " + e.getMessage());
        } finally {
            // 关闭 OSSClient
            ossClient.shutdown();
        }
    }

    private static void addImageToDocument(XWPFDocument document, String imgUrl) throws IOException, InvalidFormatException {
        URL url = new URL(imgUrl);
        InputStream inputStream = url.openStream();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        byte[] imageBytes = outputStream.toByteArray();

        XWPFParagraph paragraph = document.createParagraph();
        XWPFRun run = paragraph.createRun();
        int format = getImageFormat(imgUrl);
        run.addPicture(new ByteArrayInputStream(imageBytes), format, "image", Units.toEMU(200), Units.toEMU(200));
    }

    private static int getImageFormat(String imgUrl) {
        if (imgUrl.endsWith(".png")) {
//            return Document.PICTURE_TYPE_PNG;
            return 1;
        } else if (imgUrl.endsWith(".jpg") || imgUrl.endsWith(".jpeg")) {
//            return Document.PICTURE_TYPE_JPEG;
            return 2;
        }
//        return Document.PICTURE_TYPE_PNG;
        return 1;
    }

    /**
     * 多线程并发生成URL
     */
    public Map<String, String> generateUrlsMultiThread(List<String> fileIds) {
        Map<String, String> urlMap = new ConcurrentHashMap<>();
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        List<Future<Map<String, String>>> futures = new ArrayList<>();

        // 分割任务
        int batchSize = 100;
        for (int i = 0; i < fileIds.size(); i += batchSize) {
            List<String> batch = fileIds.subList(i, Math.min(i + batchSize, fileIds.size()));
            futures.add(executor.submit(() -> {
                OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
                Map<String, String> batchUrls = new HashMap<>();
                try {
                    for (String fileId : batch) {
                        batchUrls.put(fileId, generateSignedUrl(ossClient, fileId));
                    }
                } finally {
                    ossClient.shutdown();
                }
                return batchUrls;
            }));
        }

        // 收集结果
        for (Future<Map<String, String>> future : futures) {
            try {
                urlMap.putAll(future.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        executor.shutdown();
        return urlMap;
    }


    public List<FileBatchUrlsVO> getUrlsList(List<String> fileIds) {
        if (CollectionUtils.isEmpty(fileIds)) {
            return Collections.emptyList();

        }
        Map<String, String> stringStringMap = generateUrlsMultiThread(fileIds);
        if (null == stringStringMap || stringStringMap.isEmpty()) {
            return Collections.emptyList();
        }
        List<FileBatchUrlsVO> fileBatchUrlsVOS = new ArrayList<>();
        for (Map.Entry<String, String> entry : stringStringMap.entrySet()) {
            FileBatchUrlsVO vo = new FileBatchUrlsVO();
            vo.setId(entry.getKey());
            vo.setUrl(entry.getValue());
            fileBatchUrlsVOS.add(vo);
        }
        return fileBatchUrlsVOS;
    }

    /**
     * 生成单个签名URL
     */
    public String generateSignedUrl(OSS ossClient, String fileId) {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileId);
        request.setExpiration(new Date(System.currentTimeMillis() + URL_EXPIRE_TIME));
        URL url = ossClient.generatePresignedUrl(request);
        return url.toString();
    }

    /**
     * 获取公共读文件的访问URL
     */
    public String getPublicUrl(String ossFilePath) {
        return String.format("https://%s.%s/%s", bucketName, endpoint, ossFilePath);
    }

    /**
     * 批量获取公共读文件的访问URL
     */
    public List<FileBatchUrlsVO> getPublicUrlsList(List<String> fileIds) {
        if (CollectionUtils.isEmpty(fileIds)) {
            return Collections.emptyList();
        }
        List<FileBatchUrlsVO> fileBatchUrlsVOS = new ArrayList<>();
        for (String fileId : fileIds) {
            if (StringUtils.isBlank(fileId)) {
                continue;
            }
            String publicUrl = getPublicUrl(fileId);
            FileBatchUrlsVO vo = new FileBatchUrlsVO();
            vo.setId(fileId);
            vo.setUrl(publicUrl);
            fileBatchUrlsVOS.add(vo);
        }
        return fileBatchUrlsVOS;
    }

    /**
     * 从cyjBucketName桶的指定目录下获取任意一个PNG图片的访问地址
     *
     * @return PNG图片的访问URL地址,如果没有找到则返回null
     */
    public String getRandomPngFromCyjBucket() {
        String directoryPath = "photos/product/630内容数据_已全部移到此目录下/专属衣橱模块/海报大片图/";
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 列出目录下的所有文件
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(cyjBucketName);
            listObjectsRequest.setPrefix(directoryPath);

            ObjectListing objectListing = ossClient.listObjects(listObjectsRequest);
            List<OSSObjectSummary> objectSummaries = objectListing.getObjectSummaries();

            // 过滤出PNG文件
            List<String> pngFiles = new ArrayList<>();
            for (OSSObjectSummary objectSummary : objectSummaries) {
                String key = objectSummary.getKey();
                if (key.toLowerCase().endsWith(".png")) {
                    pngFiles.add(key);
                }
            }

            // 如果找到PNG文件,生成第一个文件的永久访问URL
            if (!pngFiles.isEmpty()) {
                String selectedPngFile = pngFiles.get(0);
                log.info("在目录 {} 下找到 {} 个PNG文件,返回第一个: {}", directoryPath, pngFiles.size(), selectedPngFile);

                // 生成永久访问URL
                String permanentUrl = String.format("https://%s.%s/%s", cyjBucketName, endpoint, selectedPngFile);
                return permanentUrl;
            }

            log.warn("在目录 {} 下未找到PNG文件", directoryPath);
            return null;

        } catch (Exception e) {
            log.error("获取PNG文件失败: {}", e.getMessage(), e);
            return null;
        } finally {
            ossClient.shutdown();
        }
    }


    /**
     * 上传文件
     *
     * @param file 文件
     * @param dir  目录
     * @return OSS路径
     */
    public String uploadApk(MultipartFile file, String dir) {
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
        String objectName = dir + "/" + fileName;
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        // 开启CNAME选项以支持自定义域名访问
        clientBuilderConfiguration.setSupportCname(true);
        OSS ossClient = new OSSClientBuilder().build("https://" + apkEndpoint, accessKeyId, accessKeySecret, clientBuilderConfiguration);

        try {
            InputStream inputStream = file.getInputStream();
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            metadata.setContentLength(file.getSize());
            log.info("上传文件的桶是: {}", apkBucketName);
            ossClient.putObject(apkBucketName, objectName, inputStream, metadata);
            return objectName;
        } catch (IOException e) {
            log.error("apk上传文件失败", e);
            throw new RuntimeException("上传文件失败");
        } finally {
            ossClient.shutdown();
        }
    }


    /**
     * 获取公共读文件的访问URL
     */
    public String getPublicUrlApk(String ossFilePath) {
        return String.format("https://%s/%s", apkEndpoint, ossFilePath);
    }


    /**
     * 将图片压缩并上传--保留了原始图片和压缩图片
     *
     * @param file 文件
     * @return OSS路径
     */
    public OssFileRespVO uploadImageZip(MultipartFile file) {
        // 1. 校验文件类型(同上)
        String originalFilename = file.getOriginalFilename();
        log.info("将图片压缩并上传开始 originalFilename={}", originalFilename);
        if (originalFilename == null || !originalFilename.matches(".*\\.(jpg|jpeg|png|gif|bmp|webp)$")) {
            throw new IllegalArgumentException("仅支持jpg、jpeg、png、gif、bmp、webp格式");
        }

        // 2. 生成存储路径(注意:路径中避免中文和特殊字符)
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String originalExt = getFileExt(originalFilename);
        String originalOssKey = originalImage + uuid + originalExt;
        String webpOssKey = thumbnailImage + uuid + ".webp";
        log.info("将图片压缩并上传路径 originalOssKey={} webpOssKey={}", originalOssKey, webpOssKey);
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        log.info("将图片压缩并上传初始化ossClient完成");
        // 3. 上传原始图片
        try (InputStream inputStream = file.getInputStream()) {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            PutObjectResult putObjectResult = ossClient.putObject(bucketName, originalOssKey, inputStream, metadata);
            log.info("将图片压缩并上传原始图片返回结果 putObjectResult={}", JSON.toJSONString(putObjectResult));
            ResponseMessage response = putObjectResult.getResponse();
            if (putObjectResult.getResponse().getStatusCode() != 200) {
                throw new RuntimeException("OSS上传原始图片失败");
            }
            // 4. 构造处理规则(关键:使用OSS专用Base64编码)
            // 格式:image/format,webp|sys/saveas,o_<Base64编码的目标路径>,b_<Base64编码的存储桶>
            String encodedKey = OSSBase64Utils.encode(webpOssKey); // 编码目标路径
            String encodedBucket = OSSBase64Utils.encode(bucketName); // 编码存储桶
            int quality = Math.min(100, Math.max(1, webpQuality));
            String processRule = String.format(
                    "image/quality,q_%d/format,webp|sys/saveas,o_%s,b_%s",
                    quality,
                    encodedKey,
                    encodedBucket
            );

            // 5. 执行处理
            ProcessObjectRequest processRequest = new ProcessObjectRequest(bucketName, originalOssKey, processRule);
            GenericResult result = ossClient.processObject(processRequest);
            log.info("将图片压缩并上传压缩图片返回结果 result={}", JSON.toJSONString(result));

            // 6. 验证处理成功
            if (result.getResponse().getStatusCode() != 200) {
                throw new RuntimeException("OSS生成WebP失败,状态码:" + result.getResponse().getStatusCode());
            }
            // 7. 返回WebP访问URL
            OssFileRespVO ossFileRespVO = new OssFileRespVO();
            ossFileRespVO.setOriginalUrl(domain + "/" + originalOssKey);
            ossFileRespVO.setThumbnailUrl(domain + "/" + webpOssKey);
            ossFileRespVO.setOriginalPath(originalOssKey);
            ossFileRespVO.setThumbnailPath(webpOssKey);

            log.info("将图片压缩并上传压返回结果 ossFileRespVO={}", JSON.toJSONString(ossFileRespVO));
            return ossFileRespVO;
        } catch (Exception e) {
            log.error("将图片压缩并上传失败", e);
            throw new RuntimeException("上传文件失败");
        } finally {
            ossClient.shutdown();
        }
    }

    private String getFileExt(String filename) {
        return filename.substring(filename.lastIndexOf("."));
    }

}

六、文件服务service接口

java 复制代码
import cn.iocoder.yudao.module.infra.controller.admin.vo.FileBatchUrlsVO;
import cn.iocoder.yudao.module.infra.controller.admin.vo.FileUploadReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.vo.OssFileRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.vo.SysFileRelationVo;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * 文件 Service 接口
 *
 * @author 芋道源码
 */
public interface OssFileService {

    /**
     * 上传文件--返回临时URL
     *
     * @param uploadReqVO
     * @return
     */
    SysFileRelationVo upload(FileUploadReqVO uploadReqVO);

    /**
     * 上传文件--返回永久URL
     *
     * @param uploadReqVO
     * @return
     */
    String uploadStr(FileUploadReqVO uploadReqVO);

    /**
     * 获取文件URL--临时
     *
     * @param fileName
     * @return
     */
    String getUrl(String fileName);

    /**
     * 批量获取文件URL--临时
     *
     * @param fileNames
     * @return
     */
    List<FileBatchUrlsVO> getUrls(List<String> fileNames);

    /**
     * 批量获取文件URL--永久
     *
     * @param fileNames
     * @return
     */
    List<FileBatchUrlsVO> getPermanentUrl(List<String> fileNames);

    /**
     * 上传文件--返回永久URL
     *
     * @param base64Str
     * @return
     */
    String uploadByBase64(String base64Str,String fileType);

    /**
     * 上传文件--返回永久URL
     *
     * @param base64Data base64 数据
     * @param bucketName 桶名称
     * @param dir 目录
     * @param fileType 文件类型
     * @return
     */
    String uploadByBase64(String base64Data,String bucketName, String dir,String fileName,String fileType);

    /**
     * 上传文件--返回永久URL
     *
     * @param uploadReqVO
     * @return
     */
    String uploadStrApk(FileUploadReqVO uploadReqVO);


    /**
     * 上传文件并压缩--返回永久URL
     *
     * @param uploadReqVO
     * @return
     */
    OssFileRespVO uploadZip(FileUploadReqVO uploadReqVO);


    /**
     * 上传文件并压缩--返回永久URL
     *
     * @param file
     * @return
     */
    String uploadZipFile(MultipartFile file);

    /**
     * 压缩图片并上传--调用oss--base64Data入参
     *
     * @param base64Data
     * @return
     */
    String uploadZipBase64Method(String base64Data, String fileType);

    /**
     * 压缩图片并上传--调用oss--base64Data入参
     *
     * @param base64Data
     * @return 返回png图片
     */
    String uploadZipBase64(String base64Data, String fileType);
}

七、文件服务service接口实现类

java 复制代码
import cn.hutool.core.io.IoUtil;
import cn.iocoder.yudao.framework.common.enums.ImageTypeEnum;
import cn.iocoder.yudao.module.infra.controller.admin.vo.FileBatchUrlsVO;
import cn.iocoder.yudao.module.infra.controller.admin.vo.FileUploadReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.vo.OssFileRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.vo.SysFileRelationVo;
import cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.infra.orm.entity.FileDO;
import cn.iocoder.yudao.module.infra.orm.mapper.FileMapper;
import cn.iocoder.yudao.module.infra.service.config.ConfigDataService;
import cn.iocoder.yudao.module.infra.utils.OSSBase64Utils;
import cn.iocoder.yudao.module.infra.utils.OssUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GenericResult;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.ProcessObjectRequest;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

/**
 * 文件 Service 实现类
 *
 * @author 芋道源码
 */
@Slf4j
@Service
@RefreshScope
public class OssFileServiceImpl implements OssFileService {

    @Resource
    private FileConfigService fileConfigService;

    @Resource
    private OssUtil ossUtil;
    @Resource
    private ConfigDataService configDataService;


    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    @Value("${aliyun.oss.original-image}")
    private String originalImage;

    @Value("${aliyun.oss.thumbnail-image}")
    private String thumbnailImage;

    @Value("${aliyun.oss.domain}")
    private String domain;

    /**
     * OSS 转 WebP 的相对质量(1-100),默认 92。未配置 quality 时 OSS 会使用较低默认值导致画质偏糊。
     */
    @Value("${aliyun.oss.webp-quality:92}")
    private int webpQuality;

    @Override
    @SneakyThrows
    public SysFileRelationVo upload(FileUploadReqVO uploadReqVO) {

        try {
            String originalFilename = uploadReqVO.getFile().getOriginalFilename();
            // 上传到OSS
            String ossPath = ossUtil.upload(uploadReqVO.getFile(), configDataService.getDirectory());

            String fileUrl = ossUtil.getFileUrl(ossPath, 24 * 60 * 60);
            MultipartFile file1 = uploadReqVO.getFile();
            String path = uploadReqVO.getPath();
            byte[] bytes = IoUtil.readBytes(file1.getInputStream());
            String type = FileTypeUtils.getMineType(bytes, originalFilename);
     
            SysFileRelationVo vo = new SysFileRelationVo();
            vo.setOssFileId(ossPath);
            vo.setAvatarUrl(fileUrl);
            return vo;
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传头像失败");
        }

    }

    @Override
    public String uploadByBase64(String base64Data, String bucketName, String dir, String fileName, String fileType) {
        try {
            if (base64Data.startsWith("data:")) {
                base64Data = base64Data.substring(base64Data.indexOf(",") + 1);
            }
            // 解码Base64
            byte[] decodedBytes = Base64.getDecoder().decode(base64Data);

            // 上传到OSS
            String ossPath = ossUtil.uploadByBase64(decodedBytes, bucketName, dir, fileName);

            String fileUrl = ossUtil.getPublicUrl(ossPath);
            String originalFilename = StringUtils.isBlank(fileName) ? UUID.randomUUID().toString().replace("-", "") + ".png" : fileName + ".png";
            String type = FileTypeUtils.getMineType(decodedBytes, originalFilename);
        
            return fileUrl;
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传头像失败");
        }

    }

    @Override
    public String uploadByBase64(String base64Data, String fileType) {
        return uploadByBase64(base64Data, configDataService.getBucketName(), configDataService.getDirectory(), null, fileType);
    }

    @Override
    public String uploadStr(FileUploadReqVO uploadReqVO) {
        String fileType = uploadReqVO.getType();
        ImageTypeEnum imageTypeEnum = ImageTypeEnum.valueOfCode(fileType);
        log.info("uploadStr上传文件,文件类型:{},文件名:{}, 路径:{}",
                imageTypeEnum == null ? "未知" : imageTypeEnum.getName(),
                uploadReqVO.getFile().getOriginalFilename(), uploadReqVO.getPath());
        try {
            String originalFilename = uploadReqVO.getFile().getOriginalFilename();
            // 上传到OSS
            String ossPath = ossUtil.upload(uploadReqVO.getFile(), configDataService.getDirectory());
            log.info("uploadStr上传文件ossPath:{}", ossPath);
            String fileUrl = ossUtil.getPublicUrl(ossPath);
            MultipartFile file1 = uploadReqVO.getFile();
            byte[] bytes = IoUtil.readBytes(file1.getInputStream());
            String type = FileTypeUtils.getMineType(bytes, originalFilename);
           
            return fileUrl;
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传头像失败");
        }

    }

    @Override
    public String getUrl(String fileName) {
        return ossUtil.getFileUrl(fileName, 24 * 60 * 60);
    }

    @Override
    public List<FileBatchUrlsVO> getUrls(List<String> fileNames) {
        return ossUtil.getUrlsList(fileNames);
    }

    @Override
    public List<FileBatchUrlsVO> getPermanentUrl(List<String> fileNames) {
        return ossUtil.getPublicUrlsList(fileNames);
    }


    @Override
    public String uploadStrApk(FileUploadReqVO uploadReqVO) {
        String fileType = uploadReqVO.getType();
        ImageTypeEnum imageTypeEnum = ImageTypeEnum.valueOfCode(fileType);
        log.info("uploadStr上传文件,文件类型:{},文件名:{}, 路径:{}",
                imageTypeEnum == null ? "未知" : imageTypeEnum.getName(),
                uploadReqVO.getFile().getOriginalFilename(), uploadReqVO.getPath());
        try {
            String originalFilename = uploadReqVO.getFile().getOriginalFilename();
            // 上传到OSS
            String ossPath = ossUtil.uploadApk(uploadReqVO.getFile(), configDataService.getDirectory());
            log.info("apk uploadStrApk上传文件ossPath:{}", ossPath);
            String fileUrl = ossUtil.getPublicUrlApk(ossPath);
            MultipartFile file1 = uploadReqVO.getFile();
            byte[] bytes = IoUtil.readBytes(file1.getInputStream());
            String type = FileTypeUtils.getMineType(bytes, originalFilename);
          
            return fileUrl;
        } catch (Exception e) {
            log.error("apk上传文件失败", e);
            throw new RuntimeException("上传头像失败");
        }

    }

    @Override
    public OssFileRespVO uploadZip(FileUploadReqVO uploadReqVO) {

        try {
            String originalFilename = uploadReqVO.getFile().getOriginalFilename();
            // 上传到OSS
            OssFileRespVO ossVO = uploadZipFileMethod(uploadReqVO.getFile());
//            String ossVO1 = uploadZipFile(uploadReqVO.getFile());
            byte[] bytes = IoUtil.readBytes(uploadReqVO.getFile().getInputStream());
            String type = FileTypeUtils.getMineType(bytes, originalFilename);
            OssFileRespVO vo = new OssFileRespVO();
            vo.setThumbnailUrl(ossVO.getThumbnailUrl());
            return vo;
        } catch (Exception e) {
            log.error("上传文件并压缩失败", e);
            throw new RuntimeException("上传文件并压缩失败");
        }
    }

    @Override
    public String uploadZipFile(MultipartFile file) {
        OssFileRespVO ossFileRespVO = uploadZipFileMethod(file);
        return ossFileRespVO.getThumbnailUrl();
    }


    /**
     * 压缩图片并上传--调用oss--入参MultipartFile
     *
     * @param file
     * @return
     */
    public OssFileRespVO uploadZipFileMethod(MultipartFile file) {
        // 1. 校验文件类型(同上)
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !originalFilename.toLowerCase().matches(".*\\.(jpg|jpeg|png|gif|bmp|webp)$")) {
            throw new IllegalArgumentException("仅支持jpg、jpeg、png、gif、bmp、webp格式");
        }

        // 2. 生成存储路径(注意:路径中避免中文和特殊字符)
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String originalExt = originalFilename.substring(originalFilename.lastIndexOf("."));
        String originalOssKey = originalImage + uuid + originalExt;
        String webpOssKey = thumbnailImage + uuid + ".webp";
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 3. 上传原始图片
        try (InputStream inputStream = file.getInputStream()) {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            ossClient.putObject(bucketName, originalOssKey, inputStream, metadata);

            // 4. 构造处理规则(关键:使用OSS专用Base64编码)
            // 格式:image/format,webp|sys/saveas,o_<Base64编码的目标路径>,b_<Base64编码的存储桶>
            String processRule = buildWebpSaveAsProcessRule(webpOssKey);

            // 5. 执行处理
            ProcessObjectRequest processRequest = new ProcessObjectRequest(bucketName, originalOssKey, processRule);
            GenericResult result = ossClient.processObject(processRequest);

            // 6. 验证处理成功
            if (result.getResponse().getStatusCode() != 200) {
                throw new RuntimeException("OSS生成WebP失败,状态码:" + result.getResponse().getStatusCode());
            }
            // 7. 返回WebP访问URL
            OssFileRespVO ossFileRespVO = new OssFileRespVO();
            ossFileRespVO.setOriginalUrl(domain + "/" + originalOssKey);
            ossFileRespVO.setThumbnailUrl(domain + "/" + webpOssKey);
            ossFileRespVO.setOriginalPath(originalOssKey);
            ossFileRespVO.setThumbnailPath(webpOssKey);
            return ossFileRespVO;
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException("上传文件失败");
        } finally {
            ossClient.shutdown();
        }
    }



    /**
     * 压缩图片并上传--调用oss--base64Data入参
     *
     * @param base64Data
     * @return
     */
    @Override
    public String uploadZipBase64Method(String base64Data, String fileType) {
        OssFileRespVO ossFileRespVO = uploadBase64AndConvertToWebp(base64Data, fileType);
        return ossFileRespVO.getThumbnailUrl();
    }

    public String uploadZipBase64(String base64Data, String fileType) {
        OssFileRespVO ossFileRespVO = uploadBase64AndConvertToWebp(base64Data, fileType);
        log.info("=======返回图片地址是:{}======", ossFileRespVO.getOriginalUrl());
        return ossFileRespVO.getOriginalUrl();
    }

    /**
     * Base64 上传原图并由 OSS 转 WebP(带质量参数)
     */
    private OssFileRespVO uploadBase64AndConvertToWebp(String base64Data, String fileType) {
        ParsedBase64Image parsed = parseBase64Image(base64Data);
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String originalOssKey = originalImage + uuid + parsed.extension;
        String webpOssKey = thumbnailImage + uuid + ".webp";
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try (InputStream inputStream = new ByteArrayInputStream(parsed.bytes)) {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(parsed.contentType);
            ossClient.putObject(bucketName, originalOssKey, inputStream, metadata);

            String processRule = buildWebpSaveAsProcessRule(webpOssKey);
            ProcessObjectRequest processRequest = new ProcessObjectRequest(bucketName, originalOssKey, processRule);
            GenericResult result = ossClient.processObject(processRequest);
            if (result.getResponse().getStatusCode() != 200) {
                throw new RuntimeException("base64DataOSS生成WebP失败,状态码:" + result.getResponse().getStatusCode());
            }

            OssFileRespVO ossFileRespVO = new OssFileRespVO();
            ossFileRespVO.setOriginalUrl(domain + "/" + originalOssKey);
            ossFileRespVO.setThumbnailUrl(domain + "/" + webpOssKey);
            ossFileRespVO.setOriginalPath(originalOssKey);
            ossFileRespVO.setThumbnailPath(webpOssKey);
            ossFileRespVO.setOriginalFilename(originalOssKey);
            ossFileRespVO.setThumbnailFilename(webpOssKey);
            return ossFileRespVO;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            log.error("base64Data上传文件失败", e);
            throw new RuntimeException("base64Data上传文件失败");
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * OSS 持久化转 WebP:先 quality 再 format(阿里云建议格式转换靠后)
     */
    private String buildWebpSaveAsProcessRule(String webpOssKey) {
        int quality = Math.min(100, Math.max(1, webpQuality));
        String encodedKey = OSSBase64Utils.encode(webpOssKey);
        String encodedBucket = OSSBase64Utils.encode(bucketName);
        return String.format("image/quality,q_%d/format,webp|sys/saveas,o_%s,b_%s", quality, encodedKey, encodedBucket);
    }

    private ParsedBase64Image parseBase64Image(String base64Data) {
        String contentType = null;
        String payload = base64Data;
        if (base64Data.startsWith("data:")) {
            int comma = base64Data.indexOf(',');
            if (comma < 0) {
                throw new IllegalArgumentException("Base64 Data URL 格式非法");
            }
            String meta = base64Data.substring(5, comma);
            int semi = meta.indexOf(';');
            contentType = semi >= 0 ? meta.substring(0, semi) : meta;
            payload = base64Data.substring(comma + 1);
        }
        byte[] bytes = Base64.getDecoder().decode(payload);
        if (StrUtil.isBlank(contentType)) {
            contentType = FileTypeUtils.getMineType(bytes);
        }
        String extension = extensionFromContentType(contentType);
        return new ParsedBase64Image(bytes, contentType, extension);
    }

    private static String extensionFromContentType(String contentType) {
        if (contentType == null) {
            return ".jpg";
        }
        return switch (contentType) {
            case "image/jpeg", "image/jpg" -> ".jpg";
            case "image/png" -> ".png";
            case "image/gif" -> ".gif";
            case "image/bmp" -> ".bmp";
            case "image/webp" -> ".webp";
            default -> ".jpg";
        };
    }

    private static final class ParsedBase64Image {
        private final byte[] bytes;
        private final String contentType;
        private final String extension;

        private ParsedBase64Image(byte[] bytes, String contentType, String extension) {
            this.bytes = bytes;
            this.contentType = contentType;
            this.extension = extension;
        }
    }

}

八、Controller层

Java 复制代码
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.encrypt.core.annotation.ApiEncrypt;
import cn.iocoder.yudao.module.infra.controller.admin.vo.*;
import cn.iocoder.yudao.module.infra.service.file.OssFileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "管理后台 - OSS文件存储")
@RestController
@RequestMapping("/infra/oss")
@Validated
@Slf4j
public class OssFileController {


    @Resource
    private OssFileService ossFileService;

    @Value("${spring.servlet.multipart.max-file-size:200MB}")
    private String maxFileSize;

    @PostMapping("/upload")
    @Operation(summary = "上传文件--返回永久URL")
    @ApiEncrypt(request = false, response = false)
    public CommonResult<String> uploadFile(FileUploadReqVO uploadReqVO) {
        long size = uploadReqVO.getFile().getSize();
        //文件大小不能超过maxFileSize
        if(size > Long.parseLong(maxFileSize.replaceAll("MB", "")) * 1024 * 1024){
            return error(400, "文件大小不能超过" + maxFileSize);
        }
        String upload = ossFileService.uploadStr(uploadReqVO);
        return success(upload);
    }

//    @PostMapping("/uploadByDTO")
//    @Operation(summary = "上传文件--返回永久URL")
//    public CommonResult<String> uploadByDTO(MultipartFile file) {
//        FileUploadReqVO fileUploadReqVO = new FileUploadReqVO();
//        fileUploadReqVO.setFile(file);
//        String upload = ossFileService.uploadStr(fileUploadReqVO);
//        return success(upload);
//    }

    @PostMapping("/upload-obj")
    @Operation(summary = "上传文件--返回临时URL")
    public CommonResult<SysFileRelationVo> uploadFileObj(FileUploadReqVO uploadReqVO) {
        SysFileRelationVo upload = ossFileService.upload(uploadReqVO);
        return success(upload);
    }

    @GetMapping("/url")
    @Operation(summary = "获取文件URL--临时")
    public CommonResult<String> getUrl(String file) {
        String url = ossFileService.getUrl(file);
        return success(url);
    }

    @PostMapping("/urls")
    @Operation(summary = "批量获取文件URL--临时")
    public CommonResult<List<FileBatchUrlsVO>> getUrls(@RequestBody List<String> fileNames) {
        List<FileBatchUrlsVO> urls = ossFileService.getUrls(fileNames);
        return success(urls);
    }

    @PostMapping("/urls-permanent")
    @Operation(summary = "批量获取文件URL--永久")
    public CommonResult<List<FileBatchUrlsVO>> getPermanentUrl(@RequestBody List<String> fileNames) {
        List<FileBatchUrlsVO> urls = ossFileService.getPermanentUrl(fileNames);
        return success(urls);
    }

    @PostMapping("/upload/file")
    @Operation(summary = "上传文件file--返回永久URL")
    public CommonResult<String> uploadFile(@RequestPart("file") MultipartFile file) {
        FileUploadReqVO vo = new FileUploadReqVO();
        vo.setFile(file);
        vo.setPath(file.getOriginalFilename());
        String upload = ossFileService.uploadStr(vo);
        return success(upload);
    }


    @PostMapping("/uploadWxProfilePicture")
    @Operation(summary = "微信上传头像文件--返回永久URL")
    @PermitAll
    public CommonResult<String> uploadWxProfilePicture(FileUploadReqVO uploadReqVO) {
        String upload = ossFileService.uploadStr(uploadReqVO);
        return success(upload);
    }



    @PostMapping("/uploadApk")
    @Operation(summary = "上传apk文件--返回永久URL")
    @ApiEncrypt(request = false, response = false)
    public CommonResult<String> uploadFileApk(FileUploadReqVO uploadReqVO) {
        long size = uploadReqVO.getFile().getSize();
        //文件大小不能超过maxFileSize
        if(size > Long.parseLong(maxFileSize.replaceAll("MB", "")) * 1024 * 1024){
            return error(400, "文件大小不能超过" + maxFileSize);
        }
        String upload = ossFileService.uploadStrApk(uploadReqVO);
        return success(upload);
    }


    @PostMapping("/upload/zip")
    @Operation(summary = "上传文件并压缩--返回永久URL")
    @ApiEncrypt(request = false, response = false)
    public CommonResult<String> uploadFileZip(FileUploadReqVO uploadReqVO) {
        long size = uploadReqVO.getFile().getSize();
        //文件大小不能超过maxFileSize
        if(size > Long.parseLong(maxFileSize.replaceAll("MB", "")) * 1024 * 1024){
            return error(500, "文件大小不能超过" + maxFileSize);
        }
        OssFileRespVO ossFileRespVO = ossFileService.uploadZip(uploadReqVO);
        return success(ossFileRespVO.getThumbnailUrl());
    }


    @PostMapping("/upload/zip1")
    @Operation(summary = "上传文件并压缩--返回永久URL")
    @ApiEncrypt(request = false, response = false)
    public CommonResult<String> uploadFileZip(@RequestParam("file") MultipartFile file) {
        long size = file.getSize();
        //文件大小不能超过maxFileSize
        if(size > Long.parseLong(maxFileSize.replaceAll("MB", "")) * 1024 * 1024){
            return error(500, "文件大小不能超过" + maxFileSize);
        }
        String ossFileRespVO = ossFileService.uploadZipFile(file);
        return success(ossFileRespVO);
    }

    @GetMapping("/base64")
    @Operation(summary = "根据文字获取base64编码")
    public CommonResult<String> base64(String text) {
        // 编码水印内容
        String encodedContent = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8))
                .replace("+", "-").replace("/", "_").replace("=", "");
        return success(encodedContent);
    }


    @PostMapping("/getUrlWatermark")
    @Operation(summary = "getUrlWatermark:给王蔷")
    @PermitAll
    public String getUrlWatermark(@RequestBody GetUrlWatermarkReqVO getUrlWatermarkReqVO) {
        String result = ossFileService.uploadZipBase64Method(getUrlWatermarkReqVO.getBase64Data(), "getUrlWatermark");
        return result+"?x-oss-process=image/watermark,image_ZGlyLzczYTllMzk2M2YwMDQ0NTNiNjcyZTg2NTcwYmVjMzFiLnBuZw";
    }


}

九、 阿里云oss配置

1、去阿里云创建bucket

2、在bucket下创建original_image(原图)和 thumbnail_image(压缩图)两个目录

相关推荐
霸道流氓气质2 小时前
Spring Boot Multipart 表单中文乱码问题全解析
java·spring boot·后端
dadaobusi2 小时前
Linux内核完成大量内存/调度/时间子系统初始化的关键阶段
java·linux·前端
garmin Chen2 小时前
prompt实战:nof1.ai Alpha Arena
java·人工智能·python·prompt
RuoyiOffice2 小时前
从 0 到 1 搭建 RuoyiOffice:30 分钟跑通后端+前端+移动端
前端·spring boot·uni-app·开源·oa·ruoyioffice·hrm
霸道流氓气质2 小时前
Spring Boot 文件上传大小限制配置全解析
spring boot·后端·firefox
Java面试题总结2 小时前
SpringBoot API参数校验
java·spring boot·后端
武子康2 小时前
Java-24 深入浅出 Spring 全景:从起源到 Spring 6 一文打通 IoC / AOP / 发展史
java·后端·spring
asdfg12589632 小时前
通俗理解软件开发中前后端开发的架构模式(后端逻辑分层的“三层架构”和前端逻辑分层的“MVC 模式”)
java·架构模式
-Thinker2 小时前
【无标题】
java·开发语言·算法·图搜索