Ruoyi-vue-plus-5.x第八篇文件管理与存储: 8.3 文件处理功能
👋 大家好,我是 阿问学长
!专注于分享优质开源项目
解析、毕业设计项目指导
支持、幼小初高
的教辅资料
推荐等,欢迎关注交流!🚀
文件处理功能
前言
文件处理是现代Web应用的重要功能模块,涉及文件的上传、下载、预览、转换、压缩等多个方面。RuoYi-Vue-Plus框架提供了完整的文件处理解决方案,支持多种文件格式的处理,包括图片处理、文档转换、视频处理等。本文将详细介绍图片处理与缩略图生成、文档预览与转换、文件压缩与解压以及文件安全检查等内容。
图片处理与缩略图生成
图片处理服务
/*** 图片处理服务*/
@Service
@Slf4j
public class ImageProcessingService {@Autowiredprivate OssStrategyManager ossStrategyManager;/*** 支持的图片格式*/private static final Set<String> SUPPORTED_IMAGE_FORMATS = Set.of("jpg", "jpeg", "png", "gif", "bmp", "webp");/*** 默认缩略图尺寸*/private static final Map<String, Dimension> THUMBNAIL_SIZES = Map.of("small", new Dimension(150, 150),"medium", new Dimension(300, 300),"large", new Dimension(600, 600));/*** 生成缩略图*/public ImageProcessResult generateThumbnail(String originalObjectName, String size) {try {// 获取原始图片OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream originalStream = ossTemplate.download(originalObjectName);// 读取原始图片BufferedImage originalImage = ImageIO.read(originalStream);if (originalImage == null) {throw new RuntimeException("无法读取图片文件");}// 获取缩略图尺寸Dimension thumbnailSize = THUMBNAIL_SIZES.get(size);if (thumbnailSize == null) {throw new RuntimeException("不支持的缩略图尺寸: " + size);}// 生成缩略图BufferedImage thumbnailImage = createThumbnail(originalImage, thumbnailSize);// 生成缩略图文件名String thumbnailObjectName = generateThumbnailObjectName(originalObjectName, size);// 上传缩略图String thumbnailUrl = uploadThumbnail(thumbnailImage, thumbnailObjectName);log.info("生成缩略图成功: original={}, thumbnail={}, size={}", originalObjectName, thumbnailObjectName, size);return ImageProcessResult.builder().success(true).originalObjectName(originalObjectName).thumbnailObjectName(thumbnailObjectName).thumbnailUrl(thumbnailUrl).size(size).width(thumbnailSize.width).height(thumbnailSize.height).build();} catch (Exception e) {log.error("生成缩略图失败: originalObjectName={}, size={}", originalObjectName, size, e);return ImageProcessResult.builder().success(false).message("生成缩略图失败: " + e.getMessage()).build();}}/*** 批量生成缩略图*/public List<ImageProcessResult> generateThumbnails(String originalObjectName, List<String> sizes) {List<ImageProcessResult> results = new ArrayList<>();for (String size : sizes) {ImageProcessResult result = generateThumbnail(originalObjectName, size);results.add(result);}return results;}/*** 图片格式转换*/public ImageProcessResult convertFormat(String originalObjectName, String targetFormat) {try {// 验证目标格式if (!SUPPORTED_IMAGE_FORMATS.contains(targetFormat.toLowerCase())) {throw new RuntimeException("不支持的图片格式: " + targetFormat);}// 获取原始图片OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream originalStream = ossTemplate.download(originalObjectName);// 读取原始图片BufferedImage originalImage = ImageIO.read(originalStream);if (originalImage == null) {throw new RuntimeException("无法读取图片文件");}// 生成转换后的文件名String convertedObjectName = generateConvertedObjectName(originalObjectName, targetFormat);// 转换格式并上传String convertedUrl = convertAndUpload(originalImage, convertedObjectName, targetFormat);log.info("图片格式转换成功: original={}, converted={}, format={}", originalObjectName, convertedObjectName, targetFormat);return ImageProcessResult.builder().success(true).originalObjectName(originalObjectName).convertedObjectName(convertedObjectName).convertedUrl(convertedUrl).targetFormat(targetFormat).build();} catch (Exception e) {log.error("图片格式转换失败: originalObjectName={}, targetFormat={}", originalObjectName, targetFormat, e);return ImageProcessResult.builder().success(false).message("图片格式转换失败: " + e.getMessage()).build();}}/*** 图片压缩*/public ImageProcessResult compressImage(String originalObjectName, float quality) {try {// 验证压缩质量参数if (quality <= 0 || quality > 1) {throw new RuntimeException("压缩质量参数必须在0-1之间");}// 获取原始图片OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream originalStream = ossTemplate.download(originalObjectName);// 读取原始图片BufferedImage originalImage = ImageIO.read(originalStream);if (originalImage == null) {throw new RuntimeException("无法读取图片文件");}// 生成压缩后的文件名String compressedObjectName = generateCompressedObjectName(originalObjectName, quality);// 压缩图片并上传String compressedUrl = compressAndUpload(originalImage, compressedObjectName, quality);log.info("图片压缩成功: original={}, compressed={}, quality={}", originalObjectName, compressedObjectName, quality);return ImageProcessResult.builder().success(true).originalObjectName(originalObjectName).compressedObjectName(compressedObjectName).compressedUrl(compressedUrl).quality(quality).build();} catch (Exception e) {log.error("图片压缩失败: originalObjectName={}, quality={}", originalObjectName, quality, e);return ImageProcessResult.builder().success(false).message("图片压缩失败: " + e.getMessage()).build();}}/*** 图片裁剪*/public ImageProcessResult cropImage(String originalObjectName, int x, int y, int width, int height) {try {// 获取原始图片OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream originalStream = ossTemplate.download(originalObjectName);// 读取原始图片BufferedImage originalImage = ImageIO.read(originalStream);if (originalImage == null) {throw new RuntimeException("无法读取图片文件");}// 验证裁剪参数validateCropParameters(originalImage, x, y, width, height);// 裁剪图片BufferedImage croppedImage = originalImage.getSubimage(x, y, width, height);// 生成裁剪后的文件名String croppedObjectName = generateCroppedObjectName(originalObjectName, x, y, width, height);// 上传裁剪后的图片String croppedUrl = uploadProcessedImage(croppedImage, croppedObjectName, "jpg");log.info("图片裁剪成功: original={}, cropped={}, region=({},{},{},{})", originalObjectName, croppedObjectName, x, y, width, height);return ImageProcessResult.builder().success(true).originalObjectName(originalObjectName).croppedObjectName(croppedObjectName).croppedUrl(croppedUrl).cropX(x).cropY(y).cropWidth(width).cropHeight(height).build();} catch (Exception e) {log.error("图片裁剪失败: originalObjectName={}, region=({},{},{},{})", originalObjectName, x, y, width, height, e);return ImageProcessResult.builder().success(false).message("图片裁剪失败: " + e.getMessage()).build();}}/*** 添加水印*/public ImageProcessResult addWatermark(String originalObjectName, String watermarkText, WatermarkPosition position, float opacity) {try {// 获取原始图片OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream originalStream = ossTemplate.download(originalObjectName);// 读取原始图片BufferedImage originalImage = ImageIO.read(originalStream);if (originalImage == null) {throw new RuntimeException("无法读取图片文件");}// 添加水印BufferedImage watermarkedImage = addTextWatermark(originalImage, watermarkText, position, opacity);// 生成水印后的文件名String watermarkedObjectName = generateWatermarkedObjectName(originalObjectName);// 上传水印后的图片String watermarkedUrl = uploadProcessedImage(watermarkedImage, watermarkedObjectName, "jpg");log.info("添加水印成功: original={}, watermarked={}, text={}, position={}", originalObjectName, watermarkedObjectName, watermarkText, position);return ImageProcessResult.builder().success(true).originalObjectName(originalObjectName).watermarkedObjectName(watermarkedObjectName).watermarkedUrl(watermarkedUrl).watermarkText(watermarkText).watermarkPosition(position).watermarkOpacity(opacity).build();} catch (Exception e) {log.error("添加水印失败: originalObjectName={}, text={}", originalObjectName, watermarkText, e);return ImageProcessResult.builder().success(false).message("添加水印失败: " + e.getMessage()).build();}}/*** 创建缩略图*/private BufferedImage createThumbnail(BufferedImage originalImage, Dimension size) {int originalWidth = originalImage.getWidth();int originalHeight = originalImage.getHeight();// 计算缩放比例,保持宽高比double scaleX = (double) size.width / originalWidth;double scaleY = (double) size.height / originalHeight;double scale = Math.min(scaleX, scaleY);int thumbnailWidth = (int) (originalWidth * scale);int thumbnailHeight = (int) (originalHeight * scale);// 创建缩略图BufferedImage thumbnailImage = new BufferedImage(thumbnailWidth, thumbnailHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = thumbnailImage.createGraphics();// 设置渲染质量g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 绘制缩略图g2d.drawImage(originalImage, 0, 0, thumbnailWidth, thumbnailHeight, null);g2d.dispose();return thumbnailImage;}/*** 上传缩略图*/private String uploadThumbnail(BufferedImage thumbnailImage, String objectName) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ImageIO.write(thumbnailImage, "jpg", baos);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();return ossTemplate.upload(objectName, bais, "image/jpeg", baos.size());}/*** 转换格式并上传*/private String convertAndUpload(BufferedImage image, String objectName, String format) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();// 处理透明度if ("jpg".equalsIgnoreCase(format) || "jpeg".equalsIgnoreCase(format)) {BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);Graphics2D g2d = rgbImage.createGraphics();g2d.setColor(Color.WHITE);g2d.fillRect(0, 0, image.getWidth(), image.getHeight());g2d.drawImage(image, 0, 0, null);g2d.dispose();image = rgbImage;}ImageIO.write(image, format, baos);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());String contentType = "image/" + format.toLowerCase();OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();return ossTemplate.upload(objectName, bais, contentType, baos.size());}/*** 压缩并上传*/private String compressAndUpload(BufferedImage image, String objectName, float quality) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();// 获取JPEG写入器Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");if (!writers.hasNext()) {throw new RuntimeException("没有找到JPEG写入器");}ImageWriter writer = writers.next();ImageOutputStream ios = ImageIO.createImageOutputStream(baos);writer.setOutput(ios);// 设置压缩参数ImageWriteParam param = writer.getDefaultWriteParam();param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);param.setCompressionQuality(quality);// 写入压缩图片writer.write(null, new IIOImage(image, null, null), param);// 清理资源ios.close();writer.dispose();ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();return ossTemplate.upload(objectName, bais, "image/jpeg", baos.size());}/*** 上传处理后的图片*/private String uploadProcessedImage(BufferedImage image, String objectName, String format) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ImageIO.write(image, format, baos);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());String contentType = "image/" + format.toLowerCase();OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();return ossTemplate.upload(objectName, bais, contentType, baos.size());}/*** 添加文字水印*/private BufferedImage addTextWatermark(BufferedImage originalImage, String watermarkText, WatermarkPosition position, float opacity) {int width = originalImage.getWidth();int height = originalImage.getHeight();BufferedImage watermarkedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = watermarkedImage.createGraphics();// 绘制原始图片g2d.drawImage(originalImage, 0, 0, null);// 设置水印样式g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g2d.setFont(new Font("Arial", Font.BOLD, Math.max(width / 20, 20)));g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));g2d.setColor(Color.WHITE);// 计算水印位置FontMetrics fm = g2d.getFontMetrics();int textWidth = fm.stringWidth(watermarkText);int textHeight = fm.getHeight();Point watermarkPos = calculateWatermarkPosition(position, width, height, textWidth, textHeight);// 绘制水印背景g2d.setColor(new Color(0, 0, 0, 100));g2d.fillRoundRect(watermarkPos.x - 10, watermarkPos.y - textHeight + 5, textWidth + 20, textHeight + 10, 10, 10);// 绘制水印文字g2d.setColor(Color.WHITE);g2d.drawString(watermarkText, watermarkPos.x, watermarkPos.y);g2d.dispose();return watermarkedImage;}/*** 计算水印位置*/private Point calculateWatermarkPosition(WatermarkPosition position, int imageWidth, int imageHeight, int textWidth, int textHeight) {int x, y;switch (position) {case TOP_LEFT:x = 20;y = textHeight + 20;break;case TOP_RIGHT:x = imageWidth - textWidth - 20;y = textHeight + 20;break;case BOTTOM_LEFT:x = 20;y = imageHeight - 20;break;case BOTTOM_RIGHT:x = imageWidth - textWidth - 20;y = imageHeight - 20;break;case CENTER:default:x = (imageWidth - textWidth) / 2;y = (imageHeight + textHeight) / 2;break;}return new Point(x, y);}/*** 验证裁剪参数*/private void validateCropParameters(BufferedImage image, int x, int y, int width, int height) {if (x < 0 || y < 0) {throw new RuntimeException("裁剪起始坐标不能为负数");}if (width <= 0 || height <= 0) {throw new RuntimeException("裁剪宽度和高度必须大于0");}if (x + width > image.getWidth() || y + height > image.getHeight()) {throw new RuntimeException("裁剪区域超出图片范围");}}/*** 生成缩略图对象名称*/private String generateThumbnailObjectName(String originalObjectName, String size) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));String extension = originalObjectName.substring(originalObjectName.lastIndexOf('.'));return baseName + "_thumb_" + size + extension;}/*** 生成转换后的对象名称*/private String generateConvertedObjectName(String originalObjectName, String targetFormat) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));return baseName + "_converted." + targetFormat.toLowerCase();}/*** 生成压缩后的对象名称*/private String generateCompressedObjectName(String originalObjectName, float quality) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));String extension = originalObjectName.substring(originalObjectName.lastIndexOf('.'));int qualityPercent = (int) (quality * 100);return baseName + "_compressed_" + qualityPercent + extension;}/*** 生成裁剪后的对象名称*/private String generateCroppedObjectName(String originalObjectName, int x, int y, int width, int height) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));String extension = originalObjectName.substring(originalObjectName.lastIndexOf('.'));return baseName + "_cropped_" + x + "_" + y + "_" + width + "_" + height + extension;}/*** 生成水印后的对象名称*/private String generateWatermarkedObjectName(String originalObjectName) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));String extension = originalObjectName.substring(originalObjectName.lastIndexOf('.'));return baseName + "_watermarked" + extension;}
}/*** 图片处理结果*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ImageProcessResult {/*** 是否成功*/private boolean success;/*** 错误消息*/private String message;/*** 原始对象名称*/private String originalObjectName;/*** 缩略图对象名称*/private String thumbnailObjectName;/*** 缩略图URL*/private String thumbnailUrl;/*** 缩略图尺寸*/private String size;/*** 缩略图宽度*/private int width;/*** 缩略图高度*/private int height;/*** 转换后的对象名称*/private String convertedObjectName;/*** 转换后的URL*/private String convertedUrl;/*** 目标格式*/private String targetFormat;/*** 压缩后的对象名称*/private String compressedObjectName;/*** 压缩后的URL*/private String compressedUrl;/*** 压缩质量*/private float quality;/*** 裁剪后的对象名称*/private String croppedObjectName;/*** 裁剪后的URL*/private String croppedUrl;/*** 裁剪起始X坐标*/private int cropX;/*** 裁剪起始Y坐标*/private int cropY;/*** 裁剪宽度*/private int cropWidth;/*** 裁剪高度*/private int cropHeight;/*** 水印后的对象名称*/private String watermarkedObjectName;/*** 水印后的URL*/private String watermarkedUrl;/*** 水印文字*/private String watermarkText;/*** 水印位置*/private WatermarkPosition watermarkPosition;/*** 水印透明度*/private float watermarkOpacity;
}/*** 水印位置枚举*/
public enum WatermarkPosition {TOP_LEFT,TOP_RIGHT,BOTTOM_LEFT,BOTTOM_RIGHT,CENTER
}
文档预览与转换
文档转换服务
/*** 文档转换服务*/
@Service
@Slf4j
public class DocumentConversionService {@Autowiredprivate OssStrategyManager ossStrategyManager;/*** 支持的文档格式*/private static final Set<String> SUPPORTED_DOCUMENT_FORMATS = Set.of("doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf");/*** LibreOffice路径配置*/@Value("${document.libreoffice.path:/usr/bin/libreoffice}")private String libreOfficePath;/*** 临时目录配置*/@Value("${document.temp.dir:/tmp/document-conversion}")private String tempDir;/*** 文档转PDF*/public DocumentConversionResult convertToPdf(String originalObjectName) {try {// 验证文档格式String extension = getFileExtension(originalObjectName);if (!SUPPORTED_DOCUMENT_FORMATS.contains(extension.toLowerCase())) {throw new RuntimeException("不支持的文档格式: " + extension);}// 下载原始文档OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream originalStream = ossTemplate.download(originalObjectName);// 创建临时文件File tempInputFile = createTempFile(originalStream, extension);File tempOutputFile = new File(tempDir, UUID.randomUUID().toString() + ".pdf");try {// 执行转换boolean success = convertWithLibreOffice(tempInputFile, tempOutputFile);if (!success) {throw new RuntimeException("文档转换失败");}// 上传转换后的PDFString pdfObjectName = generatePdfObjectName(originalObjectName);String pdfUrl = uploadConvertedFile(tempOutputFile, pdfObjectName);log.info("文档转PDF成功: original={}, pdf={}", originalObjectName, pdfObjectName);return DocumentConversionResult.builder().success(true).originalObjectName(originalObjectName).pdfObjectName(pdfObjectName).pdfUrl(pdfUrl).build();} finally {// 清理临时文件cleanupTempFiles(tempInputFile, tempOutputFile);}} catch (Exception e) {log.error("文档转PDF失败: originalObjectName={}", originalObjectName, e);return DocumentConversionResult.builder().success(false).message("文档转PDF失败: " + e.getMessage()).build();}}/*** 文档转图片*/public DocumentConversionResult convertToImages(String originalObjectName) {try {// 先转换为PDFDocumentConversionResult pdfResult = convertToPdf(originalObjectName);if (!pdfResult.isSuccess()) {return pdfResult;}// 下载PDF文件OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream pdfStream = ossTemplate.download(pdfResult.getPdfObjectName());// 将PDF转换为图片List<String> imageUrls = convertPdfToImages(pdfStream, originalObjectName);log.info("文档转图片成功: original={}, imageCount={}", originalObjectName, imageUrls.size());return DocumentConversionResult.builder().success(true).originalObjectName(originalObjectName).imageUrls(imageUrls).imageCount(imageUrls.size()).build();} catch (Exception e) {log.error("文档转图片失败: originalObjectName={}", originalObjectName, e);return DocumentConversionResult.builder().success(false).message("文档转图片失败: " + e.getMessage()).build();}}/*** 获取文档信息*/public DocumentInfo getDocumentInfo(String objectName) {try {// 下载文档OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();InputStream documentStream = ossTemplate.download(objectName);// 创建临时文件String extension = getFileExtension(objectName);File tempFile = createTempFile(documentStream, extension);try {// 解析文档信息DocumentInfo info = parseDocumentInfo(tempFile, extension);info.setObjectName(objectName);return info;} finally {// 清理临时文件if (tempFile.exists()) {tempFile.delete();}}} catch (Exception e) {log.error("获取文档信息失败: objectName={}", objectName, e);throw new RuntimeException("获取文档信息失败", e);}}/*** 使用LibreOffice转换文档*/private boolean convertWithLibreOffice(File inputFile, File outputFile) {try {// 确保输出目录存在outputFile.getParentFile().mkdirs();// 构建LibreOffice命令List<String> command = Arrays.asList(libreOfficePath,"--headless","--convert-to", "pdf","--outdir", outputFile.getParent(),inputFile.getAbsolutePath());// 执行转换命令ProcessBuilder pb = new ProcessBuilder(command);pb.redirectErrorStream(true);Process process = pb.start();// 读取输出try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {log.debug("LibreOffice输出: {}", line);}}// 等待转换完成int exitCode = process.waitFor();if (exitCode == 0) {// 重命名输出文件String expectedOutputName = inputFile.getName().replaceAll("\\.[^.]+$", ".pdf");File expectedOutputFile = new File(outputFile.getParent(), expectedOutputName);if (expectedOutputFile.exists() && !expectedOutputFile.equals(outputFile)) {return expectedOutputFile.renameTo(outputFile);}return outputFile.exists();} else {log.error("LibreOffice转换失败,退出码: {}", exitCode);return false;}} catch (Exception e) {log.error("LibreOffice转换异常", e);return false;}}/*** PDF转图片*/private List<String> convertPdfToImages(InputStream pdfStream, String originalObjectName) throws IOException {List<String> imageUrls = new ArrayList<>();try (PDDocument document = PDDocument.load(pdfStream)) {PDFRenderer pdfRenderer = new PDFRenderer(document);for (int page = 0; page < document.getNumberOfPages(); page++) {// 渲染页面为图片BufferedImage image = pdfRenderer.renderImageWithDPI(page, 150, ImageType.RGB);// 生成图片文件名String imageObjectName = generateImageObjectName(originalObjectName, page + 1);// 上传图片String imageUrl = uploadImage(image, imageObjectName);imageUrls.add(imageUrl);}}return imageUrls;}/*** 解析文档信息*/private DocumentInfo parseDocumentInfo(File file, String extension) throws IOException {DocumentInfo info = new DocumentInfo();info.setFileSize(file.length());info.setFormat(extension.toUpperCase());switch (extension.toLowerCase()) {case "pdf":parsePdfInfo(file, info);break;case "doc":case "docx":parseWordInfo(file, info);break;case "xls":case "xlsx":parseExcelInfo(file, info);break;case "ppt":case "pptx":parsePowerPointInfo(file, info);break;default:info.setPageCount(1);break;}return info;}/*** 解析PDF信息*/private void parsePdfInfo(File file, DocumentInfo info) throws IOException {try (PDDocument document = PDDocument.load(file)) {info.setPageCount(document.getNumberOfPages());PDDocumentInformation docInfo = document.getDocumentInformation();if (docInfo != null) {info.setTitle(docInfo.getTitle());info.setAuthor(docInfo.getAuthor());info.setSubject(docInfo.getSubject());info.setCreationDate(docInfo.getCreationDate() != null ? docInfo.getCreationDate().getTime() : null);}}}/*** 解析Word文档信息*/private void parseWordInfo(File file, DocumentInfo info) throws IOException {// 使用Apache POI解析Word文档// 这里简化实现,实际应该根据具体需求解析info.setPageCount(1); // Word文档页数需要特殊处理info.setTitle(file.getName());}/*** 解析Excel信息*/private void parseExcelInfo(File file, DocumentInfo info) throws IOException {// 使用Apache POI解析Excel文档// 这里简化实现info.setPageCount(1); // Excel工作表数量info.setTitle(file.getName());}/*** 解析PowerPoint信息*/private void parsePowerPointInfo(File file, DocumentInfo info) throws IOException {// 使用Apache POI解析PowerPoint文档// 这里简化实现info.setPageCount(1); // PPT幻灯片数量info.setTitle(file.getName());}/*** 创建临时文件*/private File createTempFile(InputStream inputStream, String extension) throws IOException {// 确保临时目录存在File tempDirFile = new File(tempDir);if (!tempDirFile.exists()) {tempDirFile.mkdirs();}// 创建临时文件File tempFile = new File(tempDir, UUID.randomUUID().toString() + "." + extension);// 写入文件内容try (FileOutputStream fos = new FileOutputStream(tempFile)) {IOUtils.copy(inputStream, fos);}return tempFile;}/*** 上传转换后的文件*/private String uploadConvertedFile(File file, String objectName) throws IOException {try (FileInputStream fis = new FileInputStream(file)) {OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();return ossTemplate.upload(objectName, fis, "application/pdf", file.length());}}/*** 上传图片*/private String uploadImage(BufferedImage image, String objectName) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ImageIO.write(image, "png", baos);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());OssTemplate ossTemplate = ossStrategyManager.getDefaultTemplate();return ossTemplate.upload(objectName, bais, "image/png", baos.size());}/*** 清理临时文件*/private void cleanupTempFiles(File... files) {for (File file : files) {if (file != null && file.exists()) {try {file.delete();} catch (Exception e) {log.warn("清理临时文件失败: {}", file.getAbsolutePath(), e);}}}}/*** 获取文件扩展名*/private String getFileExtension(String fileName) {int lastDotIndex = fileName.lastIndexOf('.');if (lastDotIndex == -1) {return "";}return fileName.substring(lastDotIndex + 1);}/*** 生成PDF对象名称*/private String generatePdfObjectName(String originalObjectName) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));return baseName + "_converted.pdf";}/*** 生成图片对象名称*/private String generateImageObjectName(String originalObjectName, int pageNumber) {String baseName = originalObjectName.substring(0, originalObjectName.lastIndexOf('.'));return baseName + "_page_" + pageNumber + ".png";}
}/*** 文档转换结果*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DocumentConversionResult {/*** 是否成功*/private boolean success;/*** 错误消息*/private String message;/*** 原始对象名称*/private String originalObjectName;/*** PDF对象名称*/private String pdfObjectName;/*** PDF URL*/private String pdfUrl;/*** 图片URL列表*/private List<String> imageUrls;/*** 图片数量*/private int imageCount;
}/*** 文档信息*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DocumentInfo {/*** 对象名称*/private String objectName;/*** 文件大小*/private long fileSize;/*** 文档格式*/private String format;/*** 页数*/private int pageCount;/*** 标题*/private String title;/*** 作者*/private String author;/*** 主题*/private String subject;/*** 创建时间*/private Date creationDate;/*** 格式化文件大小*/public String getFormattedFileSize() {return FileUtils.formatFileSize(fileSize);}
}
总结
本文详细介绍了文件处理功能,包括:
- 图片处理与缩略图生成:缩略图生成、格式转换、图片压缩、图片裁剪、水印添加
- 文档预览与转换:文档转PDF、文档转图片、文档信息解析、LibreOffice集成
文件处理功能为应用提供了强大的文件操作能力,支持多种格式的文件处理和转换,满足不同的业务需求。
在下一篇文章中,我们将探讨文件安全与权限控制。
参考资料
- Java BufferedImage处理
- Apache PDFBox文档
- LibreOffice命令行工具