2021. 12. 20. 20:19ใProgramming Project ์์ ์ค/๋ด์ฉ ์ ๋ฆฌ
์ฐ๋ฆฌ ๊ฐ์กฑ์ ์ปค๋ฎค๋ํฐ ์น ์๋น์ค๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋จผ์ 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
๐ฝ 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์ ๋ํด ์์๋ณผ ๊ฒ์ด์์.