diff --git a/examples/chapter07/paopao/src/main/java/com/lk/paopao/service/AttachService.java b/examples/chapter07/paopao/src/main/java/com/lk/paopao/service/AttachService.java new file mode 100644 index 0000000..9d63dde --- /dev/null +++ b/examples/chapter07/paopao/src/main/java/com/lk/paopao/service/AttachService.java @@ -0,0 +1,128 @@ +package com.lk.paopao.service; + +import com.lk.paopao.dto.AttachmentDto; +import com.lk.paopao.entity.Attachment; +import com.lk.paopao.entity.User; +import com.lk.paopao.mapper.AttachmentMapper; +import com.lk.paopao.repository.AttachmentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Service +public class AttachService { + + // 从配置中获取上传路径 + @Value("${app.upload.path}") + String UPLOAD_DIR; + + // 从配置中获取子路径名长度,用于文件分目录存储 + @Value("${app.upload.sub-path-name-length}") + int SUB_PATH_LENGTH = 1; + + @Autowired + AuthService authService; + @Autowired + AttachmentRepository attachmentRepository; + @Autowired + AttachmentMapper attachmentMapper; + + + /** + * 上传附件 + * @param file 文件 + * @param attachType 附件类型 + * @return AttachmentDto + * @throws IOException 输入输出异常 + */ + public AttachmentDto upload(MultipartFile file) throws IOException { + // 获取原始文件名 + String originFileName = file.getOriginalFilename(); + if(originFileName == null){ + throw new IllegalArgumentException("没有原始文件名"); + } + + InputStream inputStream = file.getInputStream(); + // 获取当前用户 + User currentUser = authService.getCurrentUser(); + // 上传文件并获取相对URL + String relativeUrl = save(originFileName,inputStream); + Attachment attachment = new Attachment(); + // 设置附件类型 + attachment.setType(getType(file.getContentType())); + // 设置附件内容(即存储的URL) + attachment.setContent(relativeUrl); + // 关联用户 + attachment.setUser(currentUser); + // 设置文件大小 + attachment.setFileSize(file.getSize()); + // 保存附件 + Attachment savedAttachment = attachmentRepository.save(attachment); + // 转换并返回附件DTO + return attachmentMapper.toDto(savedAttachment); + } + + + /** + * 保存文件到上传目录中 + * @param fileName 原文件名 + * @param fileStream 文件流 + * @return 保存后的文件访问路径 + * @throws IOException 文件操作异常 + */ + public String save(String fileName, InputStream fileStream) throws IOException { + // 生成新的文件名以避免重复 + String rename = UUID.randomUUID().toString(); + int dotIndex = fileName.lastIndexOf('.'); + // 新文件名,包含扩展名 + String newFile = rename+((dotIndex > 0) ? "."+fileName.substring(dotIndex + 1) : ""); + + // 根据子路径长度计算文件保存的子目录 + String subPath = rename.substring(0,SUB_PATH_LENGTH); + // 完整的保存路径 + String uploadPath = UPLOAD_DIR+"/"+subPath; + + // 确保目录存在,不存在则创建 + Path directory = Paths.get(uploadPath); + if (!Files.exists(directory)) { + Files.createDirectories(directory); + } + // 文件的最终保存位置 + Path targetLocation = Paths.get(uploadPath, newFile); + // 复制文件流到目标位置 + Files.copy(fileStream, targetLocation); + // 返回文件的访问路径 + return "/"+subPath+"/"+newFile; + } + + /** + * 根据文件的MIME类型返回文件类型标识 + * @param contentType 文件的MIME类型 + * @return 文件类型的标识字节,0表示未知类型 + */ + public static byte getType(String contentType) { + + if(contentType == null){ + return 0; + } + if(contentType.startsWith("image/")){ + return 1; + } + if(contentType.startsWith("video/")){ + return 2; + } + + return 3; + } +} + diff --git a/examples/chapter07/paopao/src/main/resources/application.yml b/examples/chapter07/paopao/src/main/resources/application.yml index 096af03..29094d0 100644 --- a/examples/chapter07/paopao/src/main/resources/application.yml +++ b/examples/chapter07/paopao/src/main/resources/application.yml @@ -20,4 +20,10 @@ spring: defer-datasource-initialization: true database-platform: org.hibernate.dialect.H2Dialect hibernate: - ddl-auto: update \ No newline at end of file + ddl-auto: update + + +app: + upload: + path: ./upload + sub-path-name-length: 1 \ No newline at end of file