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)); } }
以上代码如有错误的地方,还请指出。一起成长~