songining
FetchJoin ๊ณผ EntityGraph
BACKEND/Spring 2022. 8. 21. 15:52

์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •์„ ํ•ด์ฃผ๋ฉด ์ผ๋ฐ˜์ ์ธ ์กฐํšŒ ์ฟผ๋ฆฌ์—์„œ๋Š” ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๊นŒ์ง€ ์กฐํšŒํ•ด์˜ค์ง€ ์•Š๊ณ  ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ์„ค์ •์ด ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐ’์— ์ ‘๊ทผํ•ด์•ผํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋งˆ๋‹ค ์ฟผ๋ฆฌ๊ฐ€ ํ•œ๋ฒˆ์”ฉ ๋” ์‹คํ–‰๋˜์–ด N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด Fetch Join ์ด๋‹ค. ์—ฐ๊ด€๋œ ๊ฒƒ๋“ค์„ ํ•œ๋ฒˆ์— ๋‹ค ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๊นŒ์ง€ ์‹ค์ œ ๊ฐ’์œผ๋กœ ์ „๋ถ€ ์ฑ„์›Œ์ค€๋‹ค. (์ฆ‰, ์กฐ์ธ๋งŒ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ select ์ ˆ์— ์žˆ๋Š” ๊ฐ’๋“ค๋„ ์ „๋ถ€ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ) EntityGraph - data jpa๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ fetch join ์„ jpql ์—†์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. JpaRepository๋ฅผ ์ƒ์†๋ฐ›๋Š” repository๊ฐ€ ์žˆ์„ ๋•Œ @..

Spring Mockito when().thenReturn ๊ณผ doReturn.when()์˜ ์ฐจ์ด
BACKEND/Spring 2022. 8. 1. 16:29

Typically, stubbing argument mismatch indicates user mistake when writing tests. Mockito fails early so that you can debug potential problem easily. However, there are legit scenarios when this exception generates false negative signal: - stubbing the same method multiple times using 'given().will()' or 'when().then()' API Please use 'will().given()' or 'doReturn().when()' API for stubbing. - st..

[Spring] detached entity passed to persist ์—๋Ÿฌ
BACKEND/Spring 2022. 5. 26. 02:32

detached entity passed to persist ๊ด€๋ จ ์—๋Ÿฌ๊ฐ€ ๋œจ๋Š” ๊ฒฝ์šฐ ์ด๋ฏธ ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š” ๊ฐ์ฒด์˜ ๋ถ€๋ถ„์— ๋‹ค์‹œ ํ•œ๋ฒˆ ๋” ์„ค์ •์„ ํ•ด์ฃผ๊ฑฐ๋‚˜ ์ €์žฅ์„ ํ•ด์ฃผ๋ ค๊ณ  ํ•  ๋•Œ ์ƒ๊ธฐ๋Š” ๊ฒƒ! ์ฆ‰, ์—”ํ‹ฐํ‹ฐ ์ข…์†์„ฑ ๋ฌธ์ œ๊ฑฐ๋‚˜ ๊ฐ์ฒด ์ƒ์„ฑํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ !! ์˜ˆ๋ฅผ ๋“ค๋ฉด 1) id ํ•„๋“œ์— @GeneratedValue๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ง€๋„๋ก ํ•ด๋†“๊ณ  ํ…Œ์ŠคํŠธํ•  ๋•Œ id ๊ฐ’์„ ์„ค์ •ํ•ด์คฌ๋‹ค๋˜๊ฐ€.. 2) ์—”ํ‹ฐํ‹ฐ๋“ค์˜ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•  ๋•Œ ํด๋ž˜์ŠคA ์˜ a1, a2 ์— ์—ฐ๊ด€๋œ ํด๋ž˜์ŠคB์— b1 ์ด ์žˆ์„ ๋•Œ (a1 + b1) ์ €์žฅํ•˜๊ณ  (a2 + b1) ์ €์žฅ๋˜์–ด ์ค‘๋ณต์œผ๋กœ ์ €์žฅ๋˜๋Š” ๊ฒฝ์šฐ (์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” cascade ๊ด€๋ จํ•ด์„œ ์„ค์ •์„ ์ œ๊ฑฐํ•ด์ฃผ๋˜๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๊ฒŒ ํ•ด์ฃผ๋ฉด ๋  ๋“ฏ!)

์„ธ์…˜๊ณผ JWT์˜ ์ฐจ์ด
BACKEND/Spring 2022. 5. 23. 23:38

