springboot集成腾讯云COS,实现文件上传、生成二维码、获取视频相关信息(封面、分辨率、大小等等)

1、maven 配置

        <!--腾讯COS-->
        <dependency>
            <groupId>com.qcloud</groupId>
            <artifactId>cos_api</artifactId>
            <version>5.6.38</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 视频处理:截取封面,获取视频信息等等 https://mvnrepository.com/artifact/org.bytedeco/javacv -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.3.1</version>
        </dependency>
    <!--制作缩略图-->
    <!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
    <dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.14</version>
    </dependency>
    
    <!--生成二维码-->
    <dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.0</version>
    </dependency>
    <dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.3.0</version>
    </dependency>

 2、application.yml 配置文件

cos:
  appId: xxxxxxxxxx
  secretId: xxxxxxxxxxxxxxxxxxxxxx
  secretKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
  # 存储桶名称
  bucketName: test-1305237141
  regionName: ap-chengdu
  # 存放主目录
  masterDirectory: dev/
  imgDirectory: img/
  videoDirectory: video/
  fileDirectory: file/

 3、代码

@Slf4j
public class FileServiceImpl implements IFileService {

    /**
     * 临时文件前缀
     */
    private static final String FILE_TEMP_PREFIX = "temp";

    /**
     * 返回URL分隔符
     */
    private static final String SEPARATIVE_SING = "?";

    /**
     * cos链接过期时间
     */
    private static final Long CLIENTCONFIG_EXPIRED = 120L;

    /**
     * 上传至COS过期时间
     */
    private static final Long FILE_EXPIRED = 3600L * 1000 * 24 * 365 * 20;

    /**
     * 获取视频封面的帧数
     */
    private static final int GET_FRAMES_LENGTH = 40;

    /**
    * 截取视频封面后缀
    */
    private static final String VIDEO_IMG_SUFFIX = "jpg";

    @Value("${cos.appId}")
    private String appId;

    @Value("${cos.secretId}")
    private String secretId;

    @Value("${cos.secretKey}")
    private String secretKey;

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

    @Value("${cos.regionName}")
    private String regionName;

    @Value("${cos.masterDirectory}")
    private String masterDirectory;

    @Value("${cos.imgDirectory}")
    private String imgDirectory;

    @Value("${cos.videoDirectory}")
    private String videoDirectory;

    @Value("${cos.fileDirectory}")
    private String fileDirectory;


    /**
     * 上传图片至腾讯COS
     *
     * @param file
     * @return
     */
    @Override
    public Map<String, String> uploadImg(MultipartFile file) {
        HashMap<String, String> map = new HashMap<>(16);
        File tempFile = null;
        // 后缀
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
        try {
            /**
             * 存放到临时文件
             */
            tempFile = File.createTempFile(FILE_TEMP_PREFIX, suffix);
            file.transferTo(tempFile);
            map.put("originalDrawingUrl", imgUpload(tempFile, suffix));
            map.put("thumbnailUrl", thumbnailUpload(tempFile, suffix));
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new BizException("上传图片失败");
        } finally {
            /**
             * 删除创建的临时文件
             */
            if (tempFile != null) {
                tempFile.delete();
            }
        }
        return map;
    }

    /**
     * 上传视频至腾讯COS
     *
     * @param file
     * @return
     */
    @Override
    public Map<String, Object> uploadVideo(MultipartFile file) {
        HashMap<String, Object> map = new HashMap<>(16);
        File tempFile = null;
        // 后缀
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
        try {
            /**
             * 存放到临时文件
             */
            tempFile = File.createTempFile(FILE_TEMP_PREFIX, suffix);
            file.transferTo(tempFile);
            map.put("videoUrl", videoUpload(tempFile, suffix));
            map.put("screenshotUrl", screenshotUpload(tempFile, suffix));
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new BizException("上传视频失败");
        } finally {
            /**
             * 删除创建的临时文件
             */
            if (tempFile != null) {
                tempFile.delete();
            }
        }
        return map;
    }

