阿里云OSS图片上传压缩

pom文件增加图片压缩依赖包

<!-- 图片压缩 -->
   <dependency>
        <groupId>net.coobird</groupId>
        <artifactId>thumbnailator</artifactId>
        <version>0.4.8</version>
    </dependency>
     <!-- 阿里云对象存储 -->
    <dependency>
         <groupId>com.aliyun.oss</groupId>
         <artifactId>aliyun-sdk-oss</artifactId>
         <version>2.8.3</version>
     </dependency>

 

 

增加图片上传工具类SysOSSUplodFile.java


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.img.Img;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhc.gds.common.core.constant.CommonConstants;
import com.zhc.gds.common.utils.ImageUtil;
import com.zhc.gds.common.utils.MagicalValueConstants;
import com.zhc.gds.common.utils.R;
import com.zhc.gds.entity.upms.SysFile;
import com.zhc.gds.mapper.upms.SysFileMapper;
import com.zhc.gds.service.upms.HttpSessionService;
import com.zhc.gds.service.upms.SysFileService;
import com.zhc.gds.service.upms.SysPublicParamService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 文件管理
*
* @author Luckly
* @date 2019-06-18 17:18:42
*/
@Slf4j
@Service
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> implements SysFileService {
/*阿里云oss上传文件方式*/

//你的oss所在域,要加http:// 不明白可以对照你的文件引用地址
@Value("${aliyun.oss.endpoint}")
private String endpoint;

//密匙keyId 可以在阿里云获取到
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;

//密匙keySecret 可以在阿里云获取到
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;

//你的bucketName存储桶 名称 即是你的OSS对象名称 不明白查oss开发文档专业术语
@Value("${aliyun.oss.bucketName}")
private String bucketName;

/*
* 以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
*/
private static final Integer ZERO = 0;
private static final Integer ONE_ZERO_TWO_FOUR = 1024;
private static final Integer NINE_ZERO_ZERO = 900;
private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
private static final Double ZERO_EIGHT_FIVE = 0.85;
private static final Double ZERO_SIX = 0.6;
private static final Double ZERO_FOUR_FOUR = 0.44;
private static final Double ZERO_FOUR = 0.4;
/**
* 上传文件
*
* @param file
* @return
*/
@Override
public R uploadFile(MultipartFile file) {
String fileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename());
String allName = this.getNowYearMonthDay() + "/" + fileName;

Map<String, String> resultMap = new HashMap<>(4);
resultMap.put("name", file.getOriginalFilename());
resultMap.put("bucketName", bucketName);
resultMap.put("fileName", allName);

//上传成功后获取文件路径
String previewUrl = publicParamService.getSysPublicParamKeyToValue("MINIO_IMAGE_PREVIEW_URL");

     resultMap.put("url", url);
// 写入文件
try {
//获取上传的输入流
InputStream inputStream = file.getInputStream();
//获取图片类型
String contentType = getContentType(fileName.substring(fileName.lastIndexOf(".")));

//设置访问地址是默认是预览图片
ObjectMetadata meta = new ObjectMetadata();
/**
* 下面两行代码是重点坑:
* 现在阿里云OSS 默认图片上传ContentType是image/jpeg
* 也就是说,获取图片链接后,图片是下载链接,而并非在线浏览链接,
* 因此,这里在上传的时候要解决ContentType的问题,将其改为image/jpg
*/

meta.setCacheControl("no-cache");
meta.setContentType(contentType);
meta.setHeader("Pragma", "no-cache");

// 创建OSSClient实例
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

/*
调用oss上传到阿里云对象存储oss----Bucket存储空间
第一个参数 bucket名称
第二个参数 文件名称
第三个参数 输入流
第四个参数 文件类型
*/
if (!ossClient.doesBucketExist(bucketName)) {
//创建bucket
ossClient.createBucket(bucketName);
//设置oss实例的访问权限:公共读
ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
}

//文件上传至阿里云

String extName = FileUtil.extName(file.getOriginalFilename());
if(StrUtil.isNotBlank(extName)){
extName = extName.toLowerCase();
}
if(extName.contains("gif") || extName.contains("jpg") || extName.contains("bmp")|| extName.contains("png")|| extName.contains("jpeg")){
byte[] bytes = file.getBytes();
//调用图片压缩方法,这里压缩到100k左右
bytes = compressPicForScale(bytes,100);
InputStream sbs = new ByteArrayInputStream(bytes);
meta.setContentLength(bytes.length);
ossClient.putObject(bucketName, allName, sbs, meta);

}else{
ossClient.putObject(bucketName, allName, inputStream, meta);
}

// 关闭OSSClient。
ossClient.shutdown();


// 文件管理数据记录,收集管理追踪文件
fileLog(file, resultMap.getOrDefault("url", fileName));
} catch (IOException e) {
log.error("上传失败", e);
return R.failed(e.getLocalizedMessage());
}

return R.ok(resultMap);
 } 