JWT๋ž€? Json Web Token ์˜ ์•ฝ์ž๋กœ json ๊ฐ์ฒด์— ์‚ฌ์šฉ์ž์˜ ์ผ๋ถ€ ์ •๋ณด๋ฅผ ๋‹ด๋Š”๋‹ค. ์„ธ์…˜๊ณผ ๋‹ฌ๋ฆฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๊ฐ€ ์ค€ ํ† ํฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€ ํ—ค๋”์— ์‹ค์–ด์„œ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹ (๋‹จ์ˆœํ•˜๊ฒŒ ๋งํ•˜๋ฉด ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ ๋ฐฉ์‹) Header : Signature๋ฅผ ํ•ด์‹ฑํ•˜๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ณด๋“ค ๋‹ด๊ฒจ์žˆ์Œ Payload : ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๊ณ ๋ฐ›๋Š”, ์‹œ์Šคํ…œ์—์„œ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ์ •๋ณด๋“ค์— ๋Œ€ํ•œ ๋‚ด์šฉ ๋‹ด๊ณ  ์žˆ์Œ Signature : ํ† ํฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ์œ„ํ•œ ๋ฌธ์ž์—ด (์œ ํšจํ•œ ํ† ํฐ์ธ์ง€ ๊ฒ€์ฆ) ์„ธ์…˜์€? ์„œ๋ฒ„์˜ ๋ฉ”๋ชจ๋ฆฌ์— ์ธ์ฆํ•œ ์œ ์ €์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•ด๋‘ ! ๊ทธ๋ฆฌ๊ณ  ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ธ์ฆ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ํ†ต์‹ ํ•˜๋Š” ๋ฐฉ์‹ stateful service๋ž€ ์„ธ์…˜ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์— ์ €์žฅํ•˜๊ณ  ์„ธ์…˜ ์ƒํƒœ์— ๋”ฐ๋ฅธ ์‘๋‹ต์„ ์ฃผ๋Š” ์„œ๋น„์Šค! -> EX) ์„ธ์…˜..

Django simple-jwt ๋กœ๊ทธ์ธ ์ปค์Šคํ…€ํ•˜๊ธฐ
BACKEND/Django 2022. 5. 8. 16:43

pip install djangorestframework-simplejwt settings.py simple-jwt ํ”„๋ ˆ์ž„์›Œํฌ ์‚ฌ์šฉ๊ณผ ๊ถŒํ•œ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด settings.py ์•ˆ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”๊ฐ€ํ•ด์ค€๋‹ค. REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ) } ์ปค์Šคํ…€ ์œ ์ € ๋ชจ๋ธ์„ ์‚ฌ์šฉ ๋ฐ simple-jwt ์ถ”๊ฐ€ ์˜ต์…˜์„ ์ฃผ๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๋„ ์ถ”๊ฐ€ํ•œ๋‹ค. AUTH_USER_MODEL = "์•ฑ์ด๋ฆ„.CustomUser..

Django MVC ๊ตฌ์กฐ
BACKEND/Django 2022. 5. 2. 15:05

django-admin startproject tutorial # ์žฅ๊ณ  ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ cd tutorial # ๋ฃจํŠธ ํ”„๋กœ์ ํŠธ๋กœ ์ด๋™ ./manage.py startapp community # ์•ฑ ์ƒ์„ฑ ./manage.py migrate # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ ./manage.py createsuperuser # ๊ด€๋ฆฌ์ž ์ƒ์„ฑ ./manage.py runserver {port} # ์„œ๋ฒ„ ์—ฐ๊ฒฐ settings.py์— community ์•ฑ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผํ•จ INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.message..

SpringBoot Swagger2 UI์— JWT ํ† ํฐ Authorize ๋ฒ„ํŠผ ๋„ฃ๊ธฐ
BACKEND/Spring 2022. 2. 22. 21:12

** ๊ธฐ๋ณธ์ ์œผ๋กœ security ์„ค์ •๊ณผ swagger ์„ค์ •์ด ๋‹ค ๋˜์–ด์žˆ์Œ์„ ๋ฐ”ํƒ•์œผ๋กœ ํ•œ๋‹ค. SwaggerConfig.java @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .useDefaultResponseMessages(false) .select() .apis(RequestHandlerSelectors.basePackage("com.cherishpet.backend")) .paths(PathSelectors.ant("/api/**")) .build() .apiInfo(metaData()) .securityCon..

JPA, MYSQL DateTime ๋ณ€๊ฒฝ
BACKEND/Spring 2022. 2. 20. 21:47

