๐ spring_ssr ํ๋ก์ ํธ ์ ์ฒด ์ ๋ฆฌ
Spring Boot 3.3 + Thymeleaf SSR ๋ฐฉ์์ ์ปค๋ฎค๋ํฐ ๊ฒ์ํ ํ๋ก์ ํธ
MVC ํจํด ๊ธฐ๋ณธ๊ธฐ + IoC/DI, AOP ๊ฐ๋
ํ์ต + ๊ฒ์๊ธยท๋๊ธยทํ์ผ ๊ธฐ๋ฅ ๊ตฌํ
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ ๊ฐ์
spring_ssr/
โโโ ์ค๊ณ/ โ md ๊ฐ์ ๋ฌธ์
โโโ src/main/java/com/
โ โโโ ch/basic/ โ ์ค์ ์ ํ๋ฆฌ์ผ์ด์
(com.ch.basic)
โ โ โโโ DemoApplication.java
โ โ โโโ HomeController.java
โ โ โโโ community/ โ ๊ฒ์๊ธ (SSR)
โ โ โ โโโ comment/ โ ๋๊ธ (REST API)
โ โ โ โโโ dto/
โ โ โ โโโ repository/
โ โ โโโ user/ โ ํ์ (์ธ์
๋ก๊ทธ์ธ)
โ โ โโโ file/ โ ํ์ผ (์ฒจ๋ถํ์ผ + ์๋ํฐ ์ด๋ฏธ์ง)
โ โ โโโ api/ โ ๊ณต๊ณต๋ฐ์ดํฐ API ํ๋ก์
โ โ โโโ common/ โ ๊ณตํต (config, exception, scheduler, dto)
โ โโโ ioc/step1~4/ โ IoC/DI ๊ฐ๋
ํ์ต์ฉ ์ฝ๋
โ โโโ aop/step1~4/ โ AOP ๊ฐ๋
ํ์ต์ฉ ์ฝ๋
โโโ src/main/resources/
โ โโโ application.yml
โ โโโ data-*.sql โ ์ด๊ธฐ ๋ฐ์ดํฐ
โ โโโ templates/ โ Thymeleaf ํ
ํ๋ฆฟ
โโโ build.gradle
๊ธฐ์ ์คํ
| ํญ๋ชฉ |
๊ธฐ์ |
| Framework |
Spring Boot 3.3.4, Java 17 |
| View |
Thymeleaf (SSR) |
| ORM |
Spring Data JPA + QueryDSL 5.0 |
| DB |
MariaDB |
| ๋น๋ |
Gradle |
| ๊ธฐํ |
Lombok, spring-dotenv, Validation, AOP, DevTools |
๐ ์ค๊ณ ๋ฌธ์ (md) โ ์ค์ ์ฝ๋ ๋งค์นญ ๊ฒ์ฆ
โ
์ผ์นํ๋ ํญ๋ชฉ
| md ๋ฌธ์ |
์ค์ ์ฝ๋ |
์ํ |
๊ฐ๋
_01_IoC_DI.md โ step1~4 ํ์ต ํ๋ฆ |
com.ioc.step1~4 ํจํค์ง ์กด์ฌ, ๊ฐ step๋ณ Main.java ์์ |
โ
์ผ์น |
๊ฐ๋
_02_MVCํจํด.md โ SSR ํ๋ฆ, Controller/Model/View |
CommunityController, UserController, templates/ |
โ
์ผ์น |
๊ฐ๋
_06_Transaction.md โ readOnly + @Transactional ํจํด |
CommunityService, CommentService, FileService ๋ชจ๋ ์ด ํจํด ์ ์ฉ |
โ
์ผ์น |
๊ฐ๋
_07_Session_Login.md โ HttpSession ๋ก๊ทธ์ธ |
UserController.login(), LoginUserDTO ์ธ์
์ ์ฅ |
โ
์ผ์น |
๊ฐ๋
_08_Validation.md โ @Valid ์ค๋ช
|
build.gradle์ spring-boot-starter-validation ์์ |
โ
์ผ์น |
๊ฐ๋
_09_Exception.md โ ์ปค์คํ
์์ธ ๊ณ์ธต |
BusinessException โ EntityNotFoundException/AccessDeniedException/BusinessRuleException/DuplicateResourceException ์กด์ฌ |
โ
์ผ์น |
๊ฐ๋
_09_Exception.md โ GlobalExceptionHandler vs ApiExceptionHandler |
GlobalExceptionHandler(@ControllerAdvice) + ApiExceptionHandler(@RestControllerAdvice) ๋ถ๋ฆฌ ์ ์ฉ |
โ
์ผ์น |
๊ฐ๋
_10_AOP.md โ step1~4 ํ์ต ํ๋ฆ |
com.aop.step1~4 ํจํค์ง ์กด์ฌ, ๊ฐ step๋ณ ํ์ผ ๊ตฌ์กฐ ์ผ์น |
โ
์ผ์น |
๊ฐ๋
_11_Filter_Interceptor.md โ Interceptor ์ ์ฉ |
LoginCheckInterceptor + WebConfig ์ฝ๋์ md ์ค๋ช
์ผ์น |
โ
์ผ์น |
ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md โ ๋๊ธ REST API |
CommentApiController ๊ฒฝ๋ก/๋ฉ์๋/์๋ต ์ผ์น |
โ
์ผ์น |
ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md โ ํ์ผ ์ฒ๋ฆฌ ํ๋ฆ |
FileService, FileController, FileApiController ๋์ ์ผ์น |
โ
์ผ์น |
ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md โ ์ค์ผ์ค๋ฌ ๊ณ ์ ํ์ผ ์ญ์ |
FileCleanupScheduler (๋งค์ผ ์๋ฒฝ 4์, refId=0 + 24์๊ฐ) ์ผ์น |
โ
์ผ์น |
ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md โ ์ํํธ/ํ๋ ์ญ์ ์ ์ฑ
|
User(์ํํธ, @SQLRestriction), Community/Comment(ํ๋), File(๊ณ ์โ์ค์ผ์ค๋ฌ) ์ผ์น |
โ
์ผ์น |
ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md โ ๊ฒ์๊ธ ์ญ์ ํ๋ฆ |
CommunityController.delete(): ํ์ผ๊ณ ์โ๋๊ธ์ญ์ โ๊ฒ์๊ธ์ญ์ ์์ ์ผ์น |
โ
์ผ์น |
โ ๏ธ md ๋ฌธ์ ๋ถ์ผ์น ์ฌํญ โ ์์ ์๋ฃ
์๋ ํญ๋ชฉ๋ค์ ๋ชจ๋ ์์ ์๋ฃ๋จ.
| # |
ํ์ผ |
์์ ๋ด์ฉ |
| 1 |
๊ฐ๋
_00_๋ชฉ์ฐจ.md |
์กด์ฌํ์ง ์๋ 04_JPA_Repository, 05_QueryDSL, 12_Security ์ ๊ฑฐ. ์ค์ 12_์ค์ผ์ฅด๋ฌ ์ถ๊ฐ. ์ฐธ๊ณ ๋ฌธ์(์๋น์ค์ค๊ณ, ํ์ผํ
์ด๋ธ์ค๊ณ ๋ฑ) ์น์
์ถ๊ฐ |
| 2 |
๊ฐ๋
_07_Session_Login.md |
UserEntity โ LoginUserDTO๋ก ์์ (Entity๋ฅผ ์ธ์
์ ์ ์ฅํ์ง ์๋ ์ด์ ์ค๋ช
์ถ๊ฐ) |
| 3 |
๊ฐ๋
_08_Validation.md |
ํ์ฌ ์ฝ๋๋ @RequestParam ๋ฐฉ์์ด์ง๋ง, ๋ฌธ์๋ @Valid ์ ์ ์ฌ์ฉ๋ฒ ์ ๋ฆฌ ๋ชฉ์ ์์ ์๋ด ์ถ๊ฐ |
| 4 |
๊ฐ๋
_01_IoC_DI.md |
ํจํค์ง com.test.test โ com.ch.basic |
| 5 |
๊ฐ๋
_10_AOP.md |
ํจํค์ง com.test.test โ com.ch.basic (10๊ฑด ์ ์ฒด ์นํ) |
| 6 |
๊ฐ๋
_09_Exception.md |
@ControllerAdvice โ @ControllerAdvice(annotations = Controller.class), @RestControllerAdvice โ @RestControllerAdvice(annotations = RestController.class), findByIdAndIsDeletedFalse โ findById, @Slf4j ์ ๊ฑฐ |
๐ ๋จ์์๋ ๋ฏธ์์ฑ ํญ๋ชฉ
๋ชจ๋ ๊ฐ๋
๋ฌธ์ ์์ฑ ์๋ฃ.
๐ง ์ค์ ๊ตฌํ๋ ๊ธฐ๋ฅ ์ ๋ฆฌ
1. ๊ฒ์๊ธ (SSR โ @Controller)
| ๊ธฐ๋ฅ |
URL |
HTTP |
์ฒ๋ฆฌ |
| ๋ชฉ๋ก (๊ฒ์+ํ์ด์ง) |
/community |
GET |
QueryDSL ๋์ ์ฟผ๋ฆฌ, PageResponse |
| ์์ฑ ํผ |
/community/write |
GET |
๋ก๊ทธ์ธ ํ์ (Interceptor) |
| ์์ฑ ์ฒ๋ฆฌ |
/community/write |
POST |
๊ธ ๋ฑ๋ก โ ์๋ํฐ์ด๋ฏธ์ง ์ฐ๊ฒฐ โ ์ฒจ๋ถํ์ผ ์ ์ฅ โ redirect |
| ์์ธ |
/community/{id} |
GET |
์กฐํ์ ์ฆ๊ฐ, ๋๊ธยทํ์ผ์ JS์์ API ํธ์ถ |
| ์์ ํผ |
/community/{id}/edit |
GET |
๋ก๊ทธ์ธ ํ์ |
| ์์ ์ฒ๋ฆฌ |
/community/{id}/edit |
POST |
๊ธ ์์ โ ์๋ํฐ์ด๋ฏธ์ง ๋๊ธฐํ โ ํ์ผ์ญ์ โ ์ํ์ผ์ ์ฅ |
| ์ญ์ |
/community/{id}/delete |
POST |
ํ์ผ๊ณ ์์ฒ๋ฆฌ โ ๋๊ธ์ญ์ โ ๊ฒ์๊ธ์ญ์ |
2. ๋๊ธ (REST API โ @RestController)
| ๊ธฐ๋ฅ |
URL |
HTTP |
์๋ต |
| ๋ชฉ๋ก |
GET /api/communities/{id}/comments?page=0&size=10 |
GET |
JSON (PageResponse) |
| ์์ฑ |
POST /api/communities/{id}/comments |
POST |
JSON (201 Created) |
| ์์ |
PUT /api/communities/{id}/comments/{commentId} |
PUT |
JSON |
| ์ญ์ |
DELETE /api/communities/{id}/comments/{commentId} |
DELETE |
JSON |
3. ํ์ผ
| ๊ธฐ๋ฅ |
Controller |
URL |
์ฉ๋ |
| ๋ค์ด๋ก๋ |
FileController (@Controller) |
GET /files/download/{fileId} |
์ฒจ๋ถํ์ผ ๋ค์ด๋ก๋ |
| ์ด๋ฏธ์ง ์๋น |
FileController (@Controller) |
GET /uploads/{filename} |
์๋ํฐ ๋ณธ๋ฌธ ์ด๋ฏธ์ง |
| ๋ชฉ๋ก ์กฐํ |
FileApiController (@RestController) |
GET /api/files?refId=&refType=&usage= |
JS fetch |
| ์
๋ก๋ |
FileApiController (@RestController) |
POST /api/files/upload |
์๋ํฐ ์ด๋ฏธ์ง ์ฆ์ ์
๋ก๋ |
4. ํ์
| ๊ธฐ๋ฅ |
URL |
HTTP |
| ๋ก๊ทธ์ธ ํผ |
/login |
GET |
| ๋ก๊ทธ์ธ ์ฒ๋ฆฌ |
/login |
POST |
| ๋ก๊ทธ์์ |
/logout |
POST |
| ํ์๊ฐ์
ํผ |
/signup |
GET |
| ํ์๊ฐ์
์ฒ๋ฆฌ |
/signup |
POST |
| ๋ง์ดํ์ด์ง |
/mypage |
GET |
5. ๊ณต๊ณต๋ฐ์ดํฐ API ํ๋ก์
| ๊ธฐ๋ฅ |
URL |
| API ํ
์คํธ ํ์ด์ง |
GET /api/test โ templates/api.html |
| ์๊ตฐ๊ตฌ๋ณ ๊ด๊ด๊ธฐํ์ง์ |
GET /api/proxy/city-climate |
| ๋๋ค์๋ณด |
GET /api/proxy/tour-forecast |
6. ๊ฐ๋
ํ์ต์ฉ ์ฝ๋ (standalone)
| ํจํค์ง |
๋ด์ฉ |
com.ioc.step1 |
์ง์ ๊ฐ์ฒด ์์ฑ โ ๊ฐํ ๊ฒฐํฉ |
com.ioc.step2 |
์ธํฐํ์ด์ค + ์์ฑ์ ์ฃผ์
โ IoC ์์ |
com.ioc.step3 |
Assembler ๋์
โ IoC ์ปจํ
์ด๋ ์ํ |
com.ioc.step4 |
Spring ์ปจํ
์ด๋ (@Configuration + @Bean) |
com.aop.step1 |
AOP ์์ด โ ๋ถ๊ฐ ๋ก์ง ์ค๋ณต |
com.aop.step2 |
ํ๋ก์ ํจํด โ ์๋ ๋ถ๋ฆฌ |
com.aop.step3 |
JDK Dynamic Proxy โ ์๋ ํ๋ก์ |
com.aop.step4 |
Spring AOP โ @Aspect + Pointcut |
๐ ์ํคํ
์ฒ ์์ฝ
[๋ธ๋ผ์ฐ์ ]
โ
โโ SSR ์์ฒญ (GET/POST form) โโโ [LoginCheckInterceptor] โโโ [@Controller]
โ โ
โ CommunityController
โ UserController
โ FileController
โ โ
โ โโโโโโโโดโโโโโโโ
โ [Service] [Service]
โ โ โ
โ [Repository] [Repository]
โ (JPA+QueryDSL)
โ
โโ REST API (JS fetch) โโโ [@RestController]
โ CommentApiController (์์ฒด ์ธ์
์ฒดํฌ โ 401 JSON)
โ FileApiController
โ ApiProxyController (๊ณต๊ณตAPI ํ๋ก์)
โ
โ ์์ธ ๋ฐ์ ์:
โ @Controller โ GlobalExceptionHandler โ error.html
โ @RestController โ ApiExceptionHandler โ JSON ErrorResponse
โ
โโ ์ค์ผ์ค๋ฌ
FileCleanupScheduler (๋งค์ผ 04:00 โ ๊ณ ์ ํ์ผ ๋ฌผ๋ฆฌ์ญ์ + DB์ญ์ )
โ
์์ ์๋ฃ ์์ฝ
| # |
์์น |
์์ ๋ด์ฉ |
์ํ |
| 1 |
๊ฐ๋
_00_๋ชฉ์ฐจ.md |
04_JPA_Repository, 05_QueryDSL, 12_Security ์ ๊ฑฐ, 12_์ค์ผ์ฅด๋ฌ ๋ฐ ์ฐธ๊ณ ๋ฌธ์ ์ถ๊ฐ |
โ
์๋ฃ |
| 2 |
๊ฐ๋
_07_Session_Login.md |
UserEntity โ LoginUserDTO๋ก ์ ์ฒด ์์ |
โ
์๋ฃ |
| 3 |
๊ฐ๋
_08_Validation.md |
ํ์ฌ ์ฝ๋๋ @RequestParam, ๋ฌธ์๋ ์ ์ ์ฌ์ฉ๋ฒ ๋ชฉ์ ์์ ์๋ด ์ถ๊ฐ |
โ
์๋ฃ |
| 4 |
๊ฐ๋
_01_IoC_DI.md |
ํจํค์ง com.test.test โ com.ch.basic |
โ
์๋ฃ |
| 5 |
๊ฐ๋
_10_AOP.md |
ํจํค์ง com.test.test โ com.ch.basic (10๊ฑด) |
โ
์๋ฃ |
| 6 |
๊ฐ๋
_09_Exception.md |
@ControllerAdvice(annotations=...) ์ถ๊ฐ, findById ์์ , @Slf4j ์ ๊ฑฐ |
โ
์๋ฃ |
๐ ๋จ์์๋ ๋ฏธ์์ฑ ํญ๋ชฉ
| ํ์ผ |
์ํ |
๊ฐ๋
_03_JPA_Entity.md |
๋ฉ๋ชจ๋ง ์์ (๋ด์ฉ ๋ฏธ์์ฑ) |
๊ฐ๋
_12_์ค์ผ์ฅด๋ฌ.md |
๋ฉ๋ชจ๋ง ์์ (์์ธ ๋ด์ฉ์ ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md์ ์์) |
๐ md ๋ฌธ์๋ณ ์ํ ์ด์ ๋ฆฌ
| ํ์ผ |
๋ด์ฉ ์ถฉ์ค๋ |
์ฝ๋ ์ผ์น |
๋น๊ณ |
๊ฐ๋
_00_๋ชฉ์ฐจ.md |
โ
โ
โ
โ
โ
|
โ
|
์์ ์๋ฃ โ ์ค์ ํ์ผ๊ณผ ์ผ์น, ์ฐธ๊ณ ๋ฌธ์ ์น์
์ถ๊ฐ |
๊ฐ๋
_01_IoC_DI.md |
โ
โ
โ
โ
โ
|
โ
|
์์ ์๋ฃ โ ํจํค์ง๋ช
com.ch.basic |
๊ฐ๋
_02_MVCํจํด.md |
โ
โ
โ
โ
โ
|
โ
|
MVC ์์ธ ํ๋ฆ๋, SSR vs CSR ๋น๊ต |
๊ฐ๋
_03_JPA_Entity.md |
โ
โ
โ
โ
โ
|
โ
|
JPA, Entity, Repository, QueryDSL ๊ฐ๋
+ ์ด ํ๋ก์ ํธ ์ค์ ์ฝ๋ ๊ธฐ๋ฐ ์ค๋ช
|
๊ฐ๋
_06_Transaction.md |
โ
โ
โ
โ
โ
|
โ
|
readOnly, ์ ํ, ๋ด๋ถํธ์ถ ์ฃผ์์ฌํญ |
๊ฐ๋
_07_Session_Login.md |
โ
โ
โ
โ
โ
|
โ
|
์์ ์๋ฃ โ LoginUserDTO ๊ธฐ์ค, Entity ๋ฏธ์ ์ฅ ์ด์ ์ค๋ช
|
๊ฐ๋
_08_Validation.md |
โ
โ
โ
โ
โ |
โ
|
์ ์ ์ฌ์ฉ๋ฒ ์ ๋ฆฌ ๋ชฉ์ , ํ์ฌ ์ฝ๋์ ์ฐจ์ด ์๋ด๋จ |
๊ฐ๋
_09_Exception.md |
โ
โ
โ
โ
โ
|
โ
|
์์ ์๋ฃ โ annotations ๋งค๊ฐ๋ณ์, findById |
๊ฐ๋
_10_AOP.md |
โ
โ
โ
โ
โ
|
โ
|
์์ ์๋ฃ โ ํจํค์ง๋ช
com.ch.basic |
๊ฐ๋
_11_Filter_Interceptor.md |
โ
โ
โ
โ
โ
|
โ
|
์ค์ ์ฝ๋ ์ธ์ฉ, ์ ์ฉ ๋ฒ์ ์ ํ |
๊ฐ๋
_12_์ค์ผ์ฅด๋ฌ.md |
โ
โ
โ
โ
โ
|
โ
|
@Scheduled, cron, FileCleanupScheduler ์ ์ฉ ์ฝ๋ ๊ธฐ๋ฐ ์ค๋ช
|
ํ๋ก์ ํธ_๊ตฌ์กฐ_์ ๋ฆฌ.md |
โ
โ
โ
โ
โ
|
โ
|
์ ์ฒด ์ค๊ณ ์์ธ ๋ฌธ์ (์ฐธ๊ณ /์์์ฉ) |
์๋น์ค์ค๊ณ_์ ๋ฆฌ.md |
โ
โ
โ
โ
โ
|
- |
Facade ํจํด, ๊ณ์ธต ๊ตฌ์กฐ (์ฐธ๊ณ /์์์ฉ) |
ํ์ผํ
์ด๋ธ์ค๊ณ_์ ๋ฆฌ.md |
โ
โ
โ
โ
โ
|
- |
ํตํฉ vs ๋ถ๋ฆฌ, ์ค๋ฌด ๊ธฐ์ค (์ฐธ๊ณ /์์์ฉ) |
ํ
์คํธ์ฝ๋_์ ๋ฆฌ.md |
โ
โ
โ
โ
โ |
- |
SSR ํ
์คํธ ๊ฐ์ฑ๋น ๋ถ์ (์ฐธ๊ณ /์์์ฉ) |
ํ์
.md |
โ
โ
โโโ |
- |
๊ฐ๋ต ๋ฉ๋ชจ ์์ค |
ํ ๊ณต๊ณต๋ฐ์ดํฐAPI, CORS ์ ๋ฆฌ.md |
โ
โ
โ
โ
โ
|
โ
|
CORS ๋์์๋ฆฌ, CSRF, ์๋ฒ ์ค์ ๋ณ ๋น๊ตํ |