묻고 답해요
167만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결실전에서 바로 써먹는 Elasticsearch 입문 (검색 최적화편)
spring boot project 에 테이블을 여러 개 만드는 경우의 설정을 알고 싶습니다.
안녕하세요.spring boot project 에 테이블을 여러 개 만드는 경우의 설정을 알고 싶습니다.강의에서는 products 테이블과 index 하나이지만실제로 프로젝트를 하게 되면 테이블을 여러 개 만들게 됩니다.가령, 학사관리 시스템의 경우 필요한 테이블이,student, professor, department, subject, course_registration.. 최소한 이정도는 있어야 되는데요...이러한 경우, Spring Boot JPA + Elasticsearch 조합으로 프로젝트를 진행하게 되는데. 테이블이 여러 개 있는 경우입니다.관리자 페이지이도 있어야 되고요.학생과 교수님의 경우에는 학생검색, 교수님 검색, 과목 검색, 학과 검색을 해야 되고, 관리자는 모두 다 검색할 수 있어야 됩니다. (수강신청내역검색 추가) 이런 경우에는 settings.json 파일을 어떻게 설정해야 되는지요?자세한 답변 부탁드립니다.
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
시작하려는데 계속 오류가 발생합니다.
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "drop table if exists [*]user cascade "; expected "identifier"; SQL statement:버전도 맞췄는데 뭐가 문제일까요
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
스프링 JdbcTemplate에서 H2에 테이블이 없다는 오류 발생
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]
-
미해결[1.5탄] 옆집 개발자와 같이 진짜 이해하며 만들어보는 첫 Spring Boot 프로젝트
섹션 5 의 18 대췅
커리큘럼 섹션 5 의 강의 18제목에 대췅 이라고... 의도 하신 거라면 괜찮습니다 ㅎㅎㅎ 혹시나 해서 알려 드려요.
-
해결됨스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
수강중에 궁금한것이 생겨 질문드립니다.
안녕하세요 좋은강의 감사드립니다. 제 주변도 사서 듣는다고 합니다.예전에 완강해놓고 관련프로젝트를 하다 궁금한점이 생겼습니다. 이런식으로 분리된 구조라면, 유저 정보는 어떻게 가져오는건가요??예를들어서 게시판이면, 거기에 들어가면 게시글들이나 댓글들 뿐만 아니라 유저의 닉네임이라던가, 유저가 설정한 대표이미지 라던가 등등 유저정보에 관한것들도 같이 뷰 렌더링을 위해선 필요한 정보들일텐데 유저와 관련된 서비스도 뭔가 따로 분리가 되어있을것 같은데 이때 유저 정보들은 어떻게 같이 가져오는지 궁금합니다.디비도 다 따로 사용할텐데 연관관계매핑도 아닐테고...모르겠네요
-
해결됨Spring Boot, AWS로 백엔드 서비스 한 사이클 완성하기
jakarta persistence 플러그인은 intellij ultimate에서만 사용가능하다고 나오네요.
jakarta persistence 플러그인은 intellij ultimate에서만 사용가능하다고 나오네요. 강의 내용에도 추가를 해주셔야 할 듯합니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO 대신 Form 사용은 안되나요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용]회원 등록 api 에서 아래 코드 처럼 saveMemberV1 메서드의 반환값은 new CreateMemberResponse(id)입니다. @PostMapping("/api/v1/members") public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){ Long id = memberService.join(member); return new CreateMemberResponse(id); } 근데 MemberForm.java 에 id를 추가하고 이걸로 리턴받으면 안되나요?왜 굳이 DTO 를 만들어서 리턴하나요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
실무에서 테스트 케이스 작성 시
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요, 강의 수강 잘 하던 도중 질문이 생겨 여쭤봅니다. 강의에서는 Service 계층에서만 테스트를 하고 있고 Repository 계층에서는 따로 진행하지 않고 있습니다.실무에서도 어차피 Service 계층이 Repository 계층을 당겨서 사용하는 것이기에 Service 계층에 대해서만 테스트 케이스를 작성하면 충분할까요 ?그리고 강의에서 Member의 Name을 unique로 잡으라고 말씀하시고 있는데, 실무에서는 id로 검증하는 것이 올바른 방법이겠죠 ?
-
미해결서버개발자 과제전형 완벽가이드 - 1편
Spring Cloud 버전 관리 문제
자바 21, 스프링 부트 3.4.5로 하는데dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:2024.0.1" } }이 부분이 에러가 나는거 같아요Execution failed for task ':dependencies'.> Could not resolve all artifacts for configuration ':detachedConfiguration3'. > Cannot resolve external dependency org.springframework.boot:spring-boot-dependencies:3.4.5 because no repositories are defined. Required by: root project :Possible solution: - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html빌드가 안되네요 ㅠㅠ
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
강의 자료를 PDF로 받아볼 수 없나요?
강의 자료를 PDF로 받아볼 수 없나요?? 제목이 곧 질문입니다!
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
로그인 관련 커스텀 훅 만들기 -> 부분 질문입니다.
현재 loginSlice.tsx에서 오류가 나고 있습니다..아래와 같은 메세지를 접했습니다.useCustomLogin.tsx:2 Uncaught SyntaxError: The requested module '/src/store.tsx' does not provide an export named 'AppDispatch' (at useCustomLogin.tsx:2:10) 어느부분을 손 봐야할까요?vite 6.3버전으로 이용하고 있습니다. loginSlice.tsximport { createAsyncThunk, createSlice } from "@reduxjs/toolkit" import { loginPost } from "../api/memberApi" import { removeCookie, setCookie } from "../util/cookieUtil" export interface LoginInfo { email:string, nickname:string, accessToken: string, refreshToken: string, roleNames: string[], status: string } const initState:LoginInfo = { email: '', nickname: '', accessToken:'', refreshToken: '', roleNames: [], status: '' } export const loginPostAsync = createAsyncThunk('loginPostAsync', ({email, pw}: {email:string, pw:string}) => { console.log("---------------loginPostAsync---------------------") console.log(email, pw) return loginPost(email, pw) }) const loginSlice = createSlice({ name: 'loginSlice', initialState: initState, reducers: { save: (state, action) => { console.log("save...........") return action.payload }, logout: (state, action) => { console.log("logout..........") removeCookie("member") } }, extraReducers :(builder) => { builder.addCase(loginPostAsync.fulfilled , (state, action) => { console.log("loginPostAsync.fulfilled") const newState:LoginInfo = action.payload newState.status = 'fulfilled' setCookie("member", JSON.stringify(newState), 1) return newState }) .addCase(loginPostAsync.pending, (state, action) => { console.log("loginPostAsync.pending") state.status = 'pending' }) .addCase(loginPostAsync.rejected, (state, action) => { console.log("loginPostAsync.rejected") state.status = 'rejected' }) } }) export const { save, logout} = loginSlice.actions export default loginSlice.reducer useCustoLogin.tsximport { useDispatch, useSelector } from "react-redux" import { AppDispatch, RootState } from "../store" import { Navigate, useNavigate } from "react-router" import { loginPostAsync, logout, save } from "../slices/loginSlice" import { useEffect } from "react" import { getCookie } from "../util/cookieUtil" const useCustomLogin = () => { const dispatch = useDispatch<AppDispatch>() //로그인 상태 객체 const loginState = useSelector((state: RootState) => state.loginSlice) //로그인 여부 const loginStatus = loginState.status //fulfilled, pending, rejected useEffect(()=> { if(! loginStatus ) { const cookieData = getCookie("member") if(cookieData){ dispatch(save(cookieData)) } } }, []) const navigate = useNavigate() const doLogin = async (email:string, pw:string) => { dispatch(loginPostAsync({ email, pw })) } const doLogout = () => { dispatch(logout(null)) } const moveToLogin = () => { navigate("/member/login") } const moveToLoginReturn = () => { //--------로그인 페이지로 이동 컴포넌트 return <Navigate replace to="/member/login"/> } const moveToPath = (path:string) => { //----------------페이지 이동 navigate({pathname: path}, {replace:true}) } return {loginState, loginStatus, doLogin, doLogout,moveToLogin,moveToLoginReturn,moveToPath} } export default useCustomLogin store.tsximport { configureStore } from "@reduxjs/toolkit"; import loginSlice from "./slices/loginSlice"; const store = configureStore({ reducer: { "loginSlice": loginSlice, } }) export type AppDispatch = typeof store.dispatch export type RootState = ReturnType<typeof store.getState> export default store
-
미해결나도! 스프링으로 인공지능을 할 수 있다(인프1탄)
.getText()와 .getContent()질문입니다.
.getResult() .getOutput() .getText(); } .getoutput 다음 getContent가 있어야 하는데 gettext만 있습니다. getContent는 생성이 되지 않습니다. 똑같이 수업보면서 했는데 왜그런지 모르겠습니다. 물론 결과값은 설명하신 대로 똑같이 나오는기는 하는데 차이가 없나요?
-
해결됨개발자에게 필요한 로그 관리
학습내용 블로그 개재 여부
안녕하세요 학습 목적으로 블로그에 강의내용을 정리하고 있는데 혹시 기재해도 될까요?
-
미해결카카오,구글 SNS 로그인(springboot3, vue3)
github 주소 어디서 확인가능한가요?
소스코드 올라온 github 주소 어디서 확인이 가능할까요?
-
해결됨Spring Boot TDD - 입문부터 실전까지 정확하게
assertThat 상태 코드 비교
학습 관련 질문을 남겨주세요. 구체적으로 적을수록 좋아요!마크다운과 단축키를 활용하면 글을 더 편하게 작성할 수 있어요.커뮤니티 질문 & 답변에 비슷한 내용이 있었는지 먼저 검색해보세요.서로 예의를 지키며 존중하는 분위기를 함께 만들어가요.잠깐! 인프런 서비스 관련 문의는 1:1 문의하기를 이용해 주세요안녕하세요 좋은 강의 만들어주셔서 감사합니다. 실무에 적용할 수 있도록 열심히 듣고 있습니다.강의 내용과는 조금 거리가 있는 질문일수도 있겠으나 궁금해져서 여쭤봅니다. assertThat으로 응답코드 검증 시 getStatusCode().value() 와 200으로 직접 코드값을 검증하시는 이유가 있을까요? getStatusCode() 와 HttpStatus.OK 로 enum 타입 검사가 의도가 명확하지 않나? 라는 의문이 들어서 특별한 이유가 있으신 건지 궁금해서 질문 남겨봅니다
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
과제를 위한 초기세팅
안녕하세요 과제를 하나씩 만들고있는데 4일차 과제인 api만들기를 하려고합니다! 그전까지는위처럼 기존 강의 초기세팅 된곳에 hw폴더를 만들어서 하고있는데 이렇게 말고 강의초반에 배운대로 spring.io에서 초기세팅을 새로해서 과제를 위한 스프링부트 프로젝트를 새로 만들고싶은데요..! 혹시 현재 강의 초기세팅과 같이 하려면 어떻게해야될지 알려주실 수 있으신가요? 1~2강 초기세팅 강의에서 spring.io로 처음부터 만드는걸 배울때 자바나 스프링부트 버전설정이런건 설명이 있었는데 그다음 의존성 이런건 나중에 설명이 나온다했던거같아서 정확히 모르겠습니다.강의에 혹시 있다면 어디를 참고하면 될지만이라도 알려주시면 감사드리겠습니다!!
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
안녕하세요. 토비님! 도메인의 다양한 업데이트 요구사항을 Web API 계층에서 어떻게 다뤄야 할까요?
안녕하세요, 토비님. 강의를 들으며 많은 인사이트를 얻고 있습니다.강의를 완강한 후에도 내면적으로 정리되지 않은 부분이 있어 조심스럽게 질문을 드리게 되었습니다.생성과 관련된 설계는 강의에서 잘 이해가 되었지만, 업데이트(update)와 관련된 내용은 직접적으로 다뤄지지 않아 고민이 생겼습니다. 특히, 제 고민은 다음과 같습니다."도메인의 비즈니스 규칙이 Web API 설계에 어느 정도까지 직접적으로 드러나야 하는가?"현재 도메인 로직에서는 사용자의 여러 정보를 변경할 수 있는 비즈니스 규칙이 존재합니다. 예를 들어:비밀번호 변경 기타 세부정보 변경비즈니스적으로는 각각의 규칙이 잘 정의되어 있고, 각각의 변경 로직도 Member 객체 내에 명확히 메서드로 존재합니다.여기서, 이러한 비즈니스에 대해서 API에 어떻게 노출시켜야 하는가에 대해서 두 가지 선택지가 고려됩니다.1. 비즈니스 정의를 역할 별로 구성한다.POST /api/v1/members/{id}/change-password POST /api/v1/members/{id}/change-nickname생각이 나는 장단점은 다음과 같습니다.장점: 비즈니스에 따라 API를 관리하여 클라이언트가 이해하기 용이합니다.단점: 수정 가능한 필드가 많아질수록 API의 개수가 증가하며, 유지보수가 어려워질 수 있고, Restful 규칙에 위배됩니다.2. 하나의 update API로 통합한다.PATCH /api/v1/members/{id} { "password": "originalPassword123!", // nullable "detailRequest": { // nullable "email": "user@example.com", "nickname": "nickname123", "password": "newPassword456!" } }장점: API가 간결하여 확장이 용이하며, 클라이언트는 필요한 값만 상황에 따라 요청하면 됩니다.단점: API가 비즈니스 책임에 명확하지 않을 수 있습니다.결론적인 질문은 다음과 같이 정리 할 수 있을 것 같습니다.비즈니스 로직이 도메인 레이어에 잘 분리되어 있는 경우, API 계층에서도 분리하여 표현하는 것이 좋은가요?도메인의 역할만 명확하다면 API는 통합해서 update 형식으로 만들어도 괜찮은가요?만약, 후자로 처리를 한다면 어디서 처리를 하는게 좋아보이시나요?서비스 계층도메인 계층// MemberModifyService public void update(Long memberId, MemberUpdateRequest request) { Member member = memberFinder.find(memberId); if (request.password() != null) { member.changePassword(request.password()); } if (request.detailRequest() != null) { member.updateInfo(); } } -------- // MemberModifyService public void update(Long memberId, MemberUpdateRequest request) { Member member = memberFinder.find(memberId); member.update(request); } // Member public void update(MemberUpdateRequest request) { if (request.password() != null) { changePassword(request.password()); } if (request.detailRequest() != null) { updateInfo(); } }뭔가, 이런 고민이 계속 드는 이유가 외부 계층에 종속적이지 않고 도메인에 의존하여 개발을 하더라도 실제로 저희가 처한 상황은 대부분 WebAPI 계층에서의 요청이 많다보니 외부의 행위 또한 도메인에 종속되어야 하는가 하는 고민이 생긴 것 같습니다. 양질의 강의 제공해주셔서 감사드립니다!
-
해결됨스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
Snowflake처럼 동적으로 생성되는 ID, Mock 테스트가 올바른 접근법일까요?
14:42 에서 Snowflake 알고리즘으로 articleId를 생성한 후 DB에 저장된 121530268440289280L값을 사용해서 테스트 코드를 작성하시는 것을 보고,실제로 Snowflake를 도입해서 Id를 생성하고 같은 방식으로 테스트 코드를 작성한다면 DB에 종속적이라서 반복적으로 테스트 코드를 실행할 때 테스트 코드의 유지보수에서 문제가 발생할 수 있을 거라는 생각이 들었습니다.이런 문제를 막기 위해서 테스트 시에는 Mock 객체를 사용해 미리 정해진 Snowflake가 고정 ID 값을 반환하도록 하는 방식으로 테스트 코드를 작성하는게 맞는건지 궁금해서 질문글을 남기게 되었습니다.
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
@NaturalIdCache에 대한 보충 설명 및 사용법 공유
'25. 엔티티의 자연키 지정' 영상의 후반부에 적용한 @NaturalIdCache에 대해 추가로 학습한 내용이, 저처럼 해당 애노테이션을 처음 접한 분들에게 도움이 될 것 같아서 글을 작성합니다. 강의에서 오해가 있을 수 있는 부분, 그리고 자연키에 캐시를 적용하는 방법을 정리해 보았습니다. 강의 내용과 실제 동작의 차이점강의에서는 “같은 트랜잭션 안에서 같은 아이디 값을 가지고 여러 번 조회 시 Persistence Context 에 캐시된 값을 꺼내오는 것 처럼. @NaturalIdCache를 적용하면 이것도 영속 컨텍스트에 캐싱이 된다.”고 말씀하셨습니다. 해당 내용에 대한 이해를 돕기 위해 Hibernate의 두 가지 캐시에 대해 간단히 짚고 넘어가겠습니다.1차 캐시 (First-Level Cache): 세션(영속성 컨텍스트) 범위의 캐시입니다. 같은 트랜잭션 안에서만 유효하며, 트랜잭션이 끝나면 사라집니다. Spring Data JPA에서는 기본적으로 @Id 에 대한 조회를 1차 캐시합니다. 2차 캐시 (Second-Level Cache): 세션 팩토리 범위의 캐시로, 여러 세션에서 데이터를 공유할 수 있습니다. 적용하려면 별도의 의존성 추가 및 캐시 관련 설정(@Cache 등)이 필요합니다. 따라서, "같은 트랜잭션 안에서 캐시된 값을 꺼내온다."는 말은 세션 범위의 1차 캐시로 해석됩니다. 하지만 제가 직접 테스트해 본 결과, @NaturalIdCache는 1차 캐시가 아닌 2차 캐시와 관련이 있었으며, 1차 캐시를 적용하기 위해서는 다른 방법이 필요했습니다. 테스트를 통한 확인자연키에 대한 1차 캐시 동작을 확인하기 위해, 강의에서 적용한 Member 엔티티의 @NaturalIdCache 를 제거하고, 자연키(Email)에 @NaturalId만 적용한 상황에서 두 가지 방식으로 테스트를 진행했습니다. 테스트1: findByEmail 메서드를 사용한 조회Java@Test void NaturalIdFirstLevelCache() { Member member = Member.register(createMemberRegisterRequest(), createPasswordEncoder()); memberRepository.save(member); entityManager.flush(); entityManager.clear(); System.out.println("회원 저장 및 persistence context 초기화 완료"); // 같은 email(Natural ID)로 두 번 조회 Member findMember1 = memberRepository.findByEmail(member.getEmail()).get(); Member findMember2 = memberRepository.findByEmail(member.getEmail()).get(); assertThat(findMember1).isSameAs(findMember2); } Spring Data의 쿼리 메서드를 사용하여 이메일로 조회하는 findByEmail 메서드를 만들고, 한 트랜잭션에서 같은 회원을 두 번 조회했습니다. 자연키에 대한 1차 캐시가 동작한다면, SELECT 쿼리는 한 번만 실행되어야 합니다.결과는 SELECT 쿼리가 두 번 실행되었습니다. 즉, 자연키에 대한 1차 캐시가 동작하지 않았습니다. 테스트2: Hibernate의 자연키 관련 API를 사용한 조회@NaturalId를 다루는 글들을 찾아본 결과 Hibernate가 제공하는 자연키 관련 API가 있다는 것을 확인했고, 이를 적용하기 위해 커스텀 리포지토리를 구현했습니다.Java@Repository @RequiredArgsConstructor public class CustomizedMemberRepositoryImpl implements CustomizedMemberRepository { private final EntityManager entityManager; @Override public Optional<Member> findByNaturalId(Email naturalId) { return entityManager.unwrap(Session.class) .bySimpleNaturalId(Member.class) .loadOptional(naturalId); } } 그리고, 테스트 1과 같은 방식으로 테스트를 진행하였습니다. @Test void NaturalIdApi() { Member member = Member.register(createMemberRegisterRequest(), createPasswordEncoder()); memberRepository.save(member); entityManager.flush(); entityManager.clear(); System.out.println("회원 저장 및 persistence context 초기화 완료"); Member findMember1 = memberRepository.findByNaturalId(member.getEmail()).get(); Member findMember2 = memberRepository.findByNaturalId(member.getEmail()).get(); assertThat(findMember1).isSameAs(findMember2); }결과는 SELECT 쿼리가 한 번만 실행되었습니다. 이를 통해 자연키에 대한 1차 캐시는 @NaturalIdCache 애노테이션과 무관하게, 전용 API를 사용해야만 동작하는 것을 확인했습니다. @NaturalIdCache의 용도@NaturalIdCache Javadoc에는 다음과 같은 설명이 있습니다.Specifies that mappings from the natural id values of the annotated entity to the corresponding entity id values should be cached in the shared second-level cache.…중략This annotation is usually used in combination with Cache, since a round trip may only be avoided if the entity itself is also available in the cache.대략 “natural id와 상응하는 id에 대한 매핑을 2차 캐시에 저장하는 애노테이션이고, 엔티티가 캐시되어있어야 하기 때문에 일반적으로 Cache와 함께 사용된다.”라고 해석됩니다. 즉, 1차 캐시가 아닌 2차 캐시를 위한 애노테이션입니다. 정리2차 캐시 관련 설정 및 테스트를 마저 진행한 후 최종 정리한 내용은 다음과 같습니다. 자연키의 1차 캐시@NaturalIdCache 애노테이션과 관련 없습니다. 자연키에 @NaturalId만 붙이면 됩니다.반드시 Hibernate Session의 bySimpleNaturalId() 같은 전용 API를 사용해야 적용됩니다. 자연키의 2차 캐시@Cache와 @NaturalIdCache를 함께 사용해야 동작합니다.@Cache만 사용 시 @Id로 조회할 때만 2차 캐시가 동작합니다.@NaturalIdCache만 사용 시 자연키와 ID에 대한 매핑 정보는 캐시 히트되는 걸 확인했지만, ID와 엔티티에 대한 캐시가 없어서 캐시가 적용되지 않았습니다. @Cache와 @NaturalIdCache 모두 사용 시 ID를 통한 조회와 자연키를 통한 조회 모두 2차 캐시가 적용됩니다. 참고 자료Hibernate6.6 공식 문서NaturalCache javadocsbaeldung: Hibernate Natural IDs in Spring BootSpring Custom Repository 글의 오류나 부족한 내용을 알고 계신 분은 코멘트를 달아주시면 감사하겠습니다.
-
해결됨스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
ArticleApiTest 에서 정적 내부 클래스를 사용하는 이유는?
ArticleCreateRequest, ArticleUpdateRequest은 ArticleApiTest 클래스 내부에 따로 만들어서 사용하고 있는데 이미 만들어진 클래스를 사용하지 않고 테스트 클래스 내부에서 작성해서 사용하는 이유가 뭔지 궁금합니다. 감사합니다.