MySQL์˜ DateTime์€ default ๋กœ 2022-02-20T00:00:00.000+00:00 ์œผ๋กœ ์„ค์ •๋˜์–ด์žˆ๋‹ค. INSERT์‹œ์— ์ด๋ฅผ YYYY-MM-DD ํฌ๋งท์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๊ธฐ ์œ„ํ•ด @Temporal(TemporalType.DATE) @DateTimeFormat(pattern = "yyyy-MM-dd") private Date sampleDate; ์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด YYYY-MM-DD ํฌ๋งท์œผ๋กœ DB์— ์ €์žฅ๋œ๋‹ค.

์Šคํ”„๋ง, mysql ์—ฐ๋™ gradle, applicaion.yml ์„ค์ •ํ•˜๊ธฐ
BACKEND/Spring 2022. 2. 8. 00:46

build.gradle dependencies์— ์ถ”๊ฐ€ dependencies { .. runtimeOnly 'mysql:mysql-connector-java' .. } application.yml datasource: url: jdbc:mysql://{localhost or IP}:{ํฌํŠธ๋ฒˆํ˜ธ}/{DB๋ช…}?serverTimezone=Asia/Seoul username: ์‚ฌ์šฉ์ž๋ช… password: ๋น„๋ฐ€๋ฒˆํ˜ธ driver-class-name: com.mysql.cj.jdbc.Driver

JWT Tutorial
BACKEND/Spring 2022. 2. 1. 01:12

JWT - Header, Payload, Signature 3๊ฐœ์˜ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ Header : Signature๋ฅผ ํ•ด์‹ฑํ•˜๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ณด๋“ค ๋‹ด๊ฒจ์žˆ์Œ Payload : ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๊ณ ๋ฐ›๋Š”, ์‹œ์Šคํ…œ์—์„œ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ์ •๋ณด๋“ค์— ๋Œ€ํ•œ ๋‚ด์šฉ ๋‹ด๊ณ  ์žˆ์Œ Signature : ํ† ํฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ์œ„ํ•œ ๋ฌธ์ž์—ด (์œ ํšจํ•œ ํ† ํฐ์ธ์ง€ ๊ฒ€์ฆ)

SpringBoot API ์ฃผ์˜ํ•  ์ 
BACKEND/Spring 2022. 1. 27. 12:44

- ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœํ•˜์ง€ ๋ง๊ณ  DTO ๋ณ€ํ™˜ํ•ด๋ผ - ์ง€์—ฐ ๋กœ๋”ฉ(LAZY)๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ฆ‰์‹œ ๋กœ๋”ฉ(EARGER)๋กœ ์„ค์ •ํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ฆ‰์‹œ ๋กœ๋”ฉ ๋•Œ๋ฌธ์— ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ํ•„์š”์—†๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ญ์ƒ ์กฐํšŒํ•ด์„œ ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•ญ์ƒ ์ง€์—ฐ๋กœ๋”ฉ์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๊ณ , ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ํŽ˜์น˜์กฐ์ธ์„ ์‚ฌ์šฉํ•ด๋ผ! (+์ง€์—ฐ๋กœ๋”ฉ์˜ ๊ฒฝ์šฐ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋Š” ํ”„๋ก์‹œ๋กœ ์„ค์ •๋˜์–ด์žˆ๊ณ  getName()๊ณผ ๊ฐ™์ด ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผ LAZY๊ฐ€ ๊ฐ•์ œ ์ดˆ๊ธฐํ™”๋จ) Controller API ์˜ˆ์‹œ @GetMapping("/api/v3/orders") public List ordersV3() { List orders = orderRepository.findAllWithItem(); List result = orders.strea..

๊ฐ์ฒด์ง€ํ–ฅ์ฟผ๋ฆฌ
BACKEND/Spring 2022. 1. 19. 00:22

1. JPQL - ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ - ๊ฐ์ฒด ์ง€ํ–ฅ SLQ ( ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค SQL์— ์˜์กด x) 2. Criteria - ๋ฌธ์ž๊ฐ€ ์•„๋‹Œ ์ž๋ฐ”์ฝ”๋“œ๋กœ JPQL์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ - ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ณ  ์‹ค์šฉ์„ฑ x 3. QueryDSL - ์ž๋ฐ”์ฝ”๋“œ๋กœ JPQL ์ž‘์„ฑ ๊ฐ€๋Šฅ - ๋™์ ์ฟผ๋ฆฌ ์ž‘์„ฑ ํŽธ๋ฆฌ - ๋‹จ์ˆœํ•˜๊ณ  ์‰ฌ์›€ - ์‹ค๋ฌด ์‚ฌ์šฉ ๊ถŒ์žฅ 4. ๋„ค์ดํ‹ฐ๋ธŒ SQL 5. JDBC API ์ง์ ‘ ์‚ฌ์šฉ, MyBatis, SpringJdbcTemplate ํ•จ๊ป˜ ์‚ฌ์šฉ!!