Programming Project ์ž‘์—…์‹ค/๋‚ด์šฉ ์ •๋ฆฌ

[์šฐ๋ฆฌ์ง‘ ๊ฐ€์กฑ ์ปค๋ฎค๋‹ˆํ‹ฐ ์›น ์„œ๋น„์Šค ํ”„๋กœ์ ํŠธ] ๊ธฐ์ˆ  ์ •๋ฆฌ - ์ดˆ๊ธฐ๊ตฌ์„ฑ

์ฃผ๋‹ˆ์“ฐ๐Ÿง‘‍๐Ÿ’ป 2021. 12. 20. 20:19
728x90
๋ฐ˜์‘ํ˜•

์šฐ๋ฆฌ ๊ฐ€์กฑ์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ ์›น ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋จผ์ € Server ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

์ฝ”๋”ฉ์„ ํ•˜๋ฉด์„œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด์„œ ๋‚˜์ค‘์— ์ฃผ๋‹ˆ ํ•˜๋ž‘๋„ ํ™•์ธํ•˜๊ณ , ์—ฌ๊ธฐ ์˜ค์‹  ์—ฌ๋Ÿฌ๋ถ„๋“ค๊ณผ๋„ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด์—์š”!

๊ทธ๋Ÿผ ์‹œ์ž‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

 

ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ Source Code๋Š” '์ฃผ๋‹ˆํ•˜๋ž‘ Git Hub'์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 


 

 

 

๐Ÿ—‚ ๋ชฉ์ฐจ(INDEX)
       1.  
์ดˆ๊ธฐ๊ตฌ์„ฑ

       2. Spring Security ์ดˆ๊ธฐ ๊ตฌ์„ฑ

       3. Interceptor ์„ค์ •

.      4. ์ดˆ๊ธฐ Domain ์„ค์ •

 

 

 

 

 


 

๐Ÿš€ Build.gradle

 

๋จผ์ € ์ฃผ๋‹ˆํ•˜๋ž‘์€ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•ด ์ด๋Ÿฌํ•œ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด์—์š”.

๊ฐ์ฒด ์ง€ํ–ฅ์  DB ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด Spring DATA JPA๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ณ , RESTFulํ•˜๊ฒŒ ์›น ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด hatoas๋ฅผ ์ ์šฉ์‹œํ‚ฌ ๊ฒƒ์ด์—์š”. ๊ทธ๋ฆฌ๊ณ , ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ์œ„ํ•ด oauth2๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ณ , jwt ๊ธฐ์ˆ ์„ ์ด์šฉํ•œ ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์›๊ฐ€์ž… ๊ตฌํ˜„์„ ์œ„ํ•ด Spring Securiry ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด์—์š”.

๊ทธ๋ฆฌ๊ณ , Mail ์ธ์ฆ์„ ์ ์šฉํ•ด ๋ณด๊ธฐ ์œ„ํ•ด mail ์˜์กด์„ฑ์„ ๋ฐ›๊ณ , Spring์— ๋‚ด์žฅ๋œ Tomcat ์‚ฌ์šฉ์„ ์œ„ํ•ด Spring-boot-web์˜ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด์—์š”.

 

๊ทธ๋ฆฌ๊ณ , Model Mapper๋ผ๋Š” ๊ฒƒ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ต๋‹ˆ๋‹ค!

Model Mapper๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?

์ด๊ฒƒ์€ ์–ด๋–ค Object(๊ฐ์ฒด)์— ์žˆ๋Š” ํ•„๋“œ๊ฐ’๋“ค์„ ์ž๋™์œผ๋กœ ์›ํ•˜๋Š” Object๋กœ Mapping ์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋”ฉํ•  ๋•Œ, getter, setter๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ ์žˆ์–ด ์›ํ•˜๋Š” ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ์ด ๋‹ค๋ฅผ ๋•Œ, ์ถœ๋ ฅ(Output) Object์— ์ž…๋ ฅ(Input) ํ•„๋“œ ๊ฐ’๋“ค ์ค‘ ์›ํ•˜๋Š” ํ•„๋“œ๋“ค์„ ํ•˜๋‚˜์”ฉ ๋„ฃ์–ด์ฃผ๋Š” ๊ณผ์ •์„ ๋‹ค๋“ค ๊ฒฝํ—˜ ํ•ด ๋ณด์…จ์„ ๊ฒƒ์ด์—์š”.

์ด๋Ÿฐ ๊ฒƒ์€ ์ผ์ผ์ด getter์™€ setter๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ž‘์„ฑํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Ÿฐ ๊ฒƒ์„ ๊ฐœ๋ฐœ์ž๋Š” ์ข‹์•„ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด์—์š”! 

๋ฐ”๋กœ ์ด ์ผ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด Model Mapper๋ž๋‹ˆ๋‹ค!

 

๊ทธ ๋‹ค์Œ ์˜์กด์„ฑ์€ Swagger๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์˜์กด์„ฑ ์ž…๋‹ˆ๋‹ค!

Swagger๋Š” Back End ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐœ๋ฐœํ•œ ๋‚ด์šฉ์„ ๋ฌธ์„œํ™” ํ•˜์—ฌ Front End ๊ฐœ๋ฐœ์ž ๋ถ„๋“ค์ด ๊ฐœ๋ฐœํ•˜์‹ค ๋•Œ, ์–ด๋–ค์‹์œผ๋กœ ๊ฐœ๋ฐœํ•˜๋ฉด ๋˜๋Š”์ง€ ์ฐธ๊ณ  ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

๊ทธ ๋‹ค์Œ์œผ๋กœ๋Š” Request ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•ด Spring Validation์„ ์ถ”๊ฐ€ ํ•ด ์ฃผ์—ˆ๋‹ต๋‹ˆ๋‹ค!

์ด๊ฒƒ์„ ํ†ตํ•ด์„œ Request๋กœ ์˜ค๋Š” ๊ฐ์ฒด(DTO)๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

