92 lines
3.1 KiB
Java
92 lines
3.1 KiB
Java
|
|
package com.ga.common.file;
|
||
|
|
|
||
|
|
import com.ga.common.exception.BizException;
|
||
|
|
import com.ga.common.exception.ErrorCode;
|
||
|
|
import com.ga.common.util.SecurityUtil;
|
||
|
|
import lombok.RequiredArgsConstructor;
|
||
|
|
import lombok.extern.slf4j.Slf4j;
|
||
|
|
import org.springframework.beans.factory.annotation.Value;
|
||
|
|
import org.springframework.stereotype.Service;
|
||
|
|
import org.springframework.transaction.annotation.Transactional;
|
||
|
|
import org.springframework.web.multipart.MultipartFile;
|
||
|
|
|
||
|
|
import java.io.IOException;
|
||
|
|
import java.nio.file.Files;
|
||
|
|
import java.nio.file.Path;
|
||
|
|
import java.nio.file.Paths;
|
||
|
|
import java.time.LocalDate;
|
||
|
|
import java.util.List;
|
||
|
|
import java.util.UUID;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 파일 업로드/다운로드. 로컬 파일시스템 저장 (S3 등으로 교체 가능한 구조).
|
||
|
|
*/
|
||
|
|
@Slf4j
|
||
|
|
@Service
|
||
|
|
@RequiredArgsConstructor
|
||
|
|
public class FileService {
|
||
|
|
|
||
|
|
private final FileMapper mapper;
|
||
|
|
|
||
|
|
@Value("${ga.file.upload-dir:./uploads}")
|
||
|
|
private String uploadDir;
|
||
|
|
|
||
|
|
@Transactional
|
||
|
|
public FileVO upload(MultipartFile file, String fileGroup) {
|
||
|
|
if (file == null || file.isEmpty()) {
|
||
|
|
throw new BizException(ErrorCode.FILE_UPLOAD_FAIL, "빈 파일입니다");
|
||
|
|
}
|
||
|
|
String original = file.getOriginalFilename();
|
||
|
|
if (original == null) original = "unknown";
|
||
|
|
String ext = extension(original);
|
||
|
|
String stored = UUID.randomUUID() + (ext.isEmpty() ? "" : "." + ext);
|
||
|
|
String relPath = LocalDate.now().toString().replace("-", "/");
|
||
|
|
Path dir = Paths.get(uploadDir, relPath);
|
||
|
|
try {
|
||
|
|
Files.createDirectories(dir);
|
||
|
|
Path dest = dir.resolve(stored);
|
||
|
|
file.transferTo(dest.toFile());
|
||
|
|
|
||
|
|
FileVO vo = new FileVO();
|
||
|
|
vo.setFileGroup(fileGroup);
|
||
|
|
vo.setOriginalName(original);
|
||
|
|
vo.setStoredName(stored);
|
||
|
|
vo.setFilePath(dest.toAbsolutePath().toString());
|
||
|
|
vo.setFileSize(file.getSize());
|
||
|
|
vo.setContentType(file.getContentType());
|
||
|
|
vo.setExtension(ext);
|
||
|
|
vo.setCreatedBy(SecurityUtil.getCurrentUserId());
|
||
|
|
vo.setCreatedAt(java.time.LocalDateTime.now());
|
||
|
|
mapper.insert(vo);
|
||
|
|
return vo;
|
||
|
|
} catch (IOException e) {
|
||
|
|
log.error("File upload error", e);
|
||
|
|
throw new BizException(ErrorCode.FILE_UPLOAD_FAIL, e.getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public FileVO download(Long fileId) {
|
||
|
|
FileVO vo = mapper.selectById(fileId);
|
||
|
|
if (vo == null) throw new BizException(ErrorCode.FILE_NOT_FOUND);
|
||
|
|
mapper.incrementDownloadCount(fileId);
|
||
|
|
return vo;
|
||
|
|
}
|
||
|
|
|
||
|
|
public List<FileVO> listByGroup(String fileGroup) {
|
||
|
|
return mapper.selectByGroup(fileGroup);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Transactional
|
||
|
|
public void delete(Long fileId) {
|
||
|
|
FileVO vo = mapper.selectById(fileId);
|
||
|
|
if (vo == null) throw new BizException(ErrorCode.FILE_NOT_FOUND);
|
||
|
|
mapper.markDeleted(fileId);
|
||
|
|
// 물리 삭제는 배치로 처리
|
||
|
|
}
|
||
|
|
|
||
|
|
private String extension(String name) {
|
||
|
|
int idx = name.lastIndexOf('.');
|
||
|
|
return idx >= 0 ? name.substring(idx + 1).toLowerCase() : "";
|
||
|
|
}
|
||
|
|
}
|