/**
* 根据指定大小压缩图片
*
* @param imageBytes 源图片字节数组
* @param desFileSize 指定图片大小,单位kb
* @return 压缩质量后的图片字节数组
*/
public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
return imageBytes;
}
long srcSize = imageBytes.length;
double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
try {
while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
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("图片原大小={}kb | 压缩后大小={}kb",
srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
} catch (Exception e) {
log.error("【图片压缩】msg=图片压缩失败!", e);
}
return imageBytes;
}

/**
* 自动调节精度(经验数值)
*
* @param size 源图片大小
* @return 图片压缩质量比
*/
private static double getAccuracy(long size) {
double accuracy;
if (size < NINE_ZERO_ZERO) {
accuracy = ZERO_EIGHT_FIVE;
} else if (size < TWO_ZERO_FOUR_SEVEN) {
accuracy = ZERO_SIX;
} else if (size < THREE_TWO_SEVEN_FIVE) {
accuracy = ZERO_FOUR_FOUR;
} else {
accuracy = ZERO_FOUR;
}
return accuracy;
}

    /**
* 通过文件名判断并获取OSS服务文件上传时文件的contentType
*
* @param filenameExtension 文件名
* @return 文件的contentType
*/
public static final String getContentType(String filenameExtension) {

if (filenameExtension.equalsIgnoreCase(".bmp")) {
return "application/x-bmp";
}
if (filenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (filenameExtension.equalsIgnoreCase(".jpeg") ||
filenameExtension.equalsIgnoreCase(".jpg") ||
filenameExtension.equalsIgnoreCase(".png")) {
return "image/jpg";
}
if (filenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (filenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (filenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (filenameExtension.equalsIgnoreCase(".pptx") ||
filenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (filenameExtension.equalsIgnoreCase(".docx") ||
filenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (filenameExtension.equalsIgnoreCase(".xla") ||
filenameExtension.equalsIgnoreCase(".xlc") ||
filenameExtension.equalsIgnoreCase(".xlm") ||
filenameExtension.equalsIgnoreCase(".xls") ||
filenameExtension.equalsIgnoreCase(".xlt") ||
filenameExtension.equalsIgnoreCase(".xlw")) {
return "application/vnd.ms-excel";
}
if (filenameExtension.equalsIgnoreCase(".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
if (filenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
if (filenameExtension.equalsIgnoreCase(".pdf")) {
return "application/pdf";
}
if (filenameExtension.equalsIgnoreCase(".zip")) {
return "application/zip";
}
if (filenameExtension.equalsIgnoreCase(".tar")) {
return "application/x-tar";
}
if (filenameExtension.equalsIgnoreCase(".avi")) {
return "video/avi";
}
if (filenameExtension.equalsIgnoreCase(".mp4")) {
return "video/mpeg4";
}
if (filenameExtension.equalsIgnoreCase(".mp3")) {
return "audio/mp3";
}
if (filenameExtension.equalsIgnoreCase(".mp2")) {
return "audio/mp2";
}
// 默认下载
// return "application/octet-stream";
return "image/jpg";
}
 
package com.zhc.gds.common.utils;

import cn.hutool.core.img.ImgUtil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.math.BigDecimal;

/**
* 图片相关工具类
*
* @author qqj
* @version V1.0
* @date 2022年8月3日
*/
public class ImageUtil {
/**
* 计算图片的大小,返回单位为KB
* @param imageBase64Str 图片base64数据
* @return 图片大小
*/
public static Integer imageSize(String imageBase64Str){

//1.找到等号,把等号也去掉(=用来填充base64字符串长度用)
Integer equalIndex= imageBase64Str.indexOf("=");
if(imageBase64Str.indexOf("=")>0) {
imageBase64Str=imageBase64Str.substring(0, equalIndex);
}
//2.原来的字符流大小,单位为字节
Integer strLength=imageBase64Str.length();
System.out.println("imageBase64Str Length = "+strLength);
//3.计算后得到的文件流大小,单位为字节
Integer size=strLength-(strLength/8)*2;
return bytesToKB(size);
}

/**
* byte(字节)根据长度转成kb(千字节)
* @param bytes
* @return
*/
public static Integer bytesToKB(long bytes) {
BigDecimal filesize = new BigDecimal(bytes);
BigDecimal megabyte = new BigDecimal(1024 * 1024);
BigDecimal kilobyte = new BigDecimal(1024);
float returnValue = filesize.divide(kilobyte, 1, BigDecimal.ROUND_DOWN).floatValue();
return (int)returnValue ;
}

/**
* 根据图片的base64数据缩放图片
* @param base64ImagStr 原图的base64字符换
* @param imageType 图片类型
* @return
*/
public static String scaleImage(String base64ImagStr,String imageType){
BufferedImage bufferedImage = ImgUtil.toImage(base64ImagStr);
// 这块也可以直接通过传入一个image对象,
Image scaleImage = ImgUtil.scale(bufferedImage, 0.2f);
String resultBase64Str = ImgUtil.toBase64(scaleImage, imageType);

Integer imageSizeBase64 = imageSize(resultBase64Str);
if(imageSizeBase64 > 40){
scaleImage(resultBase64Str,imageType);
}
return resultBase64Str;

}

/**
* 获取到200kb左右的压缩scale值
* 一一手动校验值(经验值)
*
* @param srcSize 文件长度
* @return scale
*/
public static float scale200K(long srcSize) {
float scale = 0f;
if (srcSize < 200 * 1000) {
scale = 1.00f;
} else if (srcSize < 500 * 1000) {
scale = 0.57f;
} else if (srcSize < 700 * 1000) {
scale = 0.47f;
} else if (srcSize < 1 * 1000 * 1000) {
scale = 0.37f;
} else if (srcSize < 2 * 1000 * 1000) {
scale = 0.25f;
} else if (srcSize < 4 * 1000 * 1000) {
scale = 0.17f;
} else if (srcSize < 5 * 1000 * 1000) {
scale = 0.13f;
} else if (srcSize < 10 * 1000 * 1000) {
scale = 0.10f;
} else {
scale = 0.01f;
}
return scale;
}

/**
* 获取到100kb左右的压缩scale值
* 一一手动校验值(经验值)
*0.21% 每0.1f
* @param srcSize 文件长度
* @return scale
* 0.1197
*/
private static float scale100K(long srcSize) {
float scale = 0f;
if (srcSize < 100 * 1000) {
scale = 1.00f;
} else if (srcSize < 300 * 1000) {
scale = 0.57f;
} else if (srcSize < 500 * 1000) {
scale = 0.47f;
} else if (srcSize < 700 * 1000) {
scale = 0.37f;
} else if (srcSize < 1 * 1000 * 1000) {
scale = 0.25f;
} else if (srcSize < 2 * 1000 * 1000) {
scale = 0.17f;
} else if (srcSize < 4 * 1000 * 1000) {
scale = 0.13f;
} else if (srcSize < 5 * 1000 * 1000) {
scale = 0.10f;
} else if (srcSize < 10 * 1000 * 1000) {
scale = 0.05f;
} else {
scale = 0.01f;
}
return scale;
}

}
posted @ 2022-12-08 15:17  全琪俊  阅读(2858)  评论(0编辑  收藏  举报