    /**
     * 上传图片
     *
     * @param file   文件
     * @param suffix 后缀(.jpg 格式)
     * @return cos路径
     */
    @Override
    public String imgUpload(File file, String suffix) {
        String url = "";
        try {
            String key = masterDirectory + imgDirectory + UUID.randomUUID().toString() + suffix;
            url = UploadFileCOS(file, key);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BizException("上传图片失败");
        }
        return url;
    }

    /**
     * 生成二维码
     *
     * @param text
     * @param width
     * @param height
     * @return
     */
    @Override
    public String generateQRCodeImage(String text, int width, int height) {
        FileOutputStream fileOutputStream = null;
        File tempFile = null;
        String url = "";
        try {
            tempFile = File.createTempFile(FILE_TEMP_PREFIX, ".png");
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
            fileOutputStream = new FileOutputStream(tempFile);
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", fileOutputStream);

            url = imgUpload(tempFile, ".png");
        } catch (Exception e) {
            log.error("生成二维码失败!", e.getMessage());
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (tempFile != null) {
                tempFile.delete();
            }
        }
        return url;
    }

    /**
     * 生成二维码
     *
     * @param text
     * @return
     */
    @Override
    public String generateQRCodeImage(String text) {
        return generateQRCodeImage(text, 350, 350);
    }

    /**
     * 上传图片缩略图
     *
     * @param file   文件
     * @param suffix 后缀(.jpg 格式)
     * @return cos路径
     */
    private String thumbnailUpload(File file, String suffix) {
        String url = "";
        File newFile = null;
        /**
         * 指定大小进行缩放
         * 若图片横比300小,高比300小,不变
         * 若图片横比300小,高比300大,高缩小到300,图片比例不变
         * 若图片横比300大,高比300小,横缩小到300,图片比例不变
         * 若图片横比300大,高比300大,图片按比例缩小,横为300或高为300
         */
        try {
            newFile = File.createTempFile(FILE_TEMP_PREFIX, suffix);
            Thumbnails.of(file).size(300, 300).toFile(newFile);
            String key = masterDirectory + imgDirectory + UUID.randomUUID().toString() + suffix;
            url = UploadFileCOS(newFile, key);
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new BizException("上传图片失败");
        } finally {
            /**
             * 删除创建的临时文件
             */
            if (newFile != null) {
                newFile.delete();
            }
        }
        return url;
    }

    /**
     * 上传图视频
     *
     * @param file   文件
     * @param suffix 后缀(.jpg 格式)
     * @return cos路径
     */
    private String videoUpload(File file, String suffix) {
        String url = "";
        try {
            String key = masterDirectory + videoDirectory + UUID.randomUUID().toString() + suffix;
            url = UploadFileCOS(file, key);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BizException("上传视频失败");
        }
        return url;
    }

    /**
     * 上传文件
     *
     * @param file   文件
     * @param suffix 后缀(.jpg 格式)
     * @return cos路径
     */
    @Override
    public String fileUpload(File file, String suffix) {
        return fileUpload(file, suffix, FILE_EXPIRED);
    }

    /**
     * 上传文件
     *
     * @param file   文件
     * @param suffix 后缀(.jpg 格式)
     * @return cos路径
     */
    @Override
    public String fileUpload(File file, String suffix, Long expireTime) {
        String url = "";
        try {
            String key = masterDirectory + fileDirectory + UUID.randomUUID().toString() + suffix;
            url = UploadFileCOS(file, key, expireTime);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BizException("上传视频失败");
        }
        return url;
    }

