springboot上传图片到阿里云OSS同时进行压缩(使用thumbnailator)

首先导入thumbnailator包,关于这个的使用可以看别的博文。

pom文件引入:

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.10.2</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.8</version>
        </dependency>

然后写一个压缩的工具类:

import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 压缩工具类
 */
@Slf4j
public class CompressionUtil {
     

    /**
     * 压缩后的图片大小
     */
    private static final long AFTER_COMPRESSION_FILE_SIZE = 500L;

    /**方便通过文件流来给到thumbnailator的操作字节流
     * 传入stream然后转化为byte[]然后得到压缩后的数组
     */
    public static byte[] streamToBytesAndCompression(InputStream inputStream, Integer userId) throws IOException {
     
    	//使用的是org.apache.commons.io.IOUtils
        byte[] bytes = IOUtils.toByteArray(inputStream);
        //图片小于500kb
        bytes = compressPicForScale(bytes, AFTER_COMPRESSION_FILE_SIZE, userId.toString());
        return bytes;
    }

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小,单位kb
     * @param imageId     影像编号
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize, String imageId) {
     
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
     
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
     
            while (imageBytes.length > desFileSize * 1024) {
     
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                //图片压缩后的大小
                imageBytes = outputStream.toByteArray();
            }
            log.info("【图片压缩】imageId={} | 图片原大小={}kb | 压缩后大小={}kb",
                    imageId, srcSize / 1024, imageBytes.length / 1024);
        } catch (Exception e) {
     
            log.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
     
        double accuracy;
        if (size < 900) {
     
            accuracy = 0.85;
        } else if (size < 2047) {
     
            accuracy = 0.6;
        } else if (size < 3275) {
     
            accuracy = 0.44;
        } else {
     
            accuracy = 0.4;
        }
        return accuracy;
    }
}

写一个OSS上传的工具类

public class OOSUtil {
     
	/**
     * 按照byte数组传输图片
     *
     * @param dir       存放的目录名称
     * @param fileName  文件名称
     * @param byteArray 压缩后的byte数组
     * @return 图片链接
     */
    public static String addFileByByteArray(String dir, String fileName, byte[] byteArray) {
     
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
        //公共读
        metadata.setObjectAcl(CannedAccessControlList.PublicRead);
        metadata.setCacheControl("no-cache");
        metadata.setHeader("Pragma", "no-cache");
        metadata.setContentDisposition("inline;filename=" + fileName);
        metadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
        try {
     
            fileName = dir + "/" + fileName;
            ossClient.putObject(bucketName, fileName, new ByteArrayInputStream(byteArray), metadata);
        } catch (Exception e) {
     
            return null;
        } finally {
     
            ossClient.shutdown();
        }
        return "https://XXX-oos.XXX.XXX/" + fileName;//自己绑定OSS的域名
    }

	/**
     * 判断OSS服务文件上传时文件的类型contentType
     *
     * @param FilenameExtension 文件后缀
     * @return String
     */
    public static String getcontentType(String FilenameExtension) {
     
        if (".bmp".equalsIgnoreCase(FilenameExtension)) {
     
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(FilenameExtension)) {
     
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(FilenameExtension) ||
                ".jpg".equalsIgnoreCase(FilenameExtension)) {
     
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(FilenameExtension)) {
     
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(FilenameExtension)) {
     
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(FilenameExtension)) {
     
            return "application/vnd.visio";
        }
        if (".pptx".equalsIgnoreCase(FilenameExtension) ||
                ".ppt".equalsIgnoreCase(FilenameExtension)) {
     
            return "application/vnd.ms-powerpoint";
        }
        if (".docx".equalsIgnoreCase(FilenameExtension) ||
                ".doc".equalsIgnoreCase(FilenameExtension)) {
     
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(FilenameExtension)) {
     
            return "text/xml";
        }
        if (".png".equalsIgnoreCase(FilenameExtension)) {
     
            return "image/png";
        }
        return "image/jpg";
    }
}

自己写一个测试方法:

    @Test
    void testByteArrays() throws IOException {
     
        //1. 得到byte数组
        byte[] bytes = FileUtils.readFileToByteArray(new File("C:\\Users\\Lenovo\\Desktop\\earth.png"));
        long l = System.currentTimeMillis();
        String userId = "3";
        //2. 调用方法得到压缩后的byte数组
        bytes = CompressionUtil.compressPicForScale(bytes, 300, userId);// 图片小于300kb
        System.out.println("压缩花费时间为:"+(System.currentTimeMillis() - l));
        //TODO 注意文件的后缀
        //上传压缩后的数组
        String url = OOSUtil.addFileByByteArray("carry_head_portrait", userId + ".png", bytes);
        System.out.println(url);
//也可以用下面这两个方法
// byte[] bytes = CompressionUtil.streamToBytesAndCompression(inputStream, userId);
//url = OOSUtil.addFileByByteArray("carry_head_portrait", userId + suffix, bytes);    
    }

这样我们执行后在OSS控制台就可以看到结果了。

原来我的图片是4.13MB,压缩后是198.962KB,压缩的时间是2s多,说明压缩效果还是不错的。

你可能感兴趣的:(spring,boot,后端,spring,boot,阿里云)