묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
자동리소스등록?
src/main/resources/application.properties```groovy spring.profiles.active=local spring.datasource.url=jdbc:h2:tcp://localhost/~/test spring.datasource.username=sa ```이렇게 설정만 하면 스프링 부트가 해당 설정을 사용해서 커넥션 풀과 DataSource, 트랜잭션 매니저를 스프링 빈으로 자동 등록한다.(앞에서 학습한 스프링 부트의 자동 리소스 등록 내용을 떠올려보자.) 이 부분에서 자동 리로스 등록내용이 어디 강의에 있나요..?
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
JWT와 @PreAuthorize 사용하기에서 권한오류
동영상 강의에 있는 내용대로 ProductController에서 @GetMapping("/list")에 @PreAuthorize("hasAnyRole('ROLE_USER','ROLE_ADMIN')")를 작성하고나서 postman에 login 후 accessToken을 가져와서 get방식으로 토큰을 넣어서 입력하면 status : 500, "error": Interner Server Error가 뜹니다.. @PreAuthorize부분을 주석처리하고 실행해보면 list값이 잘 나오네요.. 어디부분이 잘못 된걸까요?? 참고로 CustomSecurityConfig클래스에 @EnableMethodSecurity추가도 했습니다.@PreAuthorize("hasAnyRole('ROLE_USER','ROLE_ADMIN')") @GetMapping("/list") public PageResponseDTO<ProductDTO> list(PageRequestDTO pageRequestDTO){ return productService.getList(pageRequestDTO); } 여기가 ProductController 클래스 package org.zerock.apiserver.security.filter; import com.google.gson.Gson; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.log4j.Log4j2; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; import org.zerock.apiserver.dto.MemberDTO; import org.zerock.apiserver.util.JWTUtil; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.Map; @Log4j2 public class JWTCheckFilter extends OncePerRequestFilter { @Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { //true == not check String path = request.getRequestURI(); log.info("------check uri---------"+path); if(path.startsWith("/api/member/")){ return true; } //false == check return false; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { log.info("----------------------"); log.info("----------------------"); log.info("----------------------"); String autoHeaderStr = request.getHeader("Authorization"); //bearer // 7개 후 JWT 문자열 try { String accessToken = autoHeaderStr.substring(7); Map<String, Object> claims = JWTUtil.validateToken(accessToken); log.info("JWT claims: " + claims); // filterChain.doFilter(request, response); String email = (String) claims.get("email"); String pw = (String) claims.get("pw"); String nickname = (String) claims.get("nickname"); Boolean social = (Boolean) claims.get("social"); List<String> roleNames = (List<String>) claims.get("roleNames"); MemberDTO memberDTO = new MemberDTO(email, pw, nickname, social.booleanValue(), roleNames); log.info("---------------------------------"); log.info(memberDTO); log.info(memberDTO.getAuthorities()); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(memberDTO, pw, memberDTO.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authenticationToken); filterChain.doFilter(request, response); }catch(Exception e){ log.error("JWT Check Error --------------------"); log.error(e.getMessage()); Gson gson = new Gson(); String msg = gson.toJson(Map.of("error", "ERROR_ACCESS_TOKEN")); response.setContentType("application/json"); PrintWriter printWriter = response.getWriter(); printWriter.println(msg); printWriter.close(); } //destination filterChain.doFilter(request, response); } } 여기가 JWTCheckFilter부분입니다.
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
REQUIRES_NEW 내부 커밋, 외부 롤백 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]Requires_new를 통해 내부 트랜잭션이 시작되고 내부 트랜잭션은 커밋, 외부 트랜잭션은 롤백이라고 했을 때 그대로 동작한다고 이해하면 될까요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
OrderServiceTest id to load is required for loading
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]OrderServiceTest에서id to load is required for loadingorg.springframework.dao.InvalidDataAccessApiUsageException: id to load is required for loading에러가 발생합니다. ID값이 왜 NULL인지 찾고 있는데 잘 모르겠네요.. 도움요청합니다. package jpabook.jpashop.service; import jakarta.persistence.EntityManager; import jpabook.jpashop.domain.Address; import jpabook.jpashop.domain.Member; import jpabook.jpashop.domain.Order; import jpabook.jpashop.domain.OrderStatus; import jpabook.jpashop.domain.item.Book; import jpabook.jpashop.domain.item.Item; import jpabook.jpashop.repository.OrderRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @Transactional class OrderServiceTest { @Autowired EntityManager em; @Autowired OrderService orderService; @Autowired OrderRepository orderRepository; @Test public void 상품주문() throws Exception { //given Member member = new Member(); member.setName("회원1"); member.setAddress(new Address("서울", "강가", "123-123")); em.persist(member); Book book = new Book(); book.setName("시골 JPA"); book.setPrice(10000); book.setStockQuantity(10); //when int orderCount = 2; Long orderId = orderService.order(member.getId(), book.getId(), orderCount); //then Order getOrder = orderRepository.findOne(orderId); assertEquals(OrderStatus.ORDER, getOrder.getStatus(), "상품 주문시 상태는 ORDER"); } @Test public void 주문취소() throws Exception { //given //when //then } @Test public void 상품주문_재고수량초과() throws Exception { //given //when //then } }
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
강의 화면이 나오지 않고 소리만 납니다.
섹션1의 'Cloud Native Architecture', 'Cloud Native Application' 강의에서 영상이 나오지 않는데 원래 그런건가요? 아래처럼 까맣게 아무것도 안나오고 소리만 납니다.
-
해결됨Spring Boot와 React로 배우는 초간단 REST API 게시판 만들기
SpringBoot 초기세팅 수강중 오류가 있어 문의드립니다.
안녕하세요?처음 수강중인데 오류가 있어 문의드립니다.SpringBoot 초기세팅 수강중인데 서버 실행시 아래와 같이 오류가 발생합니다.이런경우 어떻게 처리해야 하나요?
-
미해결Practical Testing: 실용적인 테스트 가이드
CQRS에 대한 jpa interface에 대한 궁금증..
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요 우빈님!테스트 강의 복습 중인데, 다시 들으니깐 너무 재밌네요... 다름 아니라, CQRS 에 따라서 강의를 진행하면서도 Controller와 Service를 CQRS에 따라 분리하고 있습니다.(패키지가 많아지긴하네요..ㅎㅎ..)그런데 궁금한 부분은 Repsitory쪽인데,JpaRepository를 상속받는 인터페이스들(강의로 예를 들면 ProductRepository, StockRepository, OrderRepository가 있겠네요)같은 경우인데, sprind data jpa 인터페이스에 CRUD 중에 CD 에 대한 책임을 줄 수는 있겠다 생각했고,U 는 변경감지에 책임을 맡기면 되겠다고 생각했습니다.. 그런데, 쿼리메서드 부분이 모호한데요.작성했던 쿼리 메서드 같은 경우는 Query에 대한 부분인데 책임을 분리하려고보니, command에 query가 묶여있는 형태더라고요.. 이 부분은 어떻게 나누는지가 궁금합니다..제 짧은 지식 선에서는 QueryDSL 로 나눠야 하나 싶지만, 쿼리 메서드라는 편리한 것이 있는데 굳이 돌아가는 것 같다는 느낌이 드네요제가 굳이 나누려는건지 싶기도 하구요...조언을 구해봅니다..
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
강의 수강에 대한 질문입니다,
선생님 강의 정말 잘 듣고 있고, 설명도 천천히 상세히 해주셔서 열심히 듣고 있습니다. 그러나 듣으면서 개념 자체는 이해가 가는데 코딩과정에서 순수하게 코드 자체가 문법적으로 이해가 안되면 일단 이 강의는 접어두고 자바부터 다시 시작해야 할까요? ㅜㅜ
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
변경 감지
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하십니까 선생님, 영속성 컨텍스트의 변경 감지에서 질문있습니다. 강의 내용 중 엔티티 클래스에는 가급적 Setter를 사용하지 말라고 하셨는데(특히 실무에서) 변경 감지라는 게 엔티티를 조회하여 영속성 컨텍스트에 저장을 해야 이 영속성 컨텍스트의 스냅샷을 통해 엔티티 필드의 값에 변경이 일어났을 때 update를 시키는 것이고 결국 엔티티의 필드를 수정 해야 하는데 그럼 필드를 수정하기 위해선 또 결국 Setter를 사용할 수밖에 없는 것 아닌가요???
-
미해결실전! 스프링 데이터 JPA
UsernameOnlyDto 타입 type mismatch 오류
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.UsernameOnly 인터페이스 타입과 지네릭스 타입으로 결과는 문제 없이 동작하지만UsernameOnlyDto 타입으로 결과 값을 받으려고 findProjectionsByUsername를 호출하면 type mismatch 오류가 생깁니다. Specified result type [study.datajpa.dto.UsernameOnlyDto] did not match Query selection type [study.datajpa.entity.Member] - multiple selections: use Tuple or arrayList<UsernameOnlyDto> result = memberRepository.findProjectionsByUsername("m1");package study.datajpa.dto; public class UsernameOnlyDto { private final String username; public UsernameOnlyDto(String username) { this.username = username; } public String getUsername() { return username; } }// List<UsernameOnly> findProjectionsByUsername(@Param("username") String username); List<UsernameOnlyDto> findProjectionsByUsername(@Param("username") String username); <T> List<T> findProjectionsByUsername(@Param("username") String username, Class<T> type); org.springframework.orm.jpa.JpaSystemException: Specified result type [study.datajpa.dto.UsernameOnlyDto] did not match Query selection type [study.datajpa.entity.Member] - multiple selections: use Tuple or array at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:341) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:241) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:560) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:343) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:136) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223) at jdk.proxy2/jdk.proxy2.$Proxy149.findProjectionsByUsername(Unknown Source) at study.datajpa.repository.MemberRepositoryTest.projections(MemberRepositoryTest.java:403) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Suppressed: org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:804) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:758) at org.springframework.test.context.transaction.TransactionContext.endTransaction(TransactionContext.java:135) at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:272) at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:488) at org.springframework.test.context.junit.jupiter.SpringExtension.afterEach(SpringExtension.java:275) ... 2 moreCaused by: org.hibernate.query.QueryTypeMismatchException: Specified result type [study.datajpa.dto.UsernameOnlyDto] did not match Query selection type [study.datajpa.entity.Member] - multiple selections: use Tuple or array at org.hibernate.query.sqm.internal.SqmUtil.throwQueryTypeMismatchException(SqmUtil.java:1272) at org.hibernate.query.sqm.internal.SqmUtil.verifyResultType(SqmUtil.java:1209) at org.hibernate.query.sqm.internal.SqmUtil.verifySelectionType(SqmUtil.java:1159) at org.hibernate.query.sqm.internal.SqmUtil.verifySingularSelectionType(SqmUtil.java:1114) at org.hibernate.query.sqm.internal.SqmUtil.checkQueryReturnType(SqmUtil.java:1088) at org.hibernate.query.sqm.internal.SqmUtil.checkQueryReturnType(SqmUtil.java:1049) at org.hibernate.query.sqm.internal.SqmUtil.validateQueryReturnType(SqmUtil.java:1040) at org.hibernate.query.sqm.tree.select.SqmSelectStatement.validateResultType(SqmSelectStatement.java:153) at org.hibernate.query.sqm.internal.QuerySqmImpl.<init>(QuerySqmImpl.java:240) at org.hibernate.internal.AbstractSharedSessionContract.createCriteriaQuery(AbstractSharedSessionContract.java:1483) at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:1443) at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:143) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:320) at jdk.proxy2/jdk.proxy2.$Proxy136.createQuery(Unknown Source)
-
해결됨코드로 배우는 React 19 with 스프링부트 API서버
access Token 만료 후 todo/list 접속시도 에러 처리
안녕하세요.access Token 정보 만료 후에 서버에서 보내는 메시지가 401 메시지로 옵니다.그래서인지 jwtUtil.js 파일에서 처리를 못하는 문제가 있는 것이 맞을까요?responseFail 을 아래와 같이 수정하는게 맞는지 무엇을 놓치고 있는 것인지 모르겠습니다.http://localhost:3000/todo/list 를 10분 이상 경과후 실행했을 때 에러 메시지를 출력했었습니다.import axios from "axios"; import {getCookie, setCookie} from "./cookieUtil"; import {API_SERVER_HOST} from "../api/hostApi"; const jwtAxios = axios.create() const refreshJWT = async (accessToken, refreshToken) => { const host = API_SERVER_HOST const header = {headers: {"Authorization": `Bearer ${accessToken}`}} const res = await axios.get(`${host}/api/member/refresh?refreshToken=${refreshToken}`, header) console.log("----------------------") console.log(res.data) return res.data } //before request const beforeReq = (config) => { console.log("before request.............") const memberInfo = getCookie("member") if (!memberInfo) { console.log("Member NOT FOUND") return Promise.reject( { response: { data: {error: "REQUIRE_LOGIN"} } } ) } const {accessToken} = memberInfo // Authorization 헤더 처리 config.headers.Authorization = `Bearer ${accessToken}` return config } //fail request const requestFail = (err) => { console.log("request error............") return Promise.reject(err) } //before return response const beforeRes = async (res) => { console.log("before return response...........") console.log(res) //'ERROR_ACCESS_TOKEN' const data = res.data if (data && data.error === 'ERROR_ACCESS_TOKEN') { const memberCookieValue = getCookie("member") const result = await refreshJWT(memberCookieValue.accessToken, memberCookieValue.refreshToken) console.log("refreshJWT RESULT", result) memberCookieValue.accessToken = result.accessToken memberCookieValue.refreshToken = result.refreshToken setCookie("member", JSON.stringify(memberCookieValue), 1) //원래의 호출 const originalRequest = res.config originalRequest.headers.Authorization = `Bearer ${result.accessToken}` return await axios(originalRequest) } return res } //fail response const responseFail = async (err) => { console.log("response fail error.............") console.log(err) const originalRequest = err.config; // 토큰 만료로 인한 401 응답이라면 → refresh 시도 if ( err.response && err.response.status === 401 && !originalRequest._retry // 무한 루프 방지 ) { originalRequest._retry = true; const memberCookieValue = getCookie("member"); try { const result = await refreshJWT( memberCookieValue.accessToken, memberCookieValue.refreshToken ); // 토큰 저장 memberCookieValue.accessToken = result.accessToken; memberCookieValue.refreshToken = result.refreshToken; setCookie("member", JSON.stringify(memberCookieValue), 1); // 원래 요청 재시도 originalRequest.headers.Authorization = `Bearer ${result.accessToken}`; return await axios(originalRequest); } catch (refreshError) { console.error("Refresh 실패, 로그아웃 처리 필요"); // 로그아웃 로직 연결 가능 localStorage.removeItem("token"); return Promise.reject(refreshError); } } return Promise.reject(err); } jwtAxios.interceptors.request.use(beforeReq, requestFail) jwtAxios.interceptors.response.use(beforeRes, responseFail) export default jwtAxios
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
트랜잭션 전파 활용 - UnexpectRollbackException 관련 질문
트랜잭션 전파 활용까지 강의를 수강하고나니이전 질문해당 질문에서 질문했던 1번 경우에 대해서는 제 생각이 맞는 것 같다는 결론이 나왔습니다.그리고 활용 강의까지 들으면서 느낀건데애초에 UnexpectRollbackException 예외는실제 정상 운영중인 서비스에서는 발생하면 안되는 예외고테스트 과정같은 개발 환경에서 개발자가 캐치해서 이 예외가 발생하지 않게끔 코드를 수정하기위한일종의 알림같은 예외라고 생각이 되었습니다.그래서 굳이 exceptionhandler로 UnexpectRollbackException 예외를 처리하는것은 뭔가 옳지 않은 방법이지 않을까 하는 생각이 들었습니다.제 생각이 맞나요?
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
트랜잭션 전파 기본 - UnexpectRollbackException 관련 질문
만약에 @Transactional 어노테이션을 사용해서 트랜잭션을 만들었을때내부 트랜잭션에서 롤백이 발생했다는건 일반적인 상황에서는 database에서 뭔가 예외가 발생해서 그런거라고 생각되는데,그러면 예외처리기에서 알아서 runtimeException을 상속받은 예외로 바뀔것이고외부 트랜잭션에서도 롤백이 발생한다는건이 경우는 database에서 발생했던 예외가 외부 트랜잭션까지 넘어와서 자연스럽게 롤백된거라고 생각합니다.그래서 UnexpectRollbackException이 발생하지 않는다고 생각됩니다. 제 생각이 맞나요?그러면 UnexpectRollbackException 이 발생할 수 있는 경우는 뭐가 있나요? 강의에서 처럼 의도적으로 문제를 일으키는게 아니면 생각나는 경우가 딱히 없습니다.하지만 제가 생각하지 못하는 것이지 예외가 발생한다는 경우가 있긴 있다는것이겠죠? 그렇다면 트랜잭션을 이용하는 순간부터는 그냥@ControllerAdvice 에서@ExceptionHandler로 UnexpectRollbackException을 캐치해줘서 처리하는 코드를 거의 무조건 작성해야할까요??
-
미해결실전! Querydsl
오류 com.mysema.codegen.model.Type 대응 방법을 알 수 있을까요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]강사님.compileQuerydsl을 실행했을때, 아래 오류가 발생했습니다.Unable to load class 'com.mysema.codegen.model.Type'.혹시 스프링부트3.0 에서는 가능한 대체 설정 방법을 알 수 있을까요?
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
"업로드 및 배포" 후 에러 메시지가 뜨지 않네요..
교재 561페이지를 따라가면서, 위의 메시지까지 받았습니다. 그리고 나서 10여분이 지났는 데도, 교재에서 얘기하는 것처럼 에러 메시지가 출력되지 않네요. 에러 메시지가 없어도 정상적으로 진행이 된 것인가요?
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
bootJar가 어디에 있지요?
교재 560페이지에서 "API 서버 프로젝트에서는 Gradle의 'bootJar'를 실행합니다'라고 되어 있는데, bootJar가 어디에 있지요?
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
양방향 참조 관계에서 `mappedBy` 를 생략하면 어떻게 될까요?
안녕하세요. JPA 학습중인 학생입니다.양방향 참조 관계에서 여러 방법으로 연습하던 중, 예상치 못한 행동을 발견해 왜 이렇게 작동하는지 궁금해서 질문드립니다. 연습한 코드입니다.// Team - Member 는 1:N @Entity class Member { @Id @GeneratedValue private Long id; private String name; // 편의상 public @ManyToOne @JoinColumn(name = "TEAM_ID") public Team team; public Member() { } public Member(String name) { this.name = name; } } @Entity public class Team { @Id @GeneratedValue private Long id; private String name; // 편의상 public @OneToMany // 원래는 mappedBy = "team" 으로 owner 를 설정해야 함. @JoinColumn(name = "TEAM_ID") public final List<Member> members = new ArrayList<>(); public Team() { } public Team(String name) { this.name = name; } } 강의에서 배웠듯, 양방향 참조관계에선 mappedBy = ... 로 관계의 주인을 설정해야 합니다.그런데 만약 이를 생략하면 어떻게 작동할까 호기심이 생겨 아래의 코드를 실행시켰습니다. EntityManager em = getEm(); // 편의상 코드 생략 em.getTransaction().begin(); Member member1 = new Member("member1"); Member member2 = new Member("member2"); Team team1 = new Team("team1"); Team team2 = new Team("team2"); // 편의상 코드 생략 // 단순 em.persist( given ) 을 수행합니다. persistAll(member1, member2, team1, team2); em.flush(); // DB 반영 System.out.println("============== AFTER FLUSH =============="); member1.team = team1; // [1] : mem1 의 팀을 t1 으로 설정 team2.members.add(member2); // [2] : mem2 의 팀을 t2 로 설정 em.getTransaction().commit(); // Member - Team 연관관계 변경 내용 commit em.close(); System.out.println("============== END =============="); 제 예상은 실행시 오류가 발생하거나 [1] 내용만 반영되는 것이었습니다.하지만 실행하니 [1], [2] 모두 반영되는 것을 확인하였습니다. DDL & 출력 내용Hibernate: create table Member ( id bigint not null, name varchar(255), TEAM_ID bigint, primary key (id) ) Hibernate: create table Team ( id bigint not null, name varchar(255), primary key (id) ) Hibernate: alter table Member add constraint FKl7wsny760hjy6x19kqnduasbm foreign key (TEAM_ID) references Team ... ============== AFTER FLUSH ============== Hibernate: /* update scripts.entities.Member */ update Member set name=?, TEAM_ID=? where id=? Hibernate: /* create one-to-many row scripts.entities.Team.members */ update Member set TEAM_ID=? where id=? ============== END ==============실행 후 DB 조회 내용입니다. 위 상황에서 왜 member1, member2 의 팀 변경내용이 모두 반영되는지 알고 싶습니다. 이러한 경우 JPA 가 Member, Team 모두를 연관관계의 주인이라 인식하는 건가요?아니면 JPA 가 Member -> Team, Team -> Member 두 참조를 서로 다른 연관관계(?) 라 해석해 동작하는 걸까요?
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
스프링 sql오류
insert부분이랑 select부분에 저렇게 네모로 표시가 되고 오류가 떠서 웹에 사용자를 등록하면 서버 오류라고 뜨네용 ㅠㅠ
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
H2 사용 시 ddl-auto update 설정하고 age 컬럼 alter 쿼리 발생 안 할 때
평소 같으면 그냥 업무할 때의 개발 환경과 동일하게 설정해서 할텐데...무슨 바람인지.. 이번엔 그냥 영한쌤 강의 보면서 그대로 따라해야지 하고 별생각 없이 강의를 듣던 중...ddl-auto create, create-drop까지 무난했음..ddl update로 하고 id , name 컬럼 생성 create문 정상 여기까지도 무난...ㅎ그러나 대망의 age 컬럼 추가하려고 하니?? alter문 왜 안 날라감? 했습니다...이것 저것하다가 해결되서 공유합니다..ㅎ영한 쌤이 실제 사용중인 H2 버전이랑 의존성 추가할 때 버전 맞추라고 하셨는데Hibernate 버전은 말씀이 없으셨습니다..그래서 H2 버전이 2.3.232 사용중이기 때문에 pom.xml 설정 중 hibernate 버전 6.4.4.Final 로 변경하고모든 import jakarta로 변경하니 잘되네요(JDK21 사용)```<!-- pom.xml --><!-- hibernate --><dependency><groupId>org.hibernate.orm</groupId><artifactId>hibernate-core</artifactId><version>6.4.4.Final</version></dependency><!-- Jakarta Persistence API --><dependency><groupId>jakarta.persistence</groupId><artifactId>jakarta.persistence-api</artifactId><version>3.1.0</version></dependency>```이후 모든 import문 jakarta로 변경Maven Refresh
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
양방향 연관관계와 연관관계의 주인 주의점 및 정리 강의에서 질문입니다~
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 강의에서 마지막에 “처음 JPA로 설계할 때, 무조건 단방향 매핑으로 설계를 완료”하는 것이 좋다고 해주셨는데,여기서 얘기하는 단방향 매핑이 1:N 연관관계에서 N쪽에서만 연관관계를 맺는 걸 말씀하신 걸까요?@ManyToOne@JoinColumn(name=“TEAM_ID”)private Team team;이런식으로요~