Data ๊ฒ€์ฆ(Validation)์€ ์—ฌ๋Ÿฌ ๊ณ„์ธต(Layer)์— ๊ฑธ์ณ ๋ฐœ์ƒํ•˜๋Š” ์•„์ฃผ ํ”ํ•œ ์ž‘์—…์ธ ๊ฒƒ์ด๋ฉฐ, ๊ผญ ํ•„์š”ํ•œ ์ž‘์—…์ธ ๊ฒƒ์ด์—์š”.

 

์ด๊ฒƒ์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด Bean Validation์ด๋ผ๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๊ฒƒ์€ Class ํ•„๋“œ์— ํŠน์ • Annotaion์„ ์ ์šฉํ•˜์—ฌ ํ•„๋“œ๊ฐ€ ๊ฐ–๋Š” ์ œ์•ฝ ์กฐ๊ฑด์„ ์ •์˜ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

Validator๊ฐ€ ๊ทธ Class๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด์˜ ์œ ํšจ์„ฑ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ฒŒ ๋˜๊ณ , ์–ด๋–ค ๋น„์ฆˆ๋‹ˆ์Šค์  ๋กœ์ง์— ๋Œ€ํ•œ ๊ฒ€์ฆ์ด ์•„๋‹Œ, ๊ฐ์ฒด ์ž์ฒด์˜ ํ•„๋“œ์— ๋Œ€ํ•œ ๊ฒ€์ฆ์„ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

๊ทธ ๋‹ค์Œ์€ ์ฃผ๋‹ˆํ•˜๋ž‘์€ TEST ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  DB๋ฅผ ์‹œ๋†€๋กœ์ง€ NAS์— ๋„์ปค๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ , MariaDB๋ฅผ ์˜ฌ๋ ค ๋†“์€ ๊ฒƒ์ด์—์š”. ๋‚˜์ค‘์— QA TEST ๋“ฑ์„ ์ง„ํ–‰ํ•  ๋•Œ, ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด DEV DB์™€ ๋ณ„๋„๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด MariaDB ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ ํ•˜์˜€์Šต๋‹ˆ๋‹ค!

 

๊ทธ๋ฆฌ๊ณ , TEST๋ฅผ ํ•  ๋•Œ ์‚ฌ์šฉํ•  JUnit4์— ์˜์กด์„ฑ์„ ๋ฐ›์•˜๊ณ , jwt๋ฅผ ํ†ตํ•ด ํ† ํฐ ๊ธฐ๋ฐ˜์— ์•ˆ์ „ํ•œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด์—์š”.

 

๊ทธ๋ฆฌ๊ณ , Getter๋‚˜, ์ƒ์„ฑ์ž๋ฅผ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด lombok ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ–ˆ๊ณ , json๊ธฐ๋ฐ˜์— API ํ†ต์‹ ์„ ์œ„ํ•ด ํ•ด๋‹น ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ ํ–ˆ๋‹ต๋‹ˆ๋‹ค!

 

 

 

JPA๋ฅผ ํ†ตํ•ด์„œ ๊ฐ์ฒด ์ง€ํ–ฅ์ ์œผ๋กœ DB์— Query๋ฅผ ๋‚ ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”. RDBMS์™€ JAVA์˜ ๊ฐ์ฒด ์ง€ํ–ฅ์ด๋ผ๋Š” ๊ฒƒ์€ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜๋ผ๋Š” Issue๊ฐ€ ์žˆ์–ด ์ด๊ฒƒ์„ ํ•ด๊ฒฐ ํ•ด ์ฃผ๋Š” ์•„์ฃผ ์ข‹์€ ์นœ๊ตฌ์ธ๋ฐ์š”!

ํ•˜์ง€๋งŒ, JPA๋ฅผ ํ†ตํ•ด์„œ ๋ชจ๋“  CRUD๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

JOIN ๋“ฑ์„ ํ•  ๋•Œ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ SQL์„ ์“ฐ๊ฑฐ๋‚˜, Jooq, Querydsl ๋“ฑ์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ฃผ๋‹ˆํ•˜๋ž‘์€ Querydsl๋กœ ์ง„ํ–‰ ํ•ด ๋ณด๋ ค๋Š” ๊ฒƒ์ด์—์š”.

 

 

๐Ÿš€ application.properties or yml

jwt:
  secret: abc
spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: junyharang8592@gmail.com
    password: pwd
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
springdoc:
  paths-to-exclude=/swagger-resources/**:


์œ„์™€ ๊ฐ™์ด application.yml์— jwt์™€ Mail ์ธ์ฆ ๋“ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์„ค์ •์„ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.


spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true

# DEV DataBase
spring.h2.console.enabled=true
spring.datasource.devdb.driver-class-name=org.h2.Driver
spring.datasource.devdb.jdbc-url=jdbc:h2:tcp://localhost/~/hongga
spring.datasource.devdb.username=sa
spring.datasource.devdb.password=
spring.jpa.devdb.database-platform=org.hibernate.dialect.H2Dialect

# Test DataBase
spring.datasource.testdb.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.testdb.jdbc-url=jdbc:mariadb://localhost:3389/hongga
spring.datasource.testdb.username=junyharang
spring.datasource.testdb.password=password
spring.jpa.testdb.database-platform=org.hibernate.dialect.MariaDBDialect

# File Upload Config
# File Saver Enable
spring.servlet.multipart.enabled=true
# Upload File Save Path
spring.servlet.multipart.location=/resources/imgUpload
com.hongga.upload.path =/resources/imgUpload
# One Thing Upload File Size
spring.servlet.multipart.max-request-size=50MB
# Upload File Max Size
spring.servlet.multipart.max-file-size=100MB

 

์œ„์˜ application.properties์—๋Š” DB ๊ด€๋ จ ์„ค์ •์ด ๋‘ ๊ฐœ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.
ํ•˜๋‚˜๋Š” Mac Book์œผ๋กœ ๊ฐœ๋ฐœ ์ค‘์ธ ์ฃผ๋‹ˆํ•˜๋ž‘์˜ '๋งฅํ”„๊ธฐ'์— H2 DBMS๋ฅผ ์„ค์น˜ํ•˜๊ณ , ๊ทธ ๊ณณ์— ์„ค์ •์„ ๋งž์ถฐ ๊ฐœ๋ฐœ์šฉ์œผ๋กœ ์“ฐ๊ธฐ ์œ„ํ•จ์ด๊ณ , ๋˜ ํ•˜๋‚˜๋Š” ์ฐจ ํ›„ Test์šฉ์œผ๋กœ ์‹œ๋†€๋กœ์ง€ NAS์— ๋„์ปค๋กœ ์˜ฌ๋ ค ๋†“์€ Maria DB๋ฅผ ์„ค์ • ํ•ด ๋‘” ๊ฒƒ์ด์—์š”.

์šด์˜ ๋‹จ๊ณ„ ๊นŒ์ง€ ๊ฐ€๋ฉด DB๋Š” ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•˜์—ฌ ์šด์˜ DB ๋˜ํ•œ ์ถ”๊ฐ€ ํ•ด ์ค„ ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๊ทธ ์•„๋ž˜๋Š” Image ๋“ฑ์„ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ File Upload ์„ค์ •์„ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

๐Ÿš€ Config

 

Config ๊ด€๋ จ Directory Tree ๊ตฌ์กฐ

 

 

    ๐Ÿ”ฝ  ModelMapperConfig



์œ„์—์„œ๋„ ์ด์•ผ๊ธฐํ•œ ๋ฐ”์™€ ๊ฐ™์€ ์ด์œ ์™€ ๋”๋ถˆ์–ด ModelMapper๋Š” API๊ฐ€ ์ œ๊ณตํ•˜๋Š” DTO๋ฅผ ๊ทธ๋ƒฅ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๊ฐ€ ํฐ ๊ฒƒ์ด์—์š”. API๋Š” ์–ธ์ œ๋“ ์ง€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š”๋ฐ, API๊ฐ€ ์ œ๊ณตํ•˜๋Š” DTO ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด์„œ Application์„ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด API๊ฐ€ ๋ณ€๊ฒฝ ๋˜์—ˆ์„ ๋•Œ, ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ๋ฐ”๊ฟ”์ค˜์•ผ ํ•œ๋‹ค๋Š” ์œ ์ง€ ๋ณด์ˆ˜์— ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒจ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— API DTO๋ฅผ ์ด๋ฆ„๋งŒ ๋ฐ”๊ฟ”(๋™์ผํ•œ Data File๋ฅผ ๊ฐ–๋Š”๋‹ค.) WrapDTO๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์‚ฌ์šฉ์„ ํ•˜๋Š” ๊ฒƒ์ด์—์š”. ๊ทธ๋ฆฌ๊ณ , Store ์—ญํ• ์„ ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ API Call๊ณผ DTO < - > WrapDTO ๊ฐ„ ๋ณ€ํ™˜์„ ๋‹ด๋‹นํ•ด์„œ API Call ์ด๋ผ๋Š” ์ฑ…์ž„์„ Store๋ผ๋Š” ๊ณณ์— ์ง‘์•ฝ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด API๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ํ•ด๋‹น ์ฑ…์ž„์„ ๋‹ด๋‹นํ•˜๋Š” Store๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

์ด ๋•Œ, Store์—์„œ DTO < - > WrapDTO๋ฅผ ํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ, ํ•„๋“œ๊ฐ€ ํ•œ ๋‘ ๊ฐœ๋ฉด ๊ทธ๋ƒฅ Setter๋กœ ๋„ฃ์–ด๋„ ๋˜์ง€๋งŒ, ์œ„์— ์˜์กด์„ฑ์—์„œ ์ด์•ผ๊ธฐ ํ–ˆ๋“ฏ์ด ์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ซ์–ดํ•˜๋Š” ๋‹จ์ˆœ ๋…ธ๊ฐ€๋‹ค๊ฐ€ ์‹œ์ž‘๋˜๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ„๋‹จํ•œ Mapping์˜ ๊ฒฝ์šฐ Model Mapper๋ผ๋Š” Mapping์„ ๋„์™€์ฃผ๋Š” Class๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ž๋‹ˆ๋‹ค!

Class A {
	int age;
} // class A ๋

Class B {
	int age;
} // class B ๋

ModelMapper mapper = new ModelMapper();

A a = new A();
a.age = 10;

B b = mapper.map(a, B.class);โ€‹

์˜ˆ์‹œ๋ฅผ ๋“ค๋ฉด ์œ„์™€ ๊ฐ™์€ Code๊ฐ€ ์žˆ์„ ๋•Œ, A ๊ฐ์ฒด๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” ํ•„๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ B์— ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.
ํ•„๋“œ ์ด๋ฆ„์ด ๊ฐ™๋‹ค๋ฉด ๊ฐ’์ด ๊ทธ๋Œ€๋กœ Mapping ๋˜๊ธฐ ๋•Œ๋ฌธ์ธ ๊ฒƒ์ด์—์š”.
b.setAge(a.getAge()); ์™€ ๊ฐ™์€ ๋ฐ˜๋ณต์ ์ธ Code๋Š” ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒƒ์ด์—์š”.


    • Model Mapper Role
      ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•„๋“œ ์ด๋ฆ„์ด ๊ฐ™๋‹ค๋ฉด Mapping์ด ๋˜๋‚˜, ๋‹ค์–‘ํ•œ ๊ทœ์น™์ด ์•„๋ž˜์™€ ๊ฐ™์ด ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด์—์š”.



      ์ฃผ๋‹ˆํ•˜๋ž‘์€ ModelMapper๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด Config Class๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋‹ต๋‹ˆ๋‹ค.




    ๐Ÿ”ฝ  QuerydslConfig

 

 

 

 

    ๐Ÿ”ฝ  SpringAsyncConfig

 


์ด Config๋ฅผ ๋งŒ๋“  ์ด์œ ๋Š” ๋ฐ”๋กœ ๋น„๋™๊ธฐ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ์ด์—์š”!

๊ทธ๋Ÿผ ๋น„๋™๊ธฐ์™€ ๊ทธ์— ๋ฐ˜๋Œ€์ธ ๋™๊ธฐ๋Š” ์–ด๋–ค ์ฐจ์ด์ ์ด ์žˆ์„๊นŒ์š”?

๋™๊ธฐ (Synchronous: ๋™์‹œ์— ์ผ์–ด๋‚˜๋Š”)
๋™๊ธฐ ๋ฐฉ์‹์€ ๋ง ๊ทธ๋Œ€๋กœ ๋™์‹œ์— ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์ด์—์š”. ์š”์ฒญ๊ณผ ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ๋™์‹œ์— ์ผ์–ด๋‚œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ๋ฐฉ์‹์€ ์š”์ฒญ์„ ํ–ˆ์„ ๋•Œ, ์‹œ๊ฐ„์ด ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ฆฌ๋˜์ง€ ์š”์ฒญํ•œ ๊ทธ ์ž๋ฆฌ์—์„œ ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ์ฃผ์–ด์ ธ์•ผ ํ•œ๋‹ต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค๋ฉด A Node์™€ B Node ์‚ฌ์ด ์ž‘์—… ์ฒ˜๋ฆฌ ๋‹จ์œ„(Transaction)์„ ๋™์‹œ์— ๋งž์ถ”๊ฒ ๋‹ค. ๊ฐ€ ์žˆ๊ฒ ๋„ค์š”!

๋น„๋™๊ธฐ (Asynchronous : ๋™์‹œ์— ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”)
๋น„ ๋™๊ธฐ๋Š” ๋™์‹œ์— ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด์—์š”.
์š”์ฒญ๊ณผ ๊ฒฐ๊ณผ๊ฐ€ ๋™์‹œ์— ์ผ์–ด๋‚˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ์•ฝ์†์ด๋ž๋‹ˆ๋‹ค. ์ฆ‰, ์š”์ฒญํ•œ ๊ทธ ์ž๋ฆฌ์—์„œ ๊ฒจ๋กœ๊ฐ€๊ฐ€ ์ฃผ์–ด์ง€์ง€ ์•Š๋Š” ๊ฒƒ์ด์—์š”.
์˜ˆ๋ฅผ ๋“ค๋ฉด A Node์™€ B Node ์‚ฌ์ด ์ž‘์—… ์ฒ˜๋ฆฌ ๋‹จ์œ„๋ฅผ ๋™์‹œ์— ๋งž์ถ”์ง€ ์•Š๊ฒ ๋‹ค. ๊ฐ€ ์žˆ๊ฒ ๋„ค์š”!

์ด ๋‘ ์นœ๊ตฌ๋Š” ๊ฐ๊ฐ์˜ ์žฅ, ๋‹จ์ ์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๋จผ์ €, ๋™๊ธฐ ๋ฐฉ์‹์€ ์„ค๊ณ„๊ฐ€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ณ , ์ง๊ด€์ ์ด์ง€๋งŒ, ๊ฒฐ๊ณผ๊ฐ€ ์ฃผ์–ด์งˆ ๋•Œ๊นŒ์ง€ ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๊ณ , ๋Œ€๊ธฐ๋งŒ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์น˜๋ช…์  ๋‹จ์ ์ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๋น„๋™๊ธฐ ๋ฐฉ์‹์€ ๋™๊ธฐ ๋ฐฉ์‹๋ณด๋‹จ ๋ณต์žกํ•˜์ง€๋งŒ, ๊ฒฐ๊ณผ๊ฐ€ ์ฃผ์–ด์ง€๋Š”๋ฐ, ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋”๋ผ๋„ ๊ทธ ์‹œ๊ฐ„ ๋™์•ˆ ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿผ ๋‹ค์‹œ ์ฃผ์ œ๋กœ ๋Œ์•„๊ฐ€์„œ ์ด ์นœ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„ ๋ณผ๊ฒŒ์š”!

@Async๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋น„๋™๊ธฐ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ œ๊ฐ€ Config์— ์‚ฌ์šฉํ•œ @EnableAsync๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”. 
๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘์„ ์›ํ•˜๋Š” Method(public Method)์— @Async๋ฅผ ๋ถ™ํ˜€์ฃผ๋ฉด ๋์ด๋ž๋‹ˆ๋‹ค!

์œ„์— ์‚ฌ์šฉ๋œ @primary๋Š” ๊ฐ™์€ Type์˜ Bean์ด ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์„ ๋•Œ, @Quilfier๋ฅผ ์ง€์ •ํ•ด ์ฃผ์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ '์ด Bean์„ ์šฐ์„ ์ ์œผ๋กœ ์„ ํƒํ•ด์„œ ์ฃผ์ž…ํ•ด๋ผ! Spring!'์„ ๋œปํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์ด ์นœ๊ตฌ๋Š” @Configuration Class์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๋งž์•„์š”! @Configuration์€ ์–ด๋–ค ์„ค์ •์„ ์œ„ํ•ด ์ƒ์„ฑํ•˜๋Š” Class์— ๋ถ™ํ˜€์ฃผ๋Š” Annotation์ธ ๊ฒƒ์ด์—์š”.


threadPoolTaskExecutor()๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ๋กœ ํ˜ธ์ถœํ•˜๋Š” Threa์— ๋Œ€ํ•œ ์„ค์ •์„ ํ•œ ๊ฒƒ์ด์—์š”.

์ฒซ๋ฒˆ์งธ : CorePoolSize - ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹คํ–‰์„ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” Thread ๊ฐœ์ˆ˜ ์„ค์ •.
๋‘๋ฒˆ์งธ : MaxPoolSize - ๋™์‹œ ๋™์ž‘ํ•  ๋•Œ, ์ตœ๋Œ€ Thread ๊ฐœ์ˆ˜ ์„ค์ •.
์„ธ๋ฒˆ์งธ : QueueCapacity - MaxPoolSize๋ฅผ ์ดˆ๊ณผํ•˜๋Š” Thread ์ƒ์„ฑ ์š”์ฒญ ๋ฐœ์ƒ ์‹œ ํ•ด๋‹น ๋‚ด์šฉ์„ Queue์— ์ €์žฅํ•˜๊ณ , ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Thread ์—ฌ์œ  ์ž๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋ฉด ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด ๋™์ž‘ํ•˜๋Š”๋ฐ, ๋ช‡ ๊ฐœ๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€ ์„ค์ •.
๋‹ค์„ฏ๋ฒˆ์งธ : RejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

RejectedExecutionHandler๋Š” ThreadPoolExecutor์—์„œ ์ž‘์—…(Task)๋ฅผ ๋” ์ด์ƒ ๋ฐ›์„ ์ˆ˜ ์—†์„ ๋•Œ, ํ˜ธ์ถœ ๋˜๋Š” ๊ฒƒ์ด์—์š”.
์ด๋Ÿฐ ๊ฒฝ์šฐ Queue ํ—ˆ์šฉ์น˜๋ฅผ ์ดˆ๊ณผํ–ˆ๋”๋‚˜, Executor๊ฐ€ ์ข…๋ฃŒ ๋˜์–ด์„œ Thread ๋˜๋Š” Queue Slot์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ
๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด์—์š”.

Reject Policy

Executor๋Š” ์ž‘์—… Queue๊ฐ€ ๋ชจ๋‘ ์ฐผ์„ ๋•Œ, ์•„๋ž˜ 4๊ฐ€์ง€ ์ „๋žต ์ค‘์— ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

ํ•˜๋‚˜! ThreadPoolExecutor.AbortPolicy
์ด๊ฒƒ์€ ๊ธฐ๋ณธ(Default)๋กœ ์„ค์ • ๋œ ์ •์ฑ…์ธ ๊ฒƒ์ด์—์š”. Reject๋œ ์ž‘์—…(Task)์ด RejectedExecutionException์„ ๋˜์ง€๋Š”
๊ฒƒ์ด์—์š”.

๋‘˜! ThreadPoolExecutor.CallerRunPolicy
      ์ด๊ฒƒ์€ ํ˜ธ์ถœํ•œ Thread์—์„œ Reject๋œ ์ž‘์—…์„ ๋Œ€์‹  ์‹คํ–‰ํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด์—์š”. ์ฃผ๋‹ˆํ•˜๋ž‘์€ ์ด ์ •์ฑ…์„ ์„ ํƒํ•˜์˜€๋‹ต๋‹ˆ๋‹ค!

์…‹! ThreadPoolExecutor.DiscardPolicy
      ์ด๊ฒƒ์€ Reject๋œ ์ž‘์—…์„ ๋ฒ„๋ ค ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด์—์š”. ๋˜ํ•œ, ์˜ˆ์™ธ(Exception)๋„ ํ„ฐ์ง€์ง€ ์•Š๋Š”๋‹ต๋‹ˆ๋‹ค!

๋„ท! ThreadPoolExecutor.DiscardOldestPolisy
      ์ด๊ฒƒ์€ ์‹คํ–‰์ž๋ฅผ ์ข…๋ฃŒํ•˜์ง€ ์•Š๋Š” ํ•œ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์ฒ˜๋ฆฌ ๋˜์ง€ ์•Š์€ ์š”์ฒญ์„ ์‚ญ์ œํ•˜๊ณ , execute()๋ฅผ ๋‹ค์‹œ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ด์—์š”.


์—ฌ์„ฏ๋ฒˆ์งธ : WaitForTasksToCompleteOnShutdown(true);

        # shutdown
        ThreadPoolTaskExecutor Bean์ด destroy(์ œ๊ฑฐ)๋  ๋•Œ, shutdown ์ฒ˜๋ฆฌ ๋˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์—์š”.
        ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์ž‘์—…์„ ๋” ์ด์ƒ ๋ฐ›์ง€ ์•Š๊ณ , ์‹คํ–‰ ์ค‘์ธ ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด ๋ƒ…๋‹ค ์ค‘์ง€(Interrupt) ์‹œ์ผœ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด์—์š”.
        ๊ทธ๋Ÿฐ๋ฐ, ์ž‘์—…์ด ๋๋‚˜์ง€๋„ ์•Š์•˜๋Š”๋ฐ, ์ค‘์ง€๋ผ๋‹ˆ์š”! ๊ทธ๋ž˜์„œ ์œ„์˜ ์„ค์ •์„ ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.
        ์ € ํ•„๋“œ Setter์— true๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด shutdown ์‹œ ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•˜๋Š” ๊ฒƒ์ด์—์š”.
        ๊ธฐ๋ณธ๊ฐ’์„ false์ด๊ณ , false๋ฉด ๋‹น์—ฐํžˆ ์ž‘์—…์ด ์žˆ๊ฑด ๋ง๊ฑด ํ‡ด๊ทผํ•˜๋Š” ๊ฒƒ์ด์—์š”. 


์ผ๊ณฑ๋ฒˆ์งธ : AwaitTerminationSeconds(60);

     ์ด๊ฒƒ์€ ์œ„์˜ ๊ฐ’์ด true์ผ ๊ฒฝ์šฐ ์–ผ๋งˆ๋‚˜ ๋Œ€๊ธฐํ•  ๊ฒƒ์ธ์ง€ ์ดˆ ๋‹จ์œ„๋กœ ์„ค์ •์„ ํ•ด ์ฃผ๋Š” ๋ถ€๋ถ„์ธ ๊ฒƒ์ด์—์š”.
     ์ฃผ๋‹ˆํ•˜๋ž‘์€ 60(1๋ถ„)์ดˆ๋ฅผ ์„ค์ • ํ•ด ์ฃผ์—ˆ๋‹ต๋‹ˆ๋‹ค!

์œ„์— ๋‘ ๊ฐ’์€ ๋น„๋™๊ธฐ ์„ค์ • ์‹œ ๋„ˆ๋ฌด ์ž‘์€ ๊ฐ’์„ ์„ค์ • ํ•ด ๋ฒ„๋ฆฌ๋ฉด ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ํ„ฐ์ง€๊ณ , ๋„ˆ๋ฌด ํฐ ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด Resource ๋ถ€์กฑ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ ์ ˆํ•˜๊ฒŒ ์ž˜ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”. 

 

 

    ๐Ÿ”ฝ  SpringSecurityConfig



๋ฐ˜์‘ํ˜•

 



์ด ์นœ๊ตฌ๋Š” Spring์ด ์ œ๊ณตํ•˜๋Š” Security๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ๊ด€๋ จ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ๊ฒƒ์ด์—์š”.

๋จผ์ € WebSecurityConfigurerAdapter๋ผ๋Š” ์นœ๊ตฌ๋ฅผ ์ƒ์†์„ ๋ฐ›์€ ๊ฒƒ์ด์—์š”. 
์ด ์นœ๊ตฌ๋Š” ๋กœ๊ทธ์ธํ•˜๊ธฐ ์ „์— ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™(Redirect)ํ•˜๋Š” ๊ธฐ๋Šฅ, ์ด์šฉ์ž์—๊ฒŒ ID์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ›๊ธฐ, ์ž…๋ ฅ ๋ฐ›์€ ๊ฐ’ DB ๊ฐ’๊ณผ ๋น„๊ตํ•˜์—ฌ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ ๋“ฑ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์นœ๊ตฌ์ธ ๊ฒƒ์ด์—์š”.

@EnableWebSecurity๋Š” ๊ธฐ๋ณธ์ ์ธ Web ๋ณด์•ˆ ํ™œ์„ฑํ™”๋ฅผ ํ•ด์ฃผ๋Š” ์นœ๊ตฌ์ธ ๊ฒƒ์ด์—์š”.
@value("${jwt.secret}") private String secret; ์ด๊ฒƒ์€ ์ง€๊ธˆ ์ด ํ”„๋กœ์ ํŠธ Code๊ฐ€ ์ฃผ๋‹ˆํ•˜๋ž‘์˜ Github์— ์˜ฌ๋ผ๊ฐ€๊ณ  ์žˆ๋Š”๋ฐ, ์ด ๋•Œ ์€๋ฐ€ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•  jwt ๊ฐ’์ด ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด jwt ๊ฐ’์„ application.yml์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๋„ฃ์–ด ์ค€ ๊ฒƒ์ด์—์š”.

PasswordEncoder๋Š” ์ด์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™” ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด ๋‘์—ˆ์Šต๋‹ˆ๋‹ค!

๊ทธ๋ฆฌ๊ณ , secret์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ jwt ๊ฐ’์„ JWTUtil์ด๋ผ๋Š” ๊ฐ์ฒด์— ๋ณด๋‚ด ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿฐ ๋‹ค์Œ configure()๋ฅผ Overrideํ•˜์—ฌ Cors Error ๋ฐฉ์–ด๋ฅผ ์„ค์ •ํ•œ ๊ฒƒ์ด์—์š”.

์ฒซ์งธ : addAllowedOring - CORS ์š”์ฒญ์„ ํ—ˆ์šฉํ•  Site ์ž…๋ ฅ
๋‘˜์งธ : addAllowedMethod - CORS ์š”์ฒญ์„ ํ—ˆ์šฉํ–˜ HTTP Method ์„ค์ • (์ฃผ๋‹ˆํ•˜๋ž‘์€ ๋ชจ๋“  Method ํ—ˆ์šฉ)
์…‹์งธ : addAllowedHeaders - ํŠน์ • Header๋ฅผ ๊ฐ€์ง„ ๊ฒฝ์šฐ์— CORS๋ฅผ ์š”์ฒญํ•  ๋•Œ, ํ—ˆ์šฉ ์—ฌ๋ถ€ (์ฃผ๋‹ˆํ•˜๋ž‘์€ ๋ชจ๋‘ ํ—ˆ์šฉ)

๋„ท์งธ :

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);

                 UrlBasedCorsConfigurationSource()๋ฅผ ํ†ตํ•ด์„œ Pattern ๋ฐฉ์‹์œผ๋กœ ์ฃผ๋‹ˆํ•˜๋ž‘์ด ๊ฐœ๋ฐœํ•˜๋Š” ์—ก ์„œ๋น„์Šค์— ๋ชจ๋“ 
                 URI์— Cors Error๊ฐ€ ๋‚˜์ง€ ์•Š๊ฒŒ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.

 

 

๋งค๊ฐœ๋ณ€์ˆ˜(ํŒŒ๋ผ๋ฏธํ„ฐ)๋กœ ๋ฐ›์€ HttpSecurity๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉ ํ•ด๋ณด๋ ค ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

๋จผ์ €, formLogin()๊ณผ logout()์€ ์ง๊ด€์ ์œผ๋กœ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด Login๊ณผ Logout ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™” ์‹œํ‚ค๊ธฐ ์œ„ํ•จ์ธ๋ฐ,

Login์˜ ๊ฒฝ์šฐ ์œ„์— ์—ด๊ฑฐํ•œ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š์œผ๋ฉด ์ž๋™์œผ๋กœ Login์ฐฝ์œผ๋กœ ์ด๋™์„ ์‹œ์ผœ Login ๋ถ€ํ„ฐ ํ•˜๋„๋ก ๋งŒ๋“œ๋ ค๊ณ  ์ถ”๊ฐ€ํ•œ ๋ถ€๋ถ„์ธ ๊ฒƒ์ด์—์š”.

 

๊ทธ ๋‹ค์Œ csrf().disable()์„ ํ•ด ์ฃผ์—ˆ๋Š”๋ฐ, (CSRF ๊ณต๊ฒฉ์€ ์ด ๊ณณ์„ ๋ˆ„๋ฅด์‹œ๋ฉด ํ™•์ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

์ด๊ฒƒ์„ ํ•ด์ œ(disable)ํ•œ ๊ฒƒ์ด์—์š”. ์™œ ๊ทธ๋žฌ์„๊นŒ์š”?

์ด์œ ๋Š” ๋ฐ”๋กœ REST API์—์„œ Spring Security Documentation์— Non-browser Clients๋งŒ์„ ์œ„ํ•œ Service๋ผ๋ฉด csrf ๊ธฐ๋Šฅ์„ disableํ•˜์—ฌ๋„ ์ข‹๋‹ค๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์ธ ๊ฒƒ์ด์—์š”.

 

 

๊ทธ ์ด์œ ๋Š” REST API๋ฅผ ์ด์šฉํ•œ ์„œ๋ฒ„๋ผ๋ฉด, Session ๊ธฐ๋ฐ˜ ์ธ์ฆ๊ณผ ๋‹ค๋ฅด๊ฒŒ Statelessํ•˜๊ธฐ ๋•Œ๋ฌธ์— Server์— ์ธ์ฆ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ณ , REST API์—์„œ Client๋Š” ๊ถŒํ•œ์ด ํ•„์š”ํ•œ ์š”์ฒญ์„ ํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ์— ํ•„์š”ํ•œ ์ธ์ฆ ์ •๋ณด(OAuth2, JWT ๋“ฑ)์„ ํฌํ•จ ์‹œ์ผœ์•ผ ํ•ด์š”.

๊ทธ๋Ÿฐ ์ด์œ ๋กœ Server์— ์ธ์ฆ์ •๋ณด๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด ๋ถˆ ํ•„์š”ํ•œ Code๊ฐ€ ๋  csrf์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ๋„ฃ์„ ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒƒ์ด์—์š”.

๋งˆ์ง€๋ง‰์œผ๋กœ cors().configurationSource๋Š” ์œ„์—์„œ ์„ค์ •ํ–ˆ๋˜ CORS Error ๋ฐฉ์–ด ์„ค์ •๋“ค์„ ํ•œ ๋ฐ ๋ชจ์•„ CORS Error ๋ฐฉ์–ด๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•œ ๋ถ€๋ถ„์ธ ๊ฒƒ์ด์—์š”.

 

 

    ๐Ÿ”ฝ  SwaggerConfig

 

Swagger๋Š” Back End ๊ฐœ๋ฐœ์ž๋“ค์ด Server ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด Front End ๊ฐœ๋ฐœ์ž๋“ค์ด ์–ด๋–ค์‹์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•ด์•ผํ• ์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ฌธ์„œ ๊ด€๋ฆฌ Tool์ธ ๊ฒƒ์ด์—์š”.

21๋ฒˆ์งธ Code์— apis์— ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ RequestHandlerSelectors.basePackage("xx.xx")๋ผ๊ณ  ํ•˜๋ฉด ํ•ด๋‹น ํŒจํ‚ค์ง€์— ์žˆ๋Š” ๋‚ด์šฉ๋งŒ ๊ฐ€์ง€๊ณ  ์ถ”์ถœํ•˜์—ฌ Swagger ๋ฌธ์„œ๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ, ์ฃผ๋‹ˆํ•˜๋ž‘์€ ๋ชจ๋‘ ์ถ”์ถœ์„ ์›ํ•ด์„œ any()๋ผ๊ณ  ์ ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๊ฒฝ๋กœ ํŒจํ„ด์œผ๋กœ URI์— ๋Œ€ํ•ด ์ถ”์ถœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์—๋„ any๋ฅผ ์ฃผ์–ด ๋ชจ๋“  ๋ถ€๋ถ„์„ ์ถ”์ถœํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

api info์—๋Š” Swagger Main page ๋“ฑ์— ํ‘œ์‹œ๋˜๋ฉด์„œ Front End ๊ฐœ๋ฐœ์ž๋“ค์ด ์ง๊ด€์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๋ช…์‹œํ•œ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  WebMvcConfing

 

 

๋จผ์ € Spring MVC์— ๊ด€๋ จ๋œ ๋‚ด์šฉ์€ ์ด ๊ณณ์„ ํด๋ฆญํ•˜์‹œ๋ฉด ํ™•์ธ ํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ฃผ๋‹ˆํ•˜๋ž‘์€ @EnableWebMvc๋ฅผ ์„ ์–ธํ•˜์—ฌ WebMvcConfigurationSupport์—์„œ ๊ตฌ์„ฑํ•œ Spring MVC ๊ตฌ์„ฑ์„ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ํ•˜๊ณ , @Configuration๊ณผ @EnableWebMvc๋ฅผ ํ•จ๊ป˜ ์„ ์–ธํ•˜์—ฌ WebMvcConfigurer Interface๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด์—์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด WebMvcConfigurationSupport์—์„œ ์ž๋™ ๊ตฌ์„ฑํ•œ Spring MVC ๊ตฌ์„ฑ์— Formatter, MessageConverter๋“ฑ์„ ์ถ”๊ฐ€๋กœ ๋“ฑ๋ก ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”. ๋˜ํ•œ, ViewResolver ๊ฐ’์ด ์ž๋™์œผ๋กœ ๋“ฑ๋ก๋˜๋Š” ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๋งŒ์•ฝ ์–ด๋–ค ๋“ฑ๋ก๋œ Setting ๊ฐ’ A๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•  ๋•Œ, A ๊ฐ’์— ์ถ”๊ฐ€์ ์ธ Setting์„ ๋” ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด A์™€ ๋˜‘๊ฐ™์€ Bean์„ ๊ตฌํ˜„ํ•˜๊ณ , ๊ฑฐ๊ธฐ์— ์›ํ•˜๋Š” ์ถ”๊ฐ€ Setting์„ ํ•˜์—ฌ customViewResolver()์™€ ๊ฐ™์€ Bean์„ ์ง์ ‘ ๋งŒ๋“ค์–ด ์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

์ด๊ฒƒ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ซ์–ดํ•˜๋Š” ๋‹จ์ˆœ ๋…ธ๊ฐ€๋‹ค์ด๋ฉฐ, ๋งค์šฐ ๋ถˆํŽธํ•œ ํ–‰์œ„์ธ ๊ฒƒ์ด์—์š”. ์ด๊ฒƒ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด WebMvcConfigurer๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด์—์š”.

์ด ์นœ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด @EnableWebMvc๊ฐ€ ์ž๋™์ ์œผ๋กœ Setiing ํ•ด์ฃผ๋Š” ์„ค์ •์— ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์„ค์ •์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์ž‡๋Š” ๊ฒƒ์ด์—์š”. ์ฆ‰, @Override(์žฌ๊ตฌ์„ฑ)์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด์ง€์š”.

 

์ฃผ๋‹ˆํ•˜๋ž‘์€ WebMvcConfigurer Interface์— ์žˆ๋Š” addInterceptors์— ๋Œ€ํ•ด ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด์—์š”.

๊ทธ ์ „์— resouceHandle, preHandle, Interceptor, Servlet ๋“ฑ์— ๋Œ€ํ•ด์„œ๋Š” ์ด ๊ณณ์„ ํด๋ฆญํ•˜์‹œ๋ฉด ํ™•์ธ ํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

addInterceptors()๋Š” ๋“ฑ๋กํ•  ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ณณ์ด๊ณ , addPathPatterns ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ ์šฉํ•  URL Pattern์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด์—์š”. ์˜ˆ๋ฅผ ๋“ค๋ฉด **/* ** ๊ฐ™์ด ํ•  ๊ฒฝ์šฐ ๋ชจ๋“  URL์— ๋Œ€ํ•ด ํ•ด๋‹น ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ , excludePathPatterns๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ œ์™ธํ•  URL Pattern์„ ๋“ฑ๋กํ•˜์—ฌ ํ•ด๋‹น URL๋กœ ์ ‘๊ทผ ์‹œ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋‹จ ์ฃผ๋‹ˆํ•˜๋ž‘์€ ์„ ์–ธ๋งŒ ํ•ด ๋…ผ ์ƒํƒœ์ธ ๊ฒƒ์ด์—์š”.

 

