当前位置: 首页 > news >正文

java设计模式-工厂模式(文件上传)

工厂模式是一种创建对象的设计模式,它将对象的创建和使用分离,通过一个工厂类来负责创建对象。
我以文件上传策略工厂为例

/*** 文件上传策略工厂*/
@Slf4j
@Component
public class FileUploadStrategyFactory {private final Map<String, FileUploadStrategy> strategyMap = new ConcurrentHashMap<>();@Autowiredpublic FileUploadStrategyFactory(List<FileUploadStrategy> strategies) {for (FileUploadStrategy strategy : strategies) {strategyMap.put(strategy.getType(), strategy);}}/*** 获取文件上传策略** @param type 策略类型* @return 文件上传策略*/public FileUploadStrategy getStrategy(String type) {FileUploadStrategy strategy = strategyMap.get(type);if (strategy == null) {throw new IllegalArgumentException("不支持的文件上传类型: " + type);}return strategy;}/*** 获取所有策略类型** @return 策略类型列表*/public java.util.Set<String> getAllTypes() {return strategyMap.keySet();}
} 
/*** 文件上传策略接口*/
public interface FileUploadStrategy {/*** 获取策略类型*/String getType();/*** 上传文件** @param file 文件* @param config OSS配置* @return 上传结果*/FileUploadResult upload(MultipartFile file, SysOssConfig config);/*** 上传文件流** @param inputStream 文件流* @param fileName 文件名* @param contentType 文件类型* @param config OSS配置* @return 上传结果*/FileUploadResult upload(InputStream inputStream, String fileName, String contentType, SysOssConfig config);/*** 删除文件** @param fileName 文件名* @param config OSS配置* @return 删除结果*/boolean delete(String fileName, SysOssConfig config);/*** 获取文件预签名URL** @param fileName 文件名* @param config OSS配置* @param expireTime 过期时间(秒)* @return 预签名URL*/String getPresignedUrl(String fileName, SysOssConfig config, int expireTime);/*** 获取文件下载流** @param fileName 文件名* @param config OSS配置* @return 文件输入流* @throws IOException IO异常*/InputStream getFileInputStream(String fileName, SysOssConfig config) throws IOException;/*** 获取文件预览信息** @param fileName 文件名* @param config OSS配置* @return 预览信息* @throws IOException IO异常*/FilePreviewInfo getPreviewInfo(String fileName, String originalName, String contentType, long size, SysOssConfig config) throws IOException;
}

MinIO文件上传策略