    /**
     * 上传视频截图
     *
     * @param file   文件
     * @param suffix 后缀(.jpg 格式)
     * @return cos路径
     */
    private String screenshotUpload(File file, String suffix) {
        log.info("视频处理开始:" + System.currentTimeMillis());
        String url = "";
        File newFile = null;
        FFmpegFrameGrabber grabber = null;

        try {
            // 创建grabber
            grabber = new FFmpegFrameGrabber(file);
            // 第一帧图片存储位置
            LocalDate date = LocalDate.now();
            grabber.start();
            // 视频总帧数
            int videoLength = grabber.getLengthInFrames();
            // 设置视频截取帧(默认取第一帧)
            Frame frame = null;
            int i = 0;
            while (i < videoLength) {
                // 过滤前5帧,避免出现全黑的图片,依自己情况而定(每循环一次取一帧)
                frame = grabber.grabFrame();
                if ((i > GET_FRAMES_LENGTH) && (frame.image != null)) {
                    break;
                }
                i++;
            }
            // 视频旋转度
            String rotate = grabber.getVideoMetadata("rotate");
            Java2DFrameConverter converter = new Java2DFrameConverter();
            //绘制图片
            BufferedImage bi = converter.getBufferedImage(frame);
            if (rotate != null) {
                // 旋转图片
                bi = rotate(bi, Integer.parseInt(rotate));
            }

            newFile = File.createTempFile(FILE_TEMP_PREFIX, VIDEO_IMG_SUFFIX);
            ImageIO.write(bi, VIDEO_IMG_SUFFIX, newFile);
            String key = masterDirectory + imgDirectory + UUID.randomUUID().toString() + "." + VIDEO_IMG_SUFFIX;
            url = UploadFileCOS(newFile, key);

            //
            long duration = grabber.getLengthInTime() / (1000 * 1000);
            log.info("视频的宽:" + bi.getWidth());
            log.info("视频的高:" + bi.getHeight());
            log.info("视频的旋转度:" + rotate);
            log.info("视频的格式:" + grabber.getFormat());
            log.info("此视频时长(s/秒):" + duration);
            log.info("视频处理结束:" + System.currentTimeMillis());
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BizException("上传图片失败");
        } finally {
            /**
             * 关闭
             */
            if (grabber != null) {
                try {
                    grabber.stop();
                } catch (FrameGrabber.Exception e) {
                    e.printStackTrace();
                }
            }
            /**
             * 删除创建的临时文件
             */
            if (newFile != null) {
                newFile.delete();
            }
        }
        return url;
    }

    /**
     * 上传文件至腾讯COS
     *
     * @param file 文件
     * @param key  路径key
     * @return
     */
    private String UploadFileCOS(File file, String key) {
        return UploadFileCOS(file, key, FILE_EXPIRED);
    }

    /**
     * 上传文件至腾讯COS
     *
     * @param file 文件
     * @param key  路径key
     * @return
     */
    private String UploadFileCOS(File file, String key, Long expireTime) {
        log.info("上传文件到腾讯COS");
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // 2 设置 bucket 的地域, COS 地域的简称
        ClientConfig clientConfig = new ClientConfig(new Region(regionName));
        clientConfig.setSignExpired(CLIENTCONFIG_EXPIRED);
        // 这里建议设置使用 https 协议
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            Date expiration = new Date(System.currentTimeMillis() + expireTime);
            URL url = cosClient.generatePresignedUrl(bucketName, key, expiration);
            return url.toString().substring(0, url.toString().indexOf(SEPARATIVE_SING));
        } catch (Exception e) {
            log.error("图片上传失败,请稍后再试", e.getMessage());
            throw new BizException("图片上传失败,请稍后再试");
        } finally {
            cosClient.shutdown();
        }
    }

    /**
     * @param src
     * @param angel 视频旋转度
     * @return BufferedImage
     * @Description: 根据视频旋转度来调整图片
     */
    private static BufferedImage rotate(BufferedImage src, int angel) {
        int srcWidth = src.getWidth(null);
        int srcHeight = src.getHeight(null);
        int type = src.getColorModel().getTransparency();
        Rectangle rectDes = calcRotatedSize(new Rectangle(new Dimension(srcWidth, srcHeight)), angel);
        BufferedImage bi = new BufferedImage(rectDes.width, rectDes.height, type);
        Graphics2D g2 = bi.createGraphics();
        g2.translate((rectDes.width - srcWidth) / 2, (rectDes.height - srcHeight) / 2);
        g2.rotate(Math.toRadians(angel), srcWidth / 2, srcHeight / 2);
        g2.drawImage(src, 0, 0, null);
        g2.dispose();
        return bi;
    }

    /**
     * @param src
     * @param angel
     * @return Rectangle
     * @Description: 计算图片旋转大小
     */
    private static Rectangle calcRotatedSize(Rectangle src, int angel) {
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }
        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);
        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }

}

 以上代码如有错误的地方,还请指出。一起成长~

 

posted @ 2021-09-13 22:09  放手解脱  阅读(656)  评论(0编辑  收藏  举报