123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- package com.zhentao.osspicture;
- import com.aliyun.oss.OSS;
- import com.aliyun.oss.OSSClientBuilder;
- import com.aliyun.oss.model.ObjectMetadata;
- import com.aliyun.oss.model.PutObjectRequest;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import org.springframework.web.multipart.MultipartFile;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.UUID;
- @Component
- @Slf4j
- public class OssUtil {
- // 从配置文件中读取OSS相关信息
- private static final String endpoint = "https://oss-cn-beijing.aliyuncs.com";
- private static final String accessKeyId = "LTAI5tH9VHPZwGJu4UX3hrL5";
- private static final String accessKeySecret = "mbsutFJYLkzosvvKNr0DD28XSg4mqA";
- private static final String bucketName = "fjj1";
- private static final boolean useCDN = true;
- private static final String cdnDomain = "https://cdn.yourdomain.com";
- // MIME类型到扩展名的映射
- private static final Map<String, String> MIME_TO_EXTENSION = new HashMap<>();
- static {
- // 图片类型
- MIME_TO_EXTENSION.put("image/jpeg", "jpg");
- MIME_TO_EXTENSION.put("image/png", "png");
- MIME_TO_EXTENSION.put("image/gif", "gif");
- MIME_TO_EXTENSION.put("image/bmp", "bmp");
- MIME_TO_EXTENSION.put("image/webp", "webp");
- MIME_TO_EXTENSION.put("image/svg+xml", "svg");
- // 视频类型
- MIME_TO_EXTENSION.put("video/mp4", "mp4");
- MIME_TO_EXTENSION.put("video/quicktime", "mov");
- MIME_TO_EXTENSION.put("video/x-msvideo", "avi");
- MIME_TO_EXTENSION.put("video/x-matroska", "mkv");
- MIME_TO_EXTENSION.put("video/x-flv", "flv");
- MIME_TO_EXTENSION.put("video/webm", "webm");
- // 音频类型
- MIME_TO_EXTENSION.put("audio/mpeg", "mp3");
- MIME_TO_EXTENSION.put("audio/wav", "wav");
- MIME_TO_EXTENSION.put("audio/ogg", "ogg");
- MIME_TO_EXTENSION.put("audio/flac", "flac");
- MIME_TO_EXTENSION.put("audio/aac", "aac");
- // 文档类型
- MIME_TO_EXTENSION.put("application/pdf", "pdf");
- MIME_TO_EXTENSION.put("application/msword", "doc");
- MIME_TO_EXTENSION.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx");
- MIME_TO_EXTENSION.put("application/vnd.ms-excel", "xls");
- MIME_TO_EXTENSION.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
- MIME_TO_EXTENSION.put("application/vnd.ms-powerpoint", "ppt");
- MIME_TO_EXTENSION.put("application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx");
- MIME_TO_EXTENSION.put("text/plain", "txt");
- }
- public String uploadFile(MultipartFile file) throws IOException {
- if (file == null || file.isEmpty()) {
- throw new IllegalArgumentException("上传文件不能为空");
- }
- OSS ossClient = null;
- try {
- ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
- String originalFilename = file.getOriginalFilename();
- String contentType = file.getContentType();
- long fileSize = file.getSize();
- // 确定文件类型和扩展名
- FileTypeInfo fileTypeInfo = determineFileType(originalFilename, contentType);
- String extension = fileTypeInfo.getExtension();
- String fileCategory = fileTypeInfo.getCategory();
- // 生成唯一的文件名
- String fileName = generateUniqueFileName(fileCategory, extension);
- // 创建文件元数据
- ObjectMetadata metadata = createMetadata(originalFilename, contentType, fileSize, fileCategory);
- // 上传文件
- try (InputStream inputStream = file.getInputStream()) {
- PutObjectRequest putObjectRequest = new PutObjectRequest(
- bucketName,
- fileName,
- inputStream,
- metadata
- );
- ossClient.putObject(putObjectRequest);
- }
- // 生成文件访问URL
- String fileUrl = generateFileUrl(fileName);
- log.info("文件上传成功: {} ({}), 大小: {} KB, URL: {}",
- originalFilename, fileCategory, fileSize / 1024, fileUrl);
- return fileUrl;
- } catch (Exception e) {
- log.error("文件上传失败: {}", e.getMessage(), e);
- throw new IOException("文件上传失败: " + e.getMessage(), e);
- } finally {
- if (ossClient != null) {
- ossClient.shutdown();
- }
- }
- }
- private String generateUniqueFileName(String category, String extension) {
- return "uploads/" + category + "/" + UUID.randomUUID() + "." + extension;
- }
- private ObjectMetadata createMetadata(String filename, String contentType,
- long fileSize, String category) {
- ObjectMetadata metadata = new ObjectMetadata();
- // 设置基础元数据
- metadata.setContentType(contentType != null ? contentType : "application/octet-stream");
- metadata.setContentLength(fileSize);
- // 设置下载时的文件名
- if (filename != null) {
- metadata.setContentDisposition("attachment; filename=\"" + filename + "\"");
- }
- // 添加自定义元数据
- metadata.addUserMetadata("Original-Filename", filename != null ? filename : "");
- metadata.addUserMetadata("File-Category", category);
- return metadata;
- }
- private FileTypeInfo determineFileType(String filename, String contentType) {
- String extension = "bin";
- String category = "other";
- // 1. 尝试从文件名获取扩展名
- if (filename != null && filename.contains(".")) {
- String fileExt = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
- if (isValidExtension(fileExt)) {
- extension = fileExt;
- category = determineCategory(extension);
- }
- }
- // 2. 如果扩展名无效,尝试从内容类型获取
- if ("bin".equals(extension) && contentType != null) {
- // 使用映射表获取标准扩展名
- String mappedExt = MIME_TO_EXTENSION.get(contentType.toLowerCase());
- if (mappedExt != null) {
- extension = mappedExt;
- category = determineCategory(extension);
- }
- }
- // 3. 最终确定文件分类
- if ("other".equals(category)) {
- category = determineCategory(extension);
- }
- return new FileTypeInfo(extension, category);
- }
- private boolean isValidExtension(String ext) {
- // 检查扩展名是否有效(不含特殊字符)
- return ext.matches("[a-z0-9]{1,10}");
- }
- private String determineCategory(String extension) {
- if (extension.matches("png|jpe?g|gif|bmp|webp|svg|heic|heif")) {
- return "images";
- } else if (extension.matches("mp4|mov|avi|mkv|flv|webm|m4v|wmv|3gp")) {
- return "videos";
- } else if (extension.matches("mp3|wav|ogg|flac|aac|m4a|wma|amr")) {
- return "audios";
- } else if (extension.matches("pdf|docx?|xlsx?|pptx?|txt|rtf|csv|pages|numbers|key")) {
- return "documents";
- } else if (extension.matches("zip|rar|7z|tar|gz")) {
- return "archives";
- }
- return "other";
- }
- private String generateFileUrl(String fileName) {
- // 使用CDN加速域名(如果配置了),否则使用标准OSS域名
- if (useCDN && cdnDomain != null && !cdnDomain.isEmpty()) {
- return cdnDomain + "/" + fileName;
- }
- // 构建标准OSS域名
- String domain = endpoint.startsWith("http") ?
- endpoint : "https://" + endpoint;
- return domain.replaceFirst("://", "://" + bucketName + ".") + "/" + fileName;
- }
- // 文件类型信息辅助类
- private static class FileTypeInfo {
- private final String extension;
- private final String category;
- public FileTypeInfo(String extension, String category) {
- this.extension = extension;
- this.category = category;
- }
- public String getExtension() {
- return extension;
- }
- public String getCategory() {
- return category;
- }
- }
- }
|