/*** MinIO文件上传策略*/
@Slf4j
@Component
public class MinioFileUploadStrategy implements FileUploadStrategy {@Overridepublic String getType() {return "minio";}@Overridepublic FileUploadResult upload(MultipartFile file, SysOssConfig config) {try {MinioClient minioClient = createMinioClient(config);String originalName = file.getOriginalFilename();String fileName = generateFileName(originalName);String objectName = buildObjectName(fileName, config);// 确保桶存在ensureBucketExists(minioClient, config.getBucketName());// 上传文件minioClient.putObject(PutObjectArgs.builder().bucket(config.getBucketName()).object(objectName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build());// 构建访问URLString url = buildAccessUrl(config, objectName);return new FileUploadResult().setFileName(fileName).setOriginalName(originalName).setFileSuffix(FileUtils.getFileExtension(originalName)).setUrl(url).setSize(file.getSize()).setFilePath(objectName).setContentType(file.getContentType()).setConfigKey(config.getConfigKey()).setUploadStatus(1);} catch (Exception e) {log.error("MinIO文件上传失败", e);throw new RuntimeException("MinIO文件上传失败: " + e.getMessage());}}@Overridepublic FileUploadResult upload(InputStream inputStream, String fileName, String contentType, SysOssConfig config) {try {MinioClient minioClient = createMinioClient(config);String objectName = buildObjectName(fileName, config);// 确保桶存在ensureBucketExists(minioClient, config.getBucketName());// 由于无法直接获取InputStream的大小,使用-1让MinIO自动处理minioClient.putObject(PutObjectArgs.builder().bucket(config.getBucketName()).object(objectName).stream(inputStream, -1, 10485760) // 10MB part size.contentType(contentType).build());// 获取文件信息StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(config.getBucketName()).object(objectName).build());// 构建访问URLString url = buildAccessUrl(config, objectName);return new FileUploadResult().setFileName(fileName).setOriginalName(fileName).setFileSuffix(FileUtils.getFileExtension(fileName)).setUrl(url).setSize(stat.size()).setFilePath(objectName).setContentType(contentType).setConfigKey(config.getConfigKey()).setUploadStatus(1);} catch (Exception e) {log.error("MinIO文件流上传失败", e);throw new RuntimeException("MinIO文件流上传失败: " + e.getMessage());}}@Overridepublic boolean delete(String fileName, SysOssConfig config) {try {MinioClient minioClient = createMinioClient(config);String objectName = config.getPrefix() + "/" + fileName;minioClient.removeObject(RemoveObjectArgs.builder().bucket(config.getBucketName()).object(objectName).build());return true;} catch (Exception e) {log.error("删除MinIO文件失败: {}", fileName, e);return false;}}@Overridepublic String getPresignedUrl(String fileName, SysOssConfig config, int expireTime) {try {MinioClient minioClient = createMinioClient(config);String objectName = config.getPrefix() + "/" + fileName;return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(config.getBucketName()).object(objectName).expiry(expireTime, TimeUnit.SECONDS).build());} catch (Exception e) {log.error("获取MinIO预签名URL失败: {}", fileName, e);return null;}}@Overridepublic InputStream getFileInputStream(String fileName, SysOssConfig config) throws IOException {try {MinioClient minioClient = createMinioClient(config);// 确保桶存在ensureBucketExists(minioClient, config.getBucketName());// 获取文件流return minioClient.getObject(GetObjectArgs.builder().bucket(config.getBucketName()).object(fileName).build());} catch (Exception e) {log.error("获取MinIO文件流失败: {}", e.getMessage(), e);throw new IOException("获取MinIO文件流失败: " + e.getMessage());}}@Overridepublic FilePreviewInfo getPreviewInfo(String fileName, String originalName, String contentType, long size, SysOssConfig config) throws IOException {try {MinioClient minioClient = createMinioClient(config);// 确保桶存在ensureBucketExists(minioClient, config.getBucketName());// 获取预签名URL,有效期10分钟String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(config.getBucketName()).object(fileName).method(Method.GET).expiry(10, TimeUnit.MINUTES).build());// 构建预览信息FilePreviewInfo previewInfo = new FilePreviewInfo().setPreviewUrl(url).setContentType(contentType).setOriginalName(originalName).setSize(size);// 设置预览类型if (isImageFile(contentType)) {// 图片直接预览previewInfo.setPreviewType(1);} else if (isPdfFile(contentType)) {// PDF直接预览previewInfo.setPreviewType(3);} else if (isOfficeFile(contentType)) {// Office文档需要预览服务previewInfo.setPreviewType(2);previewInfo.setNeedConvert(true);} else if (isVideoFile(contentType)) {// 视频文件previewInfo.setPreviewType(4);} else if (isAudioFile(contentType)) {// 音频文件previewInfo.setPreviewType(5);} else if (isTextFile(contentType, originalName)) {// 文本文件previewInfo.setPreviewType(6);} else {// 不支持预览previewInfo.setPreviewType(0);}return previewInfo;} catch (Exception e) {log.error("获取MinIO预览信息失败: {}", e.getMessage(), e);throw new IOException("获取MinIO预览信息失败: " + e.getMessage());}}/*** 判断是否为文本文件*/private boolean isTextFile(String contentType, String fileName) {// 根据内容类型判断if (contentType != null && (contentType.equals("text/plain") ||contentType.equals("text/html") ||contentType.equals("text/css") ||contentType.equals("text/javascript") ||contentType.equals("application/json") ||contentType.equals("application/xml"))) {return true;}// 根据文件扩展名判断if (fileName != null) {String lowerName = fileName.toLowerCase();return lowerName.endsWith(".txt") ||lowerName.endsWith(".log") ||lowerName.endsWith(".ini") ||lowerName.endsWith(".json") ||lowerName.endsWith(".xml") ||lowerName.endsWith(".md") ||lowerName.endsWith(".csv");}return false;}private MinioClient createMinioClient(SysOssConfig config) {return MinioClient.builder().endpoint(config.getEndpoint()).credentials(config.getAccessKey(), config.getSecretKey()).region(config.getRegion()).build();}private void ensureBucketExists(MinioClient minioClient, String bucketName) throws Exception {boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (!exists) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());log.info("创建MinIO桶: {}", bucketName);}}private String generateFileName(String originalName) {String extension = FileUtils.getFileExtension(originalName);String uuid = UUID.randomUUID().toString().replace("-", "");return uuid + (StringUtils.hasText(extension) ? "." + extension : "");}private String buildObjectName(String fileName, SysOssConfig config) {String prefix = StringUtils.hasText(config.getPrefix()) ? config.getPrefix() : "upload";String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));return prefix + "/" + datePath + "/" + fileName;}private String buildAccessUrl(SysOssConfig config, String objectName) {String baseUrl = config.getDomain();if (!StringUtils.hasText(baseUrl)) {baseUrl = config.getEndpoint();}// 确保URL以/结尾if (!baseUrl.endsWith("/")) {baseUrl += "/";}return baseUrl + config.getBucketName() + "/" + objectName;}/*** 判断是否为图片文件*/private boolean isImageFile(String contentType) {return contentType != null && contentType.startsWith("image/");}/*** 判断是否为PDF文件*/private boolean isPdfFile(String contentType) {return contentType != null && contentType.equals("application/pdf");}/*** 判断是否为Office文件*/private boolean isOfficeFile(String contentType) {if (contentType == null) return false;return contentType.contains("word") ||contentType.contains("excel") ||contentType.contains("powerpoint") ||contentType.contains("ms-excel") ||contentType.contains("ms-word") ||contentType.contains("ms-powerpoint") ||contentType.contains("openxmlformats");}/*** 判断是否为视频文件*/private boolean isVideoFile(String contentType) {return contentType != null && contentType.startsWith("video/");}/*** 判断是否为音频文件*/private boolean isAudioFile(String contentType) {return contentType != null && contentType.startsWith("audio/");}
}

阿里云OSS文件上传策略

/*** 阿里云OSS文件上传策略*/
@Slf4j
@Component
public class AliyunOssFileUploadStrategy implements FileUploadStrategy {@Overridepublic String getType() {return "aliyun";}@Overridepublic FileUploadResult upload(MultipartFile file, SysOssConfig config) {OSS ossClient = null;try {ossClient = createOssClient(config);String originalName = file.getOriginalFilename();String fileName = generateFileName(originalName);String objectName = buildObjectName(fileName, config);// 创建上传Object的MetadataObjectMetadata metadata = new ObjectMetadata();metadata.setContentLength(file.getSize());metadata.setContentType(file.getContentType());metadata.setCacheControl("no-cache");metadata.setHeader("Pragma", "no-cache");metadata.setContentDisposition("inline;filename=" + originalName);// 上传文件PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), objectName, file.getInputStream(), metadata);ossClient.putObject(putObjectRequest);// 构建访问URLString url = buildAccessUrl(config, objectName);return new FileUploadResult().setFileName(fileName).setOriginalName(originalName).setFileSuffix(FileUtils.getFileExtension(originalName)).setUrl(url).setSize(file.getSize()).setFilePath(objectName).setContentType(file.getContentType()).setConfigKey(config.getConfigKey()).setUploadStatus(1);} catch (Exception e) {log.error("阿里云OSS文件上传失败", e);throw new RuntimeException("阿里云OSS文件上传失败: " + e.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}@Overridepublic FileUploadResult upload(InputStream inputStream, String fileName, String contentType, SysOssConfig config) {OSS ossClient = null;try {ossClient = createOssClient(config);String objectName = buildObjectName(fileName, config);// 创建上传Object的MetadataObjectMetadata metadata = new ObjectMetadata();metadata.setContentType(contentType);metadata.setCacheControl("no-cache");metadata.setHeader("Pragma", "no-cache");metadata.setContentDisposition("inline;filename=" + fileName);// 上传文件PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), objectName, inputStream, metadata);ossClient.putObject(putObjectRequest);// 获取文件信息com.aliyun.oss.model.ObjectMetadata objMetadata = ossClient.getObjectMetadata(config.getBucketName(), objectName);long size = objMetadata.getContentLength();// 构建访问URLString url = buildAccessUrl(config, objectName);return new FileUploadResult().setFileName(fileName).setOriginalName(fileName).setFileSuffix(FileUtils.getFileExtension(fileName)).setUrl(url).setSize(size).setFilePath(objectName).setContentType(contentType).setConfigKey(config.getConfigKey()).setUploadStatus(1);} catch (Exception e) {log.error("阿里云OSS文件流上传失败", e);throw new RuntimeException("阿里云OSS文件流上传失败: " + e.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}@Overridepublic boolean delete(String fileName, SysOssConfig config) {OSS ossClient = null;try {ossClient = createOssClient(config);String objectName = config.getPrefix() + "/" + fileName;ossClient.deleteObject(config.getBucketName(), objectName);return true;} catch (Exception e) {log.error("删除阿里云OSS文件失败: {}", fileName, e);return false;} finally {if (ossClient != null) {ossClient.shutdown();}}}@Overridepublic String getPresignedUrl(String fileName, SysOssConfig config, int expireTime) {OSS ossClient = null;try {ossClient = createOssClient(config);String objectName = config.getPrefix() + "/" + fileName;// 设置过期时间Date expiration = new Date(System.currentTimeMillis() + expireTime * 1000L);return ossClient.generatePresignedUrl(config.getBucketName(), objectName, expiration).toString();} catch (Exception e) {log.error("获取阿里云OSS预签名URL失败: {}", fileName, e);return null;} finally {if (ossClient != null) {ossClient.shutdown();}}}@Overridepublic InputStream getFileInputStream(String fileName, SysOssConfig config) throws IOException {OSS ossClient = null;try {ossClient = createOssClient(config);// 获取文件流OSSObject ossObject = ossClient.getObject(config.getBucketName(), fileName);return ossObject.getObjectContent();} catch (Exception e) {log.error("获取阿里云OSS文件流失败: {}", e.getMessage(), e);throw new IOException("获取阿里云OSS文件流失败: " + e.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}@Overridepublic FilePreviewInfo getPreviewInfo(String fileName, String originalName, String contentType, long size, SysOssConfig config) throws IOException {OSS ossClient = null;try {ossClient = createOssClient(config);// 检查文件是否存在boolean exists = ossClient.doesObjectExist(config.getBucketName(), fileName);if (!exists) {log.error("阿里云OSS文件不存在: {}", fileName);throw new IOException("文件不存在: " + fileName);}// 获取签名URL,默认10分钟有效期Date expiration = new Date(System.currentTimeMillis() + 10 * 60 * 1000);GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(config.getBucketName(), fileName);request.setExpiration(expiration);URL signedUrl = ossClient.generatePresignedUrl(request);String url = signedUrl.toString();// 构建预览信息FilePreviewInfo previewInfo = new FilePreviewInfo().setPreviewUrl(url).setContentType(contentType).setOriginalName(originalName).setSize(size);// 设置预览类型if (isImageFile(contentType)) {// 图片直接预览previewInfo.setPreviewType(1);} else if (isPdfFile(contentType)) {// PDF直接预览previewInfo.setPreviewType(3);} else if (isOfficeFile(contentType)) {// Office文档需要预览服务previewInfo.setPreviewType(2);previewInfo.setNeedConvert(true);} else if (isVideoFile(contentType)) {// 视频文件previewInfo.setPreviewType(4);} else if (isAudioFile(contentType)) {// 音频文件previewInfo.setPreviewType(5);} else if (isTextFile(contentType, originalName)) {// 文本文件previewInfo.setPreviewType(6);} else {// 不支持预览previewInfo.setPreviewType(0);}return previewInfo;} catch (Exception e) {log.error("获取阿里云OSS预览信息失败: {}", e.getMessage(), e);throw new IOException("获取阿里云OSS预览信息失败: " + e.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}/*** 判断是否为文本文件*/private boolean isTextFile(String contentType, String fileName) {// 根据内容类型判断if (contentType != null && (contentType.equals("text/plain") ||contentType.equals("text/html") ||contentType.equals("text/css") ||contentType.equals("text/javascript") ||contentType.equals("application/json") ||contentType.equals("application/xml"))) {return true;}// 根据文件扩展名判断if (fileName != null) {String lowerName = fileName.toLowerCase();return lowerName.endsWith(".txt") ||lowerName.endsWith(".log") ||lowerName.endsWith(".ini") ||lowerName.endsWith(".json") ||lowerName.endsWith(".xml") ||lowerName.endsWith(".md") ||lowerName.endsWith(".csv");}return false;}private OSS createOssClient(SysOssConfig config) {String endpoint = config.getEndpoint();if (config.getIsHttps() != null && config.getIsHttps() == 1) {if (!endpoint.startsWith("https://")) {endpoint = "https://" + endpoint.replace("http://", "");}} else {if (!endpoint.startsWith("http://")) {endpoint = "http://" + endpoint.replace("https://", "");}}return new OSSClientBuilder().build(endpoint, config.getAccessKey(), config.getSecretKey());}private String generateFileName(String originalName) {String extension = FileUtils.getFileExtension(originalName);String uuid = UUID.randomUUID().toString().replace("-", "");return uuid + (StringUtils.hasText(extension) ? "." + extension : "");}private String buildObjectName(String fileName, SysOssConfig config) {String prefix = StringUtils.hasText(config.getPrefix()) ? config.getPrefix() : "upload";String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));return prefix + "/" + datePath + "/" + fileName;}private String buildAccessUrl(SysOssConfig config, String objectName) {String baseUrl = config.getDomain();if (!StringUtils.hasText(baseUrl)) {String endpoint = config.getEndpoint();if (config.getIsHttps() != null && config.getIsHttps() == 1) {baseUrl = "https://" + config.getBucketName() + "." + endpoint.replace("https://", "").replace("http://", "");} else {baseUrl = "http://" + config.getBucketName() + "." + endpoint.replace("https://", "").replace("http://", "");}}// 确保URL以/结尾if (!baseUrl.endsWith("/")) {baseUrl += "/";}return baseUrl + objectName;}/*** 判断是否为图片文件*/private boolean isImageFile(String contentType) {return contentType != null && contentType.startsWith("image/");}/*** 判断是否为PDF文件*/private boolean isPdfFile(String contentType) {return contentType != null && contentType.equals("application/pdf");}/*** 判断是否为Office文件*/private boolean isOfficeFile(String contentType) {if (contentType == null) return false;return contentType.contains("word") ||contentType.contains("excel") ||contentType.contains("powerpoint") ||contentType.contains("ms-excel") ||contentType.contains("ms-word") ||contentType.contains("ms-powerpoint") ||contentType.contains("openxmlformats");}/*** 判断是否为视频文件*/private boolean isVideoFile(String contentType) {return contentType != null && contentType.startsWith("video/");}/*** 判断是否为音频文件*/private boolean isAudioFile(String contentType) {return contentType != null && contentType.startsWith("audio/");}
}

本地文件上传策略

/*** 本地文件上传策略*/
@Slf4j
@Component
public class LocalFileUploadStrategy implements FileUploadStrategy {@Value("${file.upload.path:./upload}")private String uploadPath;@Value("${server.servlet.context-path:}")private String contextPath;@Value("${server.port:8080}")private String serverPort;@Overridepublic String getType() {return "local";}@Overridepublic FileUploadResult upload(MultipartFile file, SysOssConfig config) {try {// 初始化上传路径initUploadPath();String originalName = file.getOriginalFilename();String fileName = generateFileName(originalName);String filePath = buildFilePath(fileName, config);String fullPath = getNormalizedPath(uploadPath, filePath);log.info("保存文件到: {}", fullPath);// 创建目录createDirectories(fullPath);// 保存文件File targetFile = new File(fullPath);try {file.transferTo(targetFile);} catch (IOException e) {log.error("保存文件失败: {}", e.getMessage());// 尝试使用替代方法保存try (FileOutputStream out = new FileOutputStream(targetFile)) {out.write(file.getBytes());}}// 确认文件已保存成功if (!targetFile.exists()) {throw new IOException("文件保存失败,无法在目标路径找到文件: " + targetFile.getAbsolutePath());}// 构建访问URLString url = buildAccessUrl(filePath);return new FileUploadResult().setFileName(fileName).setOriginalName(originalName).setFileSuffix(FileUtils.getFileExtension(originalName)).setUrl(url).setSize(file.getSize()).setFilePath(filePath).setContentType(file.getContentType()).setConfigKey(config.getConfigKey()).setUploadStatus(1);} catch (IOException e) {log.error("本地文件上传失败: {}", e.getMessage(), e);throw new RuntimeException("本地文件上传失败: " + e.getMessage());}}@Overridepublic FileUploadResult upload(InputStream inputStream, String fileName, String contentType, SysOssConfig config) {try {// 初始化上传路径initUploadPath();String filePath = buildFilePath(fileName, config);String fullPath = getNormalizedPath(uploadPath, filePath);log.info("保存文件流到: {}", fullPath);// 创建目录createDirectories(fullPath);// 保存文件File targetFile = new File(fullPath);try (FileOutputStream outputStream = new FileOutputStream(targetFile)) {byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}}// 获取文件大小long size = targetFile.length();// 构建访问URLString url = buildAccessUrl(filePath);return new FileUploadResult().setFileName(fileName).setOriginalName(fileName).setFileSuffix(FileUtils.getFileExtension(fileName)).setUrl(url).setSize(size).setFilePath(filePath).setContentType(contentType).setConfigKey(config.getConfigKey()).setUploadStatus(1);} catch (IOException e) {log.error("本地文件流上传失败: {}", e.getMessage(), e);throw new RuntimeException("本地文件流上传失败: " + e.getMessage());}}@Overridepublic boolean delete(String fileName, SysOssConfig config) {try {String filePath = config.getPrefix() + File.separator + fileName;String fullPath = getNormalizedPath(uploadPath, filePath);File file = new File(fullPath);if (file.exists()) {return file.delete();}return true;} catch (Exception e) {log.error("删除本地文件失败: {}", fileName, e);return false;}}@Overridepublic String getPresignedUrl(String fileName, SysOssConfig config, int expireTime) {// 本地存储不需要预签名URL,直接返回访问URLString filePath = config.getPrefix() + File.separator + fileName;return buildAccessUrl(filePath);}@Overridepublic InputStream getFileInputStream(String fileName, SysOssConfig config) throws IOException {String fullPath = getNormalizedPath(uploadPath, fileName);log.debug("获取文件流: {}", fullPath);File file = new File(fullPath);if (!file.exists() || !file.isFile()) {log.error("文件不存在: {}", fullPath);throw new IOException("文件不存在: " + fileName);}return new FileInputStream(file);}@Overridepublic FilePreviewInfo getPreviewInfo(String fileName, String originalName, String contentType, long size, SysOssConfig config) throws IOException {String fullPath = getNormalizedPath(uploadPath, fileName);File file = new File(fullPath);if (!file.exists() || !file.isFile()) {log.error("文件不存在: {}", fullPath);throw new IOException("文件不存在: " + fileName);}// 构建URLString url = buildAccessUrl(fileName);// 判断文件类型,确定预览类型FilePreviewInfo previewInfo = new FilePreviewInfo().setPreviewUrl(url).setContentType(contentType).setOriginalName(originalName).setSize(size);// 设置预览类型if (isImageFile(contentType)) {// 图片直接预览previewInfo.setPreviewType(1);} else if (isPdfFile(contentType)) {// PDF直接预览previewInfo.setPreviewType(3);} else if (isOfficeFile(contentType)) {// Office文档需要预览服务previewInfo.setPreviewType(2);previewInfo.setNeedConvert(true);} else if (isVideoFile(contentType)) {// 视频文件previewInfo.setPreviewType(4);} else if (isAudioFile(contentType)) {// 音频文件previewInfo.setPreviewType(5);} else if (isTextFile(contentType, originalName)) {// 文本文件previewInfo.setPreviewType(6);} else {// 不支持预览previewInfo.setPreviewType(0);}return previewInfo;}private String generateFileName(String originalName) {String extension = FileUtils.getFileExtension(originalName);String uuid = UUID.randomUUID().toString().replace("-", "");return uuid + (StringUtils.hasText(extension) ? "." + extension : "");}private String buildFilePath(String fileName, SysOssConfig config) {// 直接使用日期路径,不添加额外的前缀,避免重复的upload目录String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));return datePath + File.separator + fileName;}/*** 初始化上传根目录*/private void initUploadPath() throws IOException {File uploadDir = new File(uploadPath);if (!uploadDir.exists()) {log.info("创建上传根目录: {}", uploadPath);if (!uploadDir.mkdirs()) {throw new IOException("无法创建上传根目录: " + uploadPath);}}}/*** 获取规范化的完整路径*/private String getNormalizedPath(String basePath, String relativePath) {// 确保基础路径不以分隔符结尾if (basePath.endsWith(File.separator)) {basePath = basePath.substring(0, basePath.length() - 1);}// 确保相对路径不以分隔符开头if (relativePath.startsWith(File.separator)) {relativePath = relativePath.substring(1);}// 组合并规范化路径Path path = Paths.get(basePath, relativePath).normalize();return path.toString();}private void createDirectories(String fullPath) throws IOException {try {Path path = Paths.get(fullPath).getParent();if (path != null && !Files.exists(path)) {log.info("创建目录: {}", path);Files.createDirectories(path);}} catch (IOException e) {log.error("创建目录失败: {}", e.getMessage(), e);// 尝试使用File API创建目录File directory = new File(Paths.get(fullPath).getParent().toString());if (!directory.exists() && !directory.mkdirs()) {throw new IOException("无法创建目录: " + directory.getAbsolutePath());}}}private String buildAccessUrl(String filePath) {// 构建完整的访问URLString baseUrl = "";// 获取当前主机名和端口baseUrl = "http://localhost:" + serverPort;if (StringUtils.hasText(contextPath) && !contextPath.equals("/")) {baseUrl += contextPath;}// 将Windows风格的路径分隔符替换为URL路径分隔符String normalizedPath = filePath.replace(File.separator, "/");return baseUrl + "/file/" + normalizedPath;}/*** 判断是否为图片文件*/private boolean isImageFile(String contentType) {return contentType != null && contentType.startsWith("image/");}/*** 判断是否为PDF文件*/private boolean isPdfFile(String contentType) {return contentType != null && contentType.equals("application/pdf");}/*** 判断是否为Office文件*/private boolean isOfficeFile(String contentType) {if (contentType == null) return false;return contentType.contains("word") ||contentType.contains("excel") ||contentType.contains("powerpoint") ||contentType.contains("ms-excel") ||contentType.contains("ms-word") ||contentType.contains("ms-powerpoint") ||contentType.contains("openxmlformats");}/*** 判断是否为视频文件*/private boolean isVideoFile(String contentType) {return contentType != null && contentType.startsWith("video/");}/*** 判断是否为音频文件*/private boolean isAudioFile(String contentType) {return contentType != null && contentType.startsWith("audio/");}/*** 判断是否为文本文件*/private boolean isTextFile(String contentType, String fileName) {// 根据内容类型判断if (contentType != null && (contentType.equals("text/plain") ||contentType.equals("text/html") ||contentType.equals("text/css") ||contentType.equals("text/javascript") ||contentType.equals("application/json") ||contentType.equals("application/xml"))) {return true;}// 根据文件扩展名判断if (fileName != null) {String lowerName = fileName.toLowerCase();return lowerName.endsWith(".txt") ||lowerName.endsWith(".log") ||lowerName.endsWith(".ini") ||lowerName.endsWith(".json") ||lowerName.endsWith(".xml") ||lowerName.endsWith(".md") ||lowerName.endsWith(".csv");}return false;}
}


FileUploadStrategyFactory 就是工厂类,它负责创建和管理不同类型的 FileUploadStrategy 对象。FileUploadStrategy 是一个接口,定义了文件上传策略的通用方法,而 AliyunOssFileUploadStrategy 等实现类则是具体的策略实现。

FileUploadStrategyFactory 类通过一个 Map 来存储不同类型的 FileUploadStrategy 对象,键是策略类型(如 "aliyun"),值是对应的策略对象。这样,当需要使用某个具体的文件上传策略时,只需要通过策略类型从工厂类中获取对应的策略对象即可,而不需要直接实例化具体的策略类。

FileUploadStrategyFactory 构造方法的含义和触发机制