๊ทธ๋ฆฌ๊ณ , GUestMemberAPIIntercptor, FamilyMemberAPIInterceptor, AdminAPIIntercpter๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์ฃผ๋‹ˆํ•˜๋ž‘์€ ์•„๋ž˜์™€ ๊ฐ™์ด ํšŒ์› ๋“ฑ๊ธ‰์„ ๋‚˜๋ˆˆ ๊ฒƒ์ด์—์š”.

 

 

๊ฐ ๊ถŒํ•œ ๋ณ„๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„๋“ค๊ณผ ์ฐจ๋‹จํ•  ๋ถ€๋ถ„๋“ค์— ๋Œ€ํ•œ ์ธ๊ฐ€์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  ๋‹ค ์ค‘ Database ์‚ฌ์šฉ ๊ด€๋ จ ์„ค์ •(DEVDBDataSourceConfig, TestDBDataSourceConfig)


  • DEVDBDataSourceConfig




  • TestDBDataSourceConfig

์ฃผ๋‹ˆํ•˜๋ž‘์€ ๊ฐœ๋ฐœ ๋‹น์‹œ์— ์‚ฌ์šฉํ•  DEVDB(H2)์™€ QA ๋“ฑ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  TEST Server์—์„œ ์‚ฌ์šฉํ•  TestDB(Maria DB)๋ฅผ ๋‚˜๋ˆ ์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด ์„ค์ •์„ ํ•œ ๊ฒƒ์ด์—์š”.

