์ฐ๊ด๋ ์ํฐํฐ์ ๋ํด ์ง์ฐ๋ก๋ฉ์ผ๋ก ์ค์ ์ ํด์ฃผ๋ฉด ์ผ๋ฐ์ ์ธ ์กฐํ ์ฟผ๋ฆฌ์์๋ ์ฐ๊ด๋ ์ํฐํฐ๊น์ง ์กฐํํด์ค์ง ์๊ณ ์ฐ๊ด๋ ์ํฐํฐ๋ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ก ์ค์ ์ด ๋๋ค. ์ด๋ ๊ฒ ๋๋ฉด ์ฐ๊ด๋ ์ํฐํฐ์ ๊ฐ์ ์ ๊ทผํด์ผํ ๋ ๋ฐ์ดํฐ๋ง๋ค ์ฟผ๋ฆฌ๊ฐ ํ๋ฒ์ฉ ๋ ์คํ๋์ด N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๊ฒ์ด Fetch Join ์ด๋ค. ์ฐ๊ด๋ ๊ฒ๋ค์ ํ๋ฒ์ ๋ค ๊ฐ์ ธ์ค๋ ๊ฒ์ผ๋ก ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๊ฐ ์๋๋ผ ์ฐ๊ด๋ ์ํฐํฐ๊น์ง ์ค์ ๊ฐ์ผ๋ก ์ ๋ถ ์ฑ์์ค๋ค. (์ฆ, ์กฐ์ธ๋ง ํ๋ ๊ฒ์ด ์๋๋ผ select ์ ์ ์๋ ๊ฐ๋ค๋ ์ ๋ถ ๋ฃ์ด์ฃผ๋ ๊ฒ) EntityGraph - data jpa๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ fetch join ์ jpql ์์ด ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค. JpaRepository๋ฅผ ์์๋ฐ๋ repository๊ฐ ์์ ๋ @..
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..
detached entity passed to persist ๊ด๋ จ ์๋ฌ๊ฐ ๋จ๋ ๊ฒฝ์ฐ ์ด๋ฏธ ์์ฑ๋์ด ์๋ ๊ฐ์ฒด์ ๋ถ๋ถ์ ๋ค์ ํ๋ฒ ๋ ์ค์ ์ ํด์ฃผ๊ฑฐ๋ ์ ์ฅ์ ํด์ฃผ๋ ค๊ณ ํ ๋ ์๊ธฐ๋ ๊ฒ! ์ฆ, ์ํฐํฐ ์ข ์์ฑ ๋ฌธ์ ๊ฑฐ๋ ๊ฐ์ฒด ์์ฑํ ๋ ๋ฌธ์ ๊ฐ ์๋ ๊ฒ !! ์๋ฅผ ๋ค๋ฉด 1) id ํ๋์ @GeneratedValue๋ฅผ ์ฌ์ฉํด์ ์๋์ผ๋ก ๋ง๋ค์ด์ง๋๋ก ํด๋๊ณ ํ ์คํธํ ๋ id ๊ฐ์ ์ค์ ํด์คฌ๋ค๋๊ฐ.. 2) ์ํฐํฐ๋ค์ ์ฐ๊ด๊ด๊ณ๊ฐ ์กด์ฌํ ๋ ํด๋์คA ์ a1, a2 ์ ์ฐ๊ด๋ ํด๋์คB์ b1 ์ด ์์ ๋ (a1 + b1) ์ ์ฅํ๊ณ (a2 + b1) ์ ์ฅ๋์ด ์ค๋ณต์ผ๋ก ์ ์ฅ๋๋ ๊ฒฝ์ฐ (์ด๋ฐ ๊ฒฝ์ฐ์๋ cascade ๊ด๋ จํด์ ์ค์ ์ ์ ๊ฑฐํด์ฃผ๋๊ฐ ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋๊ฒ ํด์ฃผ๋ฉด ๋ ๋ฏ!)
JWT๋? Json Web Token ์ ์ฝ์๋ก json ๊ฐ์ฒด์ ์ฌ์ฉ์์ ์ผ๋ถ ์ ๋ณด๋ฅผ ๋ด๋๋ค. ์ธ์ ๊ณผ ๋ฌ๋ฆฌ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ๊ฐ ์ค ํ ํฐ์ ๊ฐ์ง๊ณ ์๋ค๊ฐ ํค๋์ ์ค์ด์ ๋ณด๋ด๋ ๋ฐฉ์ (๋จ์ํ๊ฒ ๋งํ๋ฉด ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์) Header : Signature๋ฅผ ํด์ฑํ๊ธฐ ์ํ ์๊ณ ๋ฆฌ์ฆ ์ ๋ณด๋ค ๋ด๊ฒจ์์ Payload : ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์ฃผ๊ณ ๋ฐ๋, ์์คํ ์์ ์ค์ ๋ก ์ฌ์ฉ๋ ์ ๋ณด๋ค์ ๋ํ ๋ด์ฉ ๋ด๊ณ ์์ Signature : ํ ํฐ์ ์ ํจ์ฑ ๊ฒ์ฆ์ ์ํ ๋ฌธ์์ด (์ ํจํ ํ ํฐ์ธ์ง ๊ฒ์ฆ) ์ธ์ ์? ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ์ ์ธ์ฆํ ์ ์ ์ ์ ๋ณด๋ฅผ ์ ์ฅํด๋ ! ๊ทธ๋ฆฌ๊ณ ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์ธ์ฆ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ํต์ ํ๋ ๋ฐฉ์ stateful service๋ ์ธ์ ์ ๋ณด๋ฅผ ์๋ฒ์ ์ ์ฅํ๊ณ ์ธ์ ์ํ์ ๋ฐ๋ฅธ ์๋ต์ ์ฃผ๋ ์๋น์ค! -> EX) ์ธ์ ..
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-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..
** ๊ธฐ๋ณธ์ ์ผ๋ก 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..
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์ ์ ์ฅ๋๋ค.
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 - Header, Payload, Signature 3๊ฐ์ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ Header : Signature๋ฅผ ํด์ฑํ๊ธฐ ์ํ ์๊ณ ๋ฆฌ์ฆ ์ ๋ณด๋ค ๋ด๊ฒจ์์ Payload : ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์ฃผ๊ณ ๋ฐ๋, ์์คํ ์์ ์ค์ ๋ก ์ฌ์ฉ๋ ์ ๋ณด๋ค์ ๋ํ ๋ด์ฉ ๋ด๊ณ ์์ Signature : ํ ํฐ์ ์ ํจ์ฑ ๊ฒ์ฆ์ ์ํ ๋ฌธ์์ด (์ ํจํ ํ ํฐ์ธ์ง ๊ฒ์ฆ)
- ์ํฐํฐ๋ฅผ ์ง์ ๋ ธ์ถํ์ง ๋ง๊ณ DTO ๋ณํํด๋ผ - ์ง์ฐ ๋ก๋ฉ(LAZY)๋ฅผ ํผํ๊ธฐ ์ํด ์ฆ์ ๋ก๋ฉ(EARGER)๋ก ์ค์ ํ๋ฉด ์๋๋ค. ์ฆ์ ๋ก๋ฉ ๋๋ฌธ์ ์ฐ๊ด๊ด๊ณ๊ฐ ํ์์๋ ๊ฒฝ์ฐ์๋ ๋ฐ์ดํฐ๋ฅผ ํญ์ ์กฐํํด์ ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค. ๋ฐ๋ผ์ ํญ์ ์ง์ฐ๋ก๋ฉ์ ๊ธฐ๋ณธ์ผ๋ก ํ๊ณ , ์ฑ๋ฅ ์ต์ ํ๊ฐ ํ์ํ ๊ฒฝ์ฐ์๋ ํ์น์กฐ์ธ์ ์ฌ์ฉํด๋ผ! (+์ง์ฐ๋ก๋ฉ์ ๊ฒฝ์ฐ ์ฐ๊ด๋ ์ํฐํฐ๋ ํ๋ก์๋ก ์ค์ ๋์ด์๊ณ getName()๊ณผ ๊ฐ์ด ์ง์ ํธ์ถํด์ผ LAZY๊ฐ ๊ฐ์ ์ด๊ธฐํ๋จ) Controller API ์์ @GetMapping("/api/v3/orders") public List ordersV3() { List orders = orderRepository.findAllWithItem(); List result = orders.strea..
1. JPQL - ๋ฐ์ดํฐ ๋ฒ ์ด์ค ํ ์ด๋ธ์ด ์๋ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ๋์์ผ๋ก ์ฟผ๋ฆฌ - ๊ฐ์ฒด ์งํฅ SLQ ( ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค SQL์ ์์กด x) 2. Criteria - ๋ฌธ์๊ฐ ์๋ ์๋ฐ์ฝ๋๋ก JPQL์ ์์ฑํ ์ ์์ - ๋๋ฌด ๋ณต์กํ๊ณ ์ค์ฉ์ฑ x 3. QueryDSL - ์๋ฐ์ฝ๋๋ก JPQL ์์ฑ ๊ฐ๋ฅ - ๋์ ์ฟผ๋ฆฌ ์์ฑ ํธ๋ฆฌ - ๋จ์ํ๊ณ ์ฌ์ - ์ค๋ฌด ์ฌ์ฉ ๊ถ์ฅ 4. ๋ค์ดํฐ๋ธ SQL 5. JDBC API ์ง์ ์ฌ์ฉ, MyBatis, SpringJdbcTemplate ํจ๊ป ์ฌ์ฉ!!