    @Autowiredpublic FileUploadStrategyFactory(List<FileUploadStrategy> strategies) {for (FileUploadStrategy strategy : strategies) {strategyMap.put(strategy.getType(), strategy);}}

当 Spring 容器启动时,它会自动扫描所有的组件(使用 @Component@Service 等注解标记的类),并创建这些组件的实例。在创建 FileUploadStrategyFactory 实例时,Spring 会根据 @Autowired 注解的要求,自动查找所有实现了 FileUploadStrategy 接口的 Bean,并将它们作为一个 List 注入到 FileUploadStrategyFactory 的构造方法中。

我有三个不同的 FileUploadStrategy 实现类:AliyunOssFileUploadStrategy、LocalFileUploadStrategy 和 MinioFileUploadStrategy,Spring 容器会自动创建这三个类的实例,并将它们作为一个 List 注入到 FileUploadStrategyFactory 的构造方法中。然后,FileUploadStrategyFactory 会将这三个策略对象存储在 strategyMap 中,以便后续使用。


文章转载自:

http://rJg7c5pw.nynyj.cn
http://Rc3ck8gG.nynyj.cn
http://v0KgStJi.nynyj.cn
http://ZbdR5YNs.nynyj.cn
http://1zkYLF5h.nynyj.cn
http://jwYkPxwX.nynyj.cn
http://VbizNrqU.nynyj.cn
http://71MccJED.nynyj.cn
http://C0Kxhl52.nynyj.cn
http://6Y52Kz5M.nynyj.cn
http://HCiUhr8W.nynyj.cn
http://A2xwH5vM.nynyj.cn
http://4kMvn2WP.nynyj.cn
http://P79CJXWM.nynyj.cn
http://WNeeidMH.nynyj.cn
http://0yw0549g.nynyj.cn
http://B6ePCnCw.nynyj.cn
http://lAscJqEb.nynyj.cn
http://j4gBaeWN.nynyj.cn
http://wGqcDfTU.nynyj.cn
http://NyBFSM7H.nynyj.cn
http://a1w2OMpE.nynyj.cn
http://LQ0jWbHk.nynyj.cn
http://8Nofs5lA.nynyj.cn
http://nY7UKec8.nynyj.cn
http://cTZOmVjQ.nynyj.cn
http://3Z5aMZpd.nynyj.cn
http://sFnsKavS.nynyj.cn
http://nJv9KyNC.nynyj.cn
http://OXq1YzZd.nynyj.cn
http://www.dtcms.com/a/386967.html

相关文章:

  • Keras+Flask手写数字识别Web应用
  • PPTist+cpolar:开源演示文稿的远程创作方案
  • Chapter8—组合模式
  • vmware的ub系统长时间不动会黑屏
  • 从0到1打造一个能上传任意GeoJSON的交互式Web地图
  • 深入理解数据结构之复杂度
  • Silicon EFR32xG22 CMU
  • 运维面试笔记(持续补充版)
  • 托福阅读35-1
  • qt QCandlestickSet详解
  • 在Linux和Windows系统下使用Qt监测U盘的插拔事件
  • 文字识别接口的应用场景-发票识别接口-OCR API
  • 鸿蒙NEXT ArkWeb同层渲染:原生与Web的完美融合
  • 基于springboot的4s店汽车销售服务系统
  • ARM芯片的调试访问端口 DAP(Debug Access Port)
  • 减少推导式中的重复计算:赋值表达式(:=)的优雅应用 (Effective Python 第29条)
  • 空压机远程控制与数据采集的御控物联网解决方案
  • 瑞萨MCU RA4M1 FLASH锁死问题记录
  • Kubernetes 调度器(Scheduler)
  • Java设计模型-责任链模式
  • Linux 服务器安全优化:firewalld SSH 限制 白名单与 SCP 服务禁用流程
  • bisheng 智能体
  • 学完Python之后我写了一个免费看电影的软件
  • 【ROS2】Concept(Advanced )
  • Apifox自动化测试场景设计
  • 知识复用缺乏跨角色适配该如何改善
  • XML 与 YML 全方位对比:从语法到应用场景
  • pandas方法集
  • PAT乙级_1106 2019数列_Python_AC解法_含疑难点
  • 自动检测并交互删除未使用 Docker 自定义网桥