์ƒ๋‹จ์— ์ ์—ˆ๋˜ appilication.properties๋ฅผ ๋ณด์‹œ๋ฉด ๋‘ ๊ฐœ์˜ DB๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

ํ•ด๋‹น ์„ค์ •์€ application.properties์— prefix๋ฅผ ์ด์šฉํ•ด์„œ ๋‘ ๊ฐ€์ง€ DB๋ฅผ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

์•„์ง ์„ค์ • ๋‹จ๊ณ„๋ผ Repository ๋“ฑ์ด ์—†์–ด์„œ ๋นจ๊ฐ„ ์ค„์ด ๋‚˜์˜ค๋Š” ๋ถ€๋ถ„์ด ์žˆ์ง€๋งŒ, ์ฐจ ํ›„ ์ด ๋ถ€๋ถ„์€ Repository๋ฅผ ํ•ด๋‹น Package Path์— ๋งž๊ฒŒ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ด์—์š”.

์œ„์˜ ์ฝ”๋“œ์—์„œ ์ฒ˜๋Ÿผ Coustom datasource, entityManagerFactory ๋“ฑ์„ ์„ค์ •์„ ํ•˜๊ณ , base Packages์— Repository Package Path๋ฅผ ์ ์–ด์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”. entityManagerFactory์—์„œ๋Š” Entity์˜ Package๋ฅผ ์ง€์ •ํ•ด ์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ์ฃผ๋‹ˆํ•˜๋ž‘์€ ๋‘ DB ๋ณ„๋กœ ๋‹ค๋ฅด๊ฒŒ ๊ฐ๊ฐ ์„ค์ •์„ ํ•ด ์ค€ ๊ฒƒ์ด์—์š”.
์ฐธ๊ณ ๋กœ @Primary๋Š” ๊ผญ ๋ถ™ํ˜€์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

์„ค์ •์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ์„œ ๋งˆ๋ฌด๋ฆฌํ•˜๊ณ , ๋‹ค์Œ์—๋Š” Spring Security ๊ด€๋ จ CORSFilterdhk JwtUtil์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฒƒ์ด์—์š”.

728x90
๋ฐ˜์‘ํ˜•