질문 4. resources 디렉토리에서, static, template 등의 폴더가 있는데, 거기서 새로운 디렉토리를 만들게 되면, static.uploads 이런식으로 표시가 되던데, 원래라면 디렉토리 아래에 새로 만들어진 디렉토리가 표시가 되어야 하는데, 왜 resources 디렉토리 아래에 있는 디렉토리들은 그 안에 새로운 디렉토리를 만들면 왜 그렇게 표시를 해주는건가?
예를 들어서, src/main 에서 util 이라는 디렉토리를 만든다고 하면, .util 로 표시되는게 아니라 단독으로 디렉토리 아래에 표시가 되잖아. 왜 차이가 있는거지?
좋은 질문이에요! 이는 **IDE(통합 개발 환경)**와 Spring Boot의 프로젝트 구조에서 resources 디렉토리가 특별한 역할을 하기 때문입니다. 하나씩 차근히 설명드릴게요.
1. resources 디렉토리는 무엇인가요?
Spring Boot 프로젝트에서 src/main/resources 디렉토리는 애플리케이션의 리소스 파일을 관리하는 디렉토리입니다.
- HTML, CSS, JavaScript, 이미지 등 정적 파일(static).
- 템플릿 파일(templates).
- 애플리케이션 설정 파일(application.properties).
2. resources 디렉토리의 구조
Spring Boot는 resources 아래의 디렉토리와 파일을 특정 규칙에 따라 처리합니다:
- static 폴더:
- 정적 리소스(예: 이미지, CSS, JS 파일)를 저장하는 공간.
- 이 폴더의 파일은 HTTP 요청을 통해 정적으로 제공됩니다.
- 예: src/main/resources/static/image.png → http://localhost:8080/image.png.
- templates 폴더:
- Thymeleaf, FreeMarker 등의 템플릿 엔진이 사용하는 HTML 템플릿 파일을 저장.
- 기타 폴더:
- META-INF나 커스텀 폴더를 만들 수 있습니다.
- Spring Boot는 resources 내 파일과 디렉토리를 클래스패스(Classpath)에 포함시킵니다.
3. 새 디렉토리가 .static.uploads처럼 표시되는 이유
(1) IDE의 표시 방식
resources 아래에 디렉토리를 새로 만들면, IDE에서 클래스패스 기준으로 상대 경로를 표현하기 때문에 static.uploads처럼 표시됩니다.
- IDE는 resources 디렉토리가 클래스패스의 루트라는 점을 알고 있습니다.
- 따라서, resources/static/uploads라는 경로를 논리적인 경로로 보여주기 위해 static.uploads처럼 표현합니다.
왜 논리적 경로를 사용하나요?
Spring Boot에서는 resources 아래의 디렉토리가 애플리케이션에서 특별한 역할을 합니다:
- resources/static은 HTTP 경로(/)로 매핑됩니다.
- resources/templates는 템플릿 엔진 경로로 매핑됩니다.
- IDE가 이 구조를 이해하고, 프로젝트 관리에 편리하도록 상대 경로로 표시합니다.
(2) 일반 디렉토리는 논리적 경로를 사용하지 않음
src/main/java 아래의 디렉토리는 클래스 파일을 저장하는 패키지 구조로 관리됩니다. 여기서는 논리적 경로를 사용할 필요가 없습니다:
- src/main/java/com/example/util → 패키지: com.example.util.
4. src/main/resources와 src/main/java의 차이
디렉토리 | 역할 | 경로 표시 방식 |
src/main/java | Java 코드와 패키지 관리 | 디렉토리 자체 표시 |
src/main/resources | 리소스 파일 관리 (정적 파일, 설정 파일 등) | 논리적 경로로 표시 |
- Java 디렉토리는 클래스와 패키지의 물리적 구조와 논리적 구조가 동일합니다.
- 예: com/example/util → 패키지: com.example.util.
- resources 디렉토리는 클래스패스에 포함되며, Spring Boot가 디렉토리별로 다르게 처리합니다.
- 예: static → 정적 리소스 디렉토리.
5. 실무에서의 적용
- IDE 표시 방식은 실제 디렉토리 구조에 영향을 주지 않습니다.
- 예: resources/static/uploads는 물리적으로 디렉토리가 그대로 존재하지만, IDE에서 static.uploads로 보일 뿐입니다.
- Spring Boot가 처리하는 방식에 익숙해지면 됩니다:
- static 폴더: 정적 리소스.
- templates 폴더: 템플릿 엔진.
- 기타 리소스: 클래스패스에 포함.
6. 요약
- resources 디렉토리는 Spring Boot에서 특별히 취급되며, 클래스패스 기준으로 논리적 경로를 표시합니다.
- src/main/java는 일반 디렉토리처럼 물리적 구조를 그대로 표시합니다.
- 이는 IDE가 Spring Boot 프로젝트의 표준 구조를 이해하고, 개발 편의성을 위해 표시 방식을 조정한 것입니다.
이제 IDE에서 보이는 경로 표시 방식에 대해 이해가 되셨나요? 😊
클래스패스가 뭐야?
클래스패스(Classpath)는 Java 애플리케이션이 실행될 때
클래스 파일(.class)이나 리소스 파일(예: 설정 파일, 정적 파일 등)을 찾는 경로를 지정하는 설정입니다.
1. 클래스패스의 역할
Java 프로그램이 실행될 때, 필요한 클래스와 리소스 파일을 어디서 찾아야 하는지 알려주는 경로를 클래스패스라고 합니다.
비유
- 클래스패스는 Java 프로그램이 "어디에서 자료를 찾을지 알려주는 지도"와 같습니다.
- 지도에 지정된 경로에 파일이 없으면, Java는 실행 중에 오류를 발생시킵니다.
2. 클래스패스의 기본 설정
JVM과 클래스패스
- JVM(자바 가상 머신)은 클래스를 실행할 때 클래스패스를 따라가며 파일을 찾습니다.
- 클래스패스에는 다음 경로가 포함될 수 있습니다:
- 프로젝트의 컴파일된 클래스 파일 경로 (예: src/main/java → target/classes).
- 외부 라이브러리 경로 (예: Maven이나 Gradle에서 다운로드된 JAR 파일).
3. 클래스패스의 구성 요소
(1) 디렉토리
클래스파일(.class)이나 리소스파일이 있는 디렉토리.
- 예: target/classes 디렉토리에는 프로젝트의 컴파일된 클래스 파일과 리소스 파일이 저장됩니다.
- 이 디렉토리가 클래스패스에 포함됩니다.
(2) JAR 파일
외부 라이브러리나 패키징된 클래스 모음.
- 예: mysql-connector-java-8.0.33.jar (MySQL 데이터베이스 드라이버).
- 이 파일도 클래스패스에 포함될 수 있습니다.
4. 클래스패스와 Spring Boot
Spring Boot에서는 src/main/resources 디렉토리가 클래스패스의 일부로 포함됩니다. 따라서, 이 디렉토리 안의 파일은 실행 시 자동으로 JVM에서 로드됩니다.
예:
- src/main/resources/application.properties: Spring Boot 설정 파일.
- src/main/resources/static: 정적 리소스 디렉토리.
- src/main/resources/templates: 템플릿 파일.
Spring Boot는 이 경로를 클래스패스로 인식하고, 애플리케이션 실행 시 필요한 리소스를 자동으로 로드합니다.
5. 클래스패스를 설정하는 방법
(1) 기본 클래스패스
Java 애플리케이션 실행 시, 기본 클래스패스는 다음과 같습니다:
- 프로젝트의 target/classes 디렉토리.
- Maven이나 Gradle에서 관리하는 외부 라이브러리.
(2) 명시적 클래스패스 설정
Java 프로그램 실행 시 -cp(또는 -classpath) 옵션으로 클래스패스를 명시적으로 설정할 수 있습니다.
예:
java -cp .:libs/* com.example.Main
- .: 현재 디렉토리.
- libs/*: libs 디렉토리에 있는 모든 JAR 파일.
6. 클래스패스가 없으면 발생하는 문제
클래스패스에 필요한 경로가 없으면, Java는 클래스를 찾지 못해 오류를 발생시킵니다:
- ClassNotFoundException: 클래스 파일을 찾지 못했을 때 발생.
- NoClassDefFoundError: 클래스를 찾았지만, 의존성이 해결되지 않아 발생.
7. 요약
- 클래스패스란?
- Java 애플리케이션이 필요한 클래스와 리소스를 찾는 경로.
- src/main/resources, target/classes, 외부 라이브러리 등이 포함됩니다.
- Spring Boot와 클래스패스
- src/main/resources는 Spring Boot에서 기본적으로 클래스패스에 포함됩니다.
- 정적 파일, 템플릿 파일, 설정 파일은 클래스패스를 통해 자동으로 로드됩니다.
- 클래스패스를 설정하는 방법
- 기본적으로 Maven/Gradle이 클래스패스를 관리하지만, 수동으로 -cp 옵션을 사용할 수도 있습니다.
클래스패스의 역할과 중요성에 대해 이해가 되셨나요? 추가로 궁금한 점이 있다면 질문해주세요! 😊
그러면 Mark Directory as Excluded 를 하더라도 달라지는 건 없는거지?
Mark Directory as Excluded를 하면 **IDE(통합 개발 환경)**에서 해당 디렉토리를 무시하게 설정하는 것이며,
실제 애플리케이션의 동작에 영향을 주지는 않습니다.
그러나 개발 과정에서 편집기(IDE)의 동작에는 영향을 줄 수 있습니다.
이를 상세히 설명드릴게요.
1. Mark Directory as Excluded란?
IDE의 기능
- Excluded(제외): 특정 디렉토리를 프로젝트 탐색기에서 무시하도록 설정합니다.
- 이 설정은 IDE에서만 작동하며, 애플리케이션 실행에는 영향을 주지 않습니다.
2. Excluded 디렉토리의 특징
(1) 코드 및 리소스 무시
- Excluded로 지정된 디렉토리의 파일은 IDE에서 다음 작업 대상에서 제외됩니다:
- 코드 자동 완성.
- 구문 검사.
- 빌드 과정(Gradle, Maven)에서 무시.
- 탐색기에서 디렉토리 숨김.
(2) 클래스패스에는 여전히 포함
- Excluded 설정은 IDE에서만 영향을 주므로, 해당 디렉토리의 파일은 여전히 클래스패스에 포함됩니다.
- 예를 들어, src/main/resources/static을 Excluded로 설정해도, Spring Boot 애플리케이션은 여전히 이 디렉토리의 파일을 정적 리소스로 제공할 수 있습니다.
3. Excluded가 적용될 때의 IDE 동작
(1) Excluded 설정 전
- src/main/resources 디렉토리의 파일이:
- 코드 자동 완성에서 인식됨.
- IDE의 구문 검사 대상이 됨.
- 빌드에 포함될 수 있음.
(2) Excluded 설정 후
- 해당 디렉토리가 IDE에서 무시됩니다:
- 탐색기에서 흐릿하게 표시되거나 숨겨짐.
- 해당 디렉토리의 파일은 코드 자동 완성 및 구문 검사에서 제외됨.
- 빌드(컴파일) 과정에서 제외될 수도 있음(Gradle/Maven 설정에 따라 다름).
4. Excluded가 실제 애플리케이션에 미치는 영향
(1) Spring Boot 애플리케이션에서
- Spring Boot는 클래스패스를 기준으로 파일을 로드합니다.
- IDE에서 Excluded로 설정해도, 해당 파일이 클래스패스에 포함되어 있다면 애플리케이션 실행에는 영향이 없습니다.
예: src/main/resources/static
- Excluded 설정 전: 파일이 정적 리소스로 제공됩니다.
- Excluded 설정 후: 여전히 정적 리소스로 제공됩니다. (IDE에서만 무시될 뿐)
(2) 실제 애플리케이션에서의 예외
- 만약 Excluded 설정이 빌드 도구(예: Gradle, Maven)에도 영향을 미치도록 설정되었다면, 애플리케이션 실행 시 해당 파일이 누락될 수 있습니다.
5. 결론
- Mark Directory as Excluded는 IDE에서만 작동하는 설정으로, Spring Boot 애플리케이션 실행에는 영향을 미치지 않습니다.
- 그러나 Excluded로 지정된 디렉토리는 구문 검사 및 빌드 대상에서 제외될 수 있으므로, 디렉토리를 무조건 Excluded로 지정하지 않는 것이 좋습니다.
- 실제 애플리케이션에 영향을 미치려면 Gradle/Maven 설정에서 해당 디렉토리를 명시적으로 제외해야 합니다.
질문 5. @Value 어노테이션이 상대 경로에 대한 정보를 받아오도록 했는데 그것말고도 다른 기능도 있어?
이건 나중에, @Value 가 필요할 때 공부하는 걸로.
질문 6. 상대 경로와 절대 경로에 대해서 상세하게 설명해줄래? 현업에서 일을 하게 되면 상대 경로와 절대 경로의 활용에 대해서 말해줄래? 그리고 클라우드 저장소를 활용할 때와 로컬 저장소를 활용할 때의 상대 경로와 절대 경로의 차이도 알려주면 좋겠어.
좋은 질문이에요! 상대 경로와 절대 경로는 파일 시스템과 URL, 클라우드 환경 등에서 매우 중요한 개념입니다. 이 개념을 이해하고 실무에서 어떻게 활용되는지, 로컬과 클라우드 환경에서의 차이까지 상세히 설명드릴게요.
1. 상대 경로와 절대 경로의 개념
(1) 절대 경로 (Absolute Path)
- 루트 디렉토리부터 시작하여 파일이나 디렉토리까지의 전체 경로를 나타냅니다.
- 경로가 전체적으로 명확하고, 어디에서 참조해도 항상 동일한 파일이나 디렉토리를 가리킵니다.
예 (운영체제)
- 윈도우: C:\Users\Username\Documents\file.txt
- 리눅스/맥: /home/username/documents/file.txt
예 (웹 URL)
(2) 상대 경로 (Relative Path)
- **현재 작업 디렉토리(기준점)**를 기준으로 파일이나 디렉토리의 위치를 나타냅니다.
- 경로는 기준점에 따라 다르게 해석됩니다.
예 (운영체제)
- 기준 디렉토리가 /home/username일 때:
- 상대 경로: documents/file.txt → 절대 경로: /home/username/documents/file.txt.
예 (웹 URL)
- 기준 URL이 https://example.com/products/일 때:
- 상대 경로: images/photo.jpg → 절대 경로: https://example.com/products/images/photo.jpg.
(3) 상대 경로와 절대 경로의 차이
특징 | 절대 경로 | 상대 경로 |
시작점 | 루트 디렉토리나 도메인부터 시작 | 현재 디렉토리나 기준점부터 시작 |
이동 가능성 | 항상 동일한 위치를 가리킴 | 기준점에 따라 달라짐 |
명확성 | 경로가 명확 | 기준점이 필요 |
유연성 | 덜 유연함 | 더 유연함 |
2. 현업에서의 활용
(1) 절대 경로의 활용
- 파일 시스템:
- 중요한 시스템 파일이나 고정된 리소스를 참조할 때 절대 경로를 사용합니다.
- 예: /etc/config/system.properties (서버 설정 파일).
- 웹 개발:
- 외부 리소스를 참조할 때 사용.
- 예: https://cdn.example.com/styles/main.css.
- 클라우드 환경:
- 클라우드 스토리지의 고유 경로를 참조할 때.
- 예: s3://my-bucket/images/photo.jpg.
(2) 상대 경로의 활용
- 프로젝트 개발:
- 애플리케이션 내부의 파일 참조.
- 예: src/main/resources/static/images/logo.png.
- 웹 개발:
- 같은 도메인 내의 리소스를 참조할 때 사용.
- 예: images/photo.jpg.
- 유연성 확보:
- 경로가 고정되지 않고, 프로젝트 위치나 실행 환경에 따라 자동으로 경로를 조정할 수 있습니다.
3. 클라우드 저장소와 로컬 저장소의 차이
(1) 로컬 저장소에서의 상대 경로와 절대 경로
- 절대 경로: 운영체제의 파일 시스템 경로를 기준으로 작성.
- 예: C:\Users\Username\Documents\file.txt.
- 상대 경로: 애플리케이션 실행 디렉토리를 기준으로 작성.
- 예: ./files/data.json → 실행 디렉토리가 C:\app라면, 실제 경로는 C:\app\files\data.json.
실무에서의 활용
- 로컬 저장소에서는 상대 경로를 더 자주 사용합니다.
- 예: src/main/resources는 상대 경로로 관리됩니다.
- 절대 경로는 OS마다 다르기 때문에, 하드코딩하면 이동성이 떨어질 수 있습니다.
(2) 클라우드 저장소에서의 상대 경로와 절대 경로
- 절대 경로: 클라우드 저장소는 보통 고유한 URL을 제공하며, 이를 절대 경로로 사용합니다.
- 상대 경로: 클라우드 환경에서는 상대 경로를 사용할 일이 드뭅니다. 대부분 절대 경로로 접근합니다.
실무에서의 활용
- 클라우드 스토리지는 절대 경로를 사용해 파일이나 데이터를 관리합니다.
- 하지만, 애플리케이션 내부에서 상대 경로처럼 동작하도록 설정할 수 있습니다.
- 예: /images/photo.jpg를 기본 경로로 사용하고, 이를 S3 절대 경로로 매핑.
4. 절대 경로와 상대 경로를 선택하는 기준
상황 | 추천 경로 유형 | 이유 |
고정된 위치의 파일 참조 | 절대 경로 | 명확하고 일관된 참조 가능. |
프로젝트 내부 리소스 관리 | 상대 경로 | 실행 환경에 따라 경로 조정 가능. |
외부 리소스(URL, API) 참조 | 절대 경로 | 항상 동일한 위치에서 리소스 접근. |
유연성이 필요한 애플리케이션 | 상대 경로 | 환경별 경로 조정 가능. |
5. 요약
- 절대 경로는 항상 고유하며 명확한 참조를 보장.
- 상대 경로는 환경에 따라 유연하게 적용 가능.
- 로컬 저장소에서는 상대 경로가 더 유리하며, 클라우드 저장소에서는 절대 경로가 일반적.
- 실무에서는 절대 경로를 하드코딩하지 않고, 환경 설정 파일(application.properties)이나 상수를 활용해 경로를 관리하는 것이 좋습니다.
질문 7. yml 파일에 spring: servlet: multipart: 한 뒤에 업로드 파일의 크기 제한과 한 번에 여러 개의 파일을 업로드할 때 총 파일 크기의 제한을 걸어주었었어. 왜 그걸 spring 에서 관여하는거지? 그리고 servlet, multipart 가 관여된 이유는 뭐지? 그리고 servlet과 multipart 가 뭐길래? 그 다음에 파일 크기 제한을 10MB 로 했는데, 최대 얼마까지 제한을 걸어줄 수가 있어? 왜냐면 점점 세상이 발전할 수록 파일 크기가 커질 수가 있잖아.
아주 좋은 질문이에요! Spring에서 파일 업로드 크기 제한을 설정하는 이유와 servlet, multipart의 역할을 살펴보고, 파일 크기 제한에 대해 상세히 설명드릴게요.
1. Spring에서 파일 크기 제한을 설정하는 이유
Spring은 웹 애플리케이션에서 파일 업로드 요청을 처리할 때, 서버와 애플리케이션을 보호하기 위해 파일 크기를 제한합니다.
왜 제한이 필요할까?
- 서버 자원 보호:
- 큰 파일이 업로드되면 메모리, 디스크 공간 등이 과도하게 사용될 수 있습니다.
- 서버가 응답하지 못하거나, 다른 사용자 요청에 영향을 줄 수 있습니다.
- 보안:
- 악의적인 사용자가 매우 큰 파일을 업로드하여 서비스 거부 공격(DDoS)을 시도할 수 있습니다.
- 파일 크기를 제한하면 이런 공격을 예방할 수 있습니다.
- 사용자 경험:
- 파일 크기를 제한하면 업로드 시간이 짧아지고, 사용자 경험이 향상됩니다.
2. Spring에서 servlet과 multipart가 관여하는 이유
Spring은 파일 업로드 처리를 Servlet 기반의 기술로 수행합니다. 그 과정에서 **multipart**가 중요한 역할을 합니다.
(1) Servlet이란?
- Servlet은 Java 웹 애플리케이션의 기본 구성 요소로, HTTP 요청과 응답을 처리하는 기술입니다.
- Spring MVC는 Servlet 기반 프레임워크로, 모든 HTTP 요청은 Servlet을 통해 처리됩니다.
Servlet의 역할
- 클라이언트의 요청(파일 업로드 포함)을 받아서 컨트롤러로 전달.
- 응답을 클라이언트에게 반환.
(2) Multipart란?
- Multipart는 파일 업로드 시 사용하는 HTTP 요청 형식인 multipart/form-data를 처리하는 데 사용됩니다.
- 파일 업로드 요청은 일반 텍스트 요청과 다르게, 파일 데이터가 여러 부분(Part)으로 나뉘어 전송됩니다.
Multipart 처리 과정
- 클라이언트가 파일을 multipart/form-data 형식으로 전송.
- Spring의 CommonsMultipartResolver 또는 StandardServletMultipartResolver가 요청을 해석.
- 해석된 파일 데이터가 컨트롤러의 MultipartFile 객체로 전달.
3. YAML 설정에서 spring.servlet.multipart의 역할
Spring Boot에서 파일 업로드 설정은 spring.servlet.multipart로 관리됩니다:
spring:
servlet:
multipart:
max-file-size: 10MB # 단일 파일의 최대 크기
max-request-size: 50MB # 전체 요청의 최대 크기 (여러 파일 포함)
각 설정의 의미
- max-file-size: 업로드할 수 있는 단일 파일의 최대 크기를 지정.
- max-request-size: 한 번의 요청에서 업로드할 수 있는 총 파일 크기를 지정.
Spring이 설정을 제공하는 이유
- 개발자가 복잡한 설정 없이 파일 업로드 크기를 쉽게 제한할 수 있도록 도와줍니다.
- Spring Boot는 Servlet과 Multipart를 자동으로 설정 및 관리하기 때문에 설정이 간단합니다.
4. 파일 크기 제한: 최대 크기는 얼마까지 가능할까?
(1) Spring Boot의 제한
- Spring Boot 자체적으로는 최대 크기에 제한이 없습니다.
- 설정 파일에서 원하는 크기를 지정하면 그만큼 업로드가 가능합니다.
spring:
servlet:
multipart:
max-file-size: 1GB
max-request-size: 5GB
(2) 서버와 운영체제의 제한
- 파일 크기는 Spring 설정뿐 아니라, 서버와 운영체제의 제한도 영향을 받습니다.
- 예: Apache, Nginx 같은 웹 서버는 기본적으로 업로드 크기 제한이 설정되어 있습니다.
5. 점점 더 커지는 파일 크기에 대한 대처 방법
(1) 큰 파일을 지원하는 경우
- Spring Boot 설정에서 제한을 늘리면 됩니다.
- 예: 영상 파일, 대규모 데이터 파일 등.
(2) 클라우드와 스트리밍 활용
큰 파일 업로드를 처리하는 더 좋은 방법은 클라우드 스토리지를 활용하거나 스트리밍 방식을 사용하는 것입니다:
- 클라우드 스토리지:
- S3, Azure Blob Storage, Google Cloud Storage 같은 서비스를 활용해 클라이언트가 파일을 직접 클라우드에 업로드.
- 서버는 파일을 저장하지 않고, 클라우드에 저장된 URL만 관리.
- 스트리밍 방식:
- 파일을 한 번에 전송하지 않고, 부분적으로 처리하여 메모리 사용량을 줄임.
6. 현업에서의 활용
(1) 로컬 서버
- 파일 크기 제한 설정을 통해 서버를 보호.
- YAML 설정:
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 500MB
(2) 클라우드 기반
- Spring 애플리케이션은 클라이언트의 요청을 받아 클라우드에 파일을 업로드하거나 URL을 관리.
7. 요약
- Spring에서 파일 크기 제한을 설정하는 이유:
- 서버 자원 보호, 보안, 사용자 경험 개선.
- Servlet과 Multipart:
- Servlet은 HTTP 요청을 처리.
- Multipart는 파일 업로드 요청(multipart/form-data)을 처리.
- Spring 설정:
- 단일 파일 크기와 전체 요청 크기를 쉽게 제한 가능.
- 최대 크기:
- Spring 자체로는 제한 없음. 서버와 운영체제 설정이 관건.
- 미래 대비:
- 클라우드 스토리지와 스트리밍 방식을 활용해 대용량 파일 처리.
'Spring Boot (+ RESTful)' 카테고리의 다른 글
RESTful 웹 서비스 구축 - # Project 04 - 이미지 업로드 (6) (0) | 2025.01.08 |
---|---|
RESTful 웹 서비스 구축 - # Project 04 - 이미지 업로드 (5) (0) | 2025.01.07 |
RESTful 웹 서비스 구축 - # Project 04 - 이미지 업로드 (3) (0) | 2025.01.05 |
RESTful 웹 서비스 구축 - # Project 04 - 이미지 업로드 (2) (0) | 2025.01.04 |
RESTful 웹 서비스 구축 - # Project 04 - 이미지 업로드 (1) (0) | 2025.01.03 |