일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- google font icon
- 웹서비스 배포
- 웹개발
- 초보 개발자
- 구글 간편 로그인
- 검색 기능
- firebase storage
- 초성 검색
- CloudType
- 웹 개발
- Github Actions
- CI/CD
- 카카오 간편 로그인
- 욕설 및 비속어 필터링
- 파일 업로드
- Stomp
- 네이버 간편 로그인
- 크롬 확장 프로그램
- 1인 개발
- perspective api
- 웹소켓
- 무한 스크롤
- Today
- Total
J2ong 님의 블로그
Spring + React 파일 업로드 통합 구현 (korean-romanizer 라이브러리를 활용한 한글 파일명 오류 해결) 본문
Spring + React 파일 업로드 통합 구현 (korean-romanizer 라이브러리를 활용한 한글 파일명 오류 해결)
J2ong 2025. 4. 21. 17:51안녕하세요!
이번 글에서는 Spring Boot와 React 환경에서 파일 업로드 기능을 구현하는 방법을 공유합니다. 특히 한글 파일명을 업로드할 때 생길 수 있는 문제를 해결하는 방법도 함께 다룹니다.
📌 Spring 파일 업로드 및 로컬 저장
한글 파일명 문제 해결
한글 파일명을 그대로 저장하면 시스템에 따라 파일 접근 시 문제가 생길 수 있습니다. 이를 해결하기 위해 korean-romanizer 라이브러리를 사용해 로마자로 변환해줍니다.
자세한 설명은 korean-romanizer 문서를 확인해주세요.
GitHub - crizin/korean-romanizer: 한국어를 입력하면 로마자로 변환해주는 Java 라이브러리
한국어를 입력하면 로마자로 변환해주는 Java 라이브러리. Contribute to crizin/korean-romanizer development by creating an account on GitHub.
github.com
gradle 설정
Maven 중심의 문서가 제공되지만, Gradle 환경에서는 다음과 같이 추가해줍니다.
버전은 mvn repository에서 확인 가능합니다.
https://mvnrepository.com/artifact/net.crizin/korean-romanizer
implementation 'net.crizin:korean-romanizer:jar:2.0.1'
application.propertice
file.path=D:/fileUpload/
file.url=http://localhost:8080/file/
- file.path: 실제 파일이 저장될 경로
- 예) file.path=D:/fileUpload/
- file.url: 클라이언트가 접근할 파일 URL
- 예) file.url=http://localhost:8080/file/
Service (파일 업로드)
@Value("${file.path}")
private String filePath;
@Value("${file.url}")
private String fileUrl;
@Override
@Transactional
public String upload(MultipartFile file) {
if (file.isEmpty()) return null;
String originalFileName = file.getOriginalFilename();
String fileNameWithoutExt = originalFileName.substring(0, originalFileName.lastIndexOf("."));
String ext = originalFileName.substring(originalFileName.lastIndexOf("."));
// 1. 로마자로 변환
String romanized = KoreanRomanizer.romanize(fileNameWithoutExt);
// 2. 특수문자 제거
String sanitized = romanized.replaceAll("[^a-zA-Z0-9]", "_");
String uuid = UUID.randomUUID().toString();
// 3. UUID와 합쳐 저장할 이름 생성
String saveFileName = uuid + "_" + sanitized + ext;
String savePath = filePath + saveFileName;
try {
file.transferTo(new File(savePath));
} catch (Exception exception) {
exception.printStackTrace();
return null;
}
String url = fileUrl + saveFileName;
return url;
}
- 파일명을 로마자로 변환 → 특수문자 제거 → UUID 추가 → 저장
- 업로드된 파일 URL 반환
Service (파일 다운로드)
@Override
public Resource getFile(String fileName) {
Resource resource = null;
try {
resource = new UrlResource("file:" + filePath + fileName);
} catch (Exception exception) {
exception.printStackTrace();
return null;
}
return resource;
}
Controller
@PostMapping("/upload")
public String upload (
@RequestParam("file") MultipartFile file
) {
String url = fileService.upload(file);
return url;
}
@GetMapping(value = "{fileName}", produces = {
MediaType.IMAGE_JPEG_VALUE,
MediaType.IMAGE_PNG_VALUE,
MediaType.APPLICATION_PDF_VALUE,
MediaType.APPLICATION_OCTET_STREAM_VALUE
})
public Resource getFile (
@PathVariable("fileName") String fileName
) {
Resource resource = fileService.getFile(fileName);
return resource;
}
- MediaType 설명:
MediaType 상수 | 설명 |
MediaType.IMAGE_JPEG_VALUE | JPEG 이미지 파일 형식 (예: .jpg, .jpeg) |
MediaType.IMAGE_PNG_VALUE | PNG 이미지 파일 형식 (예: .png) |
MediaType.APPLICATION_PDF_VALUE | PDF 문서 형식 (예: .pdf) |
MediaType.APPLICATION_OCTET_STREAM_VALUE | 일반적인 바이너리 파일 형식. MIME 타입이 정확히 지정되지 않은 파일도 이 형식으로 반환 가능 |
📌 Postman 테스트
백엔드 코드를 완성했으니 제대로 동작하는지 postman을 통해 테스트를 진행하겠습니다.
이미지는 구글에서 임의로 검색후 진행하겠습니다.
API 요청 (업로드)
POST http://{서버 URL}/upload
- Body → form-data
- Key: file
- Type: File
- Value: 업로드할 파일
응답으로 업로드된 파일의 URL 문자열이 반환되면 성공입니다.
지정한 file.path 위치에 이미지가 잘 저장되는지 확인
API 요청 (파일 가져오기)
GET http://{서버 URL}/{파일명}
업로드 시 반환된 URL 경로에서 마지막 "/" 이후 경로만(확장자명 포함) 추출해 테스트하세요.
응답이 성공적으로 반환되는지 확인합니다.
📌 React 파일 업로드
API 요청 (Axios)
const FILE_UPLOAD_URL = () => `${DOMAIN}/upload`;
const multipartFormData = { headers: { 'Content-Type': 'multipart/form-data' } };
export const fileUploadRequest = async (data: FormData) => {
const result = await axios.post(FILE_UPLOAD_URL(), data, multipartFormData)
.then(response => {
const responseBody: string = response.data;
return responseBody;
})
.catch(error => {
return null;
})
return result;
}
파일 업로드 함수
const onFileUploadHandler = (event: ChangeEvent<HTMLInputElement>) => {
if (!event.target.files || !event.target.files.length) return;
const file = event.target.files[0];
const data = new FormData();
data.append('file', file);
fileUploadRequest(data)
.then(url => {
if (url) {
console.log("업로드된 파일 URL:", url);
// 상태 저장 or 미리보기 렌더링 가능
}
});
}
업로드 입력 필드
<input ref={fileInputRef} type="file" accept='image/*' style={{ display: 'none' }} onChange={onFileUploadHandler} />
버튼 클릭 시 fileInputRef.current.click()을 호출하면 사용자에게 파일 선택창을 열 수 있습니다.
이제 Spring + React 환경에서 한글 파일명도 안정적으로 처리되는 파일 업로드 기능을 완성할 수 있습니다.
추가로 업로드한 파일 미리보기, 다중 파일 처리 기능으로 확장해볼 수도 있겠죠. 오늘도 즐거운 개발 되시길 바랍니다!
'개인 프로젝트' 카테고리의 다른 글
Google Font Icon을 활용한 아이콘 사용법 (React) (0) | 2025.04.23 |
---|---|
Firebase Storage를 활용한 파일 업로드 구현 방법 (2) | 2025.04.22 |
Github Actions와 Cloudtype을 활용한 CI/CD 자동 배포 설정 (0) | 2025.04.20 |
React + Spring 배포 (Cloudtype - 배포) (1) | 2025.03.27 |
Perspective API - 욕설 및 비속어 필터링 (0) | 2025.03.22 |