자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
대출기능을 개발하려고 하니, 저희가 가진 두 테이블, User와 Book은 서로를 가리킬 필드가 없어서 '대출했다.'라는 정보를 표시할 수 없었습니다. 그래서 user_loan_history 테이블을 새로 만드는 내용이 강의의 주된 내용이 되는데요, 제가 궁금한건 여기서 User와 Book 테이블을 수정하여, 예를들면 User테이블에는 OneToMany로 Book의 id를 가리킬 수 있는 필드를, Book테이블에는 ManyToOne으로 User의 id를 가리킬 수 있는 필드를 추가하여 개발할 수도 있지 않나 싶어서요! 객체지향적으로 생각했을 때 User와 Book은 객체지만, '대출기록'은 객체가 아니라 객체간의 관계 같아서 테이블로 만드는 것에 거부감이 생기는 것 같습니다. 어떤 이유에서 기존의 테이블을 수정하지 않고, 새로운 테이블을 만들었는지 궁금합니다!
[질문 내용] SpringConfig클래스에 MemoryMemberRepsoitory 메소드에 retrun new JdbcMemberRepository();를 하고 dataSource 객체 생성 후 생성자까지 만들어주었습니다. 여기까지는 ()에 오류가 생기는데 여기에 dataSource를 넣어주면 전체오류가 생기여 옵션엔터를 눌러 해결하면 메소드 이름을 MemoryMemberRepository가 아닌 JdbcMemeberRepository로 바꿔라 합니다. 이를 변경하면 위에 MemberService도 바꿔야하며 전체코드에 이상이 생깁니다. package hello.hellospring; import hello.hellospring.repository.JdbcMemberRepository; import hello.hellospring.repository.MemoryMemberRepository; import hello.hellospring.service.MemberService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; @Configuration public class SpringConfig { DataSource dataSource; public SpringConfig(DataSource dataSource) { this.dataSource = dataSource; } @Bean public MemberService memberService(){ return new MemberService(memberRepository()); } @Bean public MemoryMemberRepository memberRepository(){ //return new MemoryMemberRepository(); return new JdbcMemberRepository(dataSource); //오류발생 } } java: incompatible types: hello.hellospring.repository.JdbcMemberRepository cannot be converted to hello.hellospring.repository.MemoryMemberRepository 이러한 오류내용이 뜹니다. 수업 소스코드와 동일하게 해봤는데 이럽니다!
Q1: auto-fill 에 대해 질문드립니다. <Grid #3 강의의 4:30초> 에서 셀이 2개 있고, grid-template-columns에 minmax(200px, auto)가 설정되어 있으며 auto-fill이 적용되어 있을때 grid-template-columns: repeat(auto-fill, minmax(200px, auto)) 전체 Grid Container의 넓이가 500px 일때에, 셀의 column 길이가 200px 이상이 되어지게 됩니다. 제가 알기로는 minmax(최솟값, auto) 라면 셀의 길이가 최솟값 보다 커지려면 셀이 가지는 컨텐츠의 길이가 최솟값보다 커야된다고 알고 있는데요. 그런데 왜 auto-fill이 설정되어 있을때에는 컨텐츠의 column 길이가 200px 보다 작은데 왜 Grid Container의 넓이 만큼 늘어나는 것인가요? 이것이 auto-fill을 적용하여 Grid의 기본 성질인 꽉 차게 늘어나는 성질때문에 그런가요? Q2 auto-fill 적용불가에 대해 질문드립니다. 저의 브라우저에서 테스트 해본결과, auto-fill이 적용이 되지 않는 부분은 셀이 2개가 있고, column의 길이가 minmax(200px, auto) 이며, auto-fill을 사용하고, Grid Container의 넓이가 600px 초과 된다면, 셀이 가지는 column의 길이가 원래는 Grid Container의 길이만큼 꽉차게 늘어나다가 200px이 가질 수 있는 크기를 넘어서게 되니 꽉차지 않게 되는 것 같습니다. 위의 질문과 동일한 것같습니다만, 자동으로 늘어나는 것은 400px (200px 셀 2개) 의 크기보다 Grid Container의 길이에서 뺀것의 크기가 200px 이상이라면 자동으로 늘어나는 것이 중단되고, 200px 이하라면 늘어나는 것이 되는 것인데, 왜 200px 이하라면 늘어나는 것입니까? Grid Container의 넓이를 200px으로 나눌때 나머지가 200px 보다 작다면 그냥 Grid의 성질에 의해 늘어나는 것인가요? Flex만 사용하던 사람이라 minmax의 대한 성질과 auto-fill을 공부하니 약간 했갈리네요...
안녕하세요. 그랩님 매일 같이 열정적으로 댓글 달아주셔서 항상 감사드립니다. 모든 것이 그러하듯 강의를 운영하는 것도 엄청난 공수가 든다는 것을 깨달았네요. 현재 오류가 생겼는데, useHistory를 이용해서 upload 페이지로 이동한 후 Upload 클라이언트 쪽에서 아무 반응도 일어나지 않고 있습니다. 아무리 코드랑 구글링을 해봐도 해결이 안되는데요. upload페이지가 console창을 보면 /upload/index.js의 html 코드가 아무것도 불러와지지 않고 있는 것 같아요. 혹시 조언좀 구할 수 있을까요? 1. 현상 : 클라이언트에 아무것도 뜨지 않음 Elements 창을 클릭해도 upload.js 작성한 HTML이 없습니다. 2.App.js에 제가 작성한 코드입니다. History와 import 란에 모두 정확하게 작성하였는데요. 3. upload/index.js 파일 코드도 같이 첨부드립니다. 한번만 봐주실 수 있을까요? ㅠ useHistory가 만료가 되어서 작동을 안 하는걸까요.. https://github.com/promotionX/Grabmarket-clinet
안녕하세요 강의듣다가 막혔다 해결한 부분이 있어서 혹여나 동일한 문제를 겪고 있으신 분이 계실까봐 공유드립니다. named lock파트의 native query를 작성하는 부분에서 강의 코드와 동일하게 작성하였음에도 불구하고 스프링 빈을 초기화 하는 과정에서 다음과 같은 에러를 만나게 되었습니다. 작성한 코드 @Query("select get_lock(:key, 3000)", nativeQuery = true) fun getLock(key: String) @Query("select release_lock(:key)", nativeQuery = true) fun releaseLock(key: String) 발생한 에러 Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract void com.waterfogsw.cucurrentsolutions.domain.LockRepository.getLock(java.lang.String); Reason: Cannot invoke "String.contains(java.lang.CharSequence)" because "variable" is null at app//org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:115) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:99) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:88) at java.base@17.0.6/java.util.Optional.map(Optional.java:260) at app//org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:88) at app//org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:357) at app//org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:279) at app//org.springframework.data.util.Lazy.getNullable(Lazy.java:245) at app//org.springframework.data.util.Lazy.get(Lazy.java:114) at app//org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:285) at app//org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:132) at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1798) at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1748) ... 122 more Caused by: java.lang.NullPointerException: Cannot invoke "String.contains(java.lang.CharSequence)" because "variable" is null at org.springframework.data.jpa.repository.query.QueryUtils.createCountQueryFor(QueryUtils.java:620) at org.springframework.data.jpa.repository.query.DefaultQueryEnhancer.createCountQueryFor(DefaultQueryEnhancer.java:49) at org.springframework.data.jpa.repository.query.StringQuery.deriveCountQuery(StringQuery.java:111) at org.springframework.data.jpa.repository.query.AbstractStringBasedJpaQuery.<init>(AbstractStringBasedJpaQuery.java:82) at org.springframework.data.jpa.repository.query.NativeJpaQuery.<init>(NativeJpaQuery.java:58) at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:53) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:170) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:252) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:95) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:111) ... 134 more 동일한 강의를 수강중이던 지인분과 함께 비교해본 결과 스프링 부트 버전 문제임을 확인하였습니다. 지인분은 data jpa 3.0.1 버전을 사용중이셨고, 저는 data jpa 3.0.3버전을 사용하였는데 3.0.2 이상 버전에서 nativeQuery=true 사용시 NullPointerException이 발생하는 이슈가 있음을 알려드립니다. 저는 부트버전을 3.0.1로 다운그레이드하여 정상적으로 실습 진행할 수 있었습니다 :) https://github.com/spring-projects/spring-data-jpa/issues/2812
안녕하세요 선생님🙇♀️ 클래스_메소드 강의를 보다 궁금한 점이 생겨 질문 남깁니다. BlockBox 클래스에 두 메소드를 넣었고, 04_Method클래스에 두 메소드를 활용한 문장이 있었는데요. insertMemoryCard()는 그대로 사용했지만, getVideoFileCount()는 다시 변수로 선언한 이유가 무엇인가요? 감사합니다. void inserMemoryCard(int capacity) { System.out.println("메모리 카드가 삽입되었습니다."); System.out.println("용량은 " + capacity + "GB 입니다."); } void getVideoFileCount(int type) { if ( type == 1) { return 9; } else if ( type == 2) { return 1; } return 10; } b1.insertMemoryCard(256); int fileCount = b1.getVideoFileCount(1);
안녕하세요 강의 잘 보고있습니다. csrf 토큰 값을 헤더에 넣어서 실습하는 부분 따라해봤는데 잘 안되서 코드를 뜯어봤습니다. 이번에 시큐리티 버전이 6으로 올라가면서 csrf 토큰을 인코딩해서 전달하고 이걸 디코딩하는 부분이 영상과 다른것같았습니다. 그래서 기본으로 제공하는 로그인 페이지에서 디버깅을 해보았는데 클라이언트에 전달한 csrf 토큰값이랑 실제 서버가 가지는 csrf 토큰값이 서로 달랐습니다. 이렇게되면 영상에서 보여주신 실습은 제대로 동작하지 않는게 맞나요? 해당 사진은 CsrfFilter에서 actualToken을 받아오기 위한XorCsrfTokenRequestAttributeHandler 클래스 내부에 존재하는 resolveCsrfTokenValue 함수의 소스코드입니다. 예제 따라하면 항상 마지막에 사이즈 비교하는 부분에서 걸렸습니다.
안녕하세요. 모임 만들기 페이지에서 시간을 설정할 때, 연월일 제외하고 시간만 입력하려면 어떻게 하면 되는지요? fragments.html 의 <div th:fragment="event-form (mode, action)"> 에서 <input id="endEnrollmentDateTime" type="datetime-local" 의 type 부분을 type="time" 으로 하고 Event 클래스에서 private LocalDateTime endEnrollmentDateTime; 을 private DateTime endEnrollmentDateTime; 로 변경하고 실행하면 html 상에서는 시간이 입력되나, DB 에는 insert 되어 있지 않습니다. 어떻게 하면 가능한지요? 자세한 설명 부탁드립니다. 그리고, 제공해 주신 소스를 다운로드해서 프로젝트를 실행한 후, 오른쪽 드롭다운 메뉴 중 스터디를 클릭해도 아무 동작이 일어나지 않습니다. 소스를 보면 <a class="dropdown-item" >스터디</a> 이렇게만 나와있고 th:href="@{}" 로 연결된 페이지가 없습니다. 이 부분 기능 구현은 안 해 놓으신 건지요? 프로필 페이지에서도 왼쪽 프로필 사진 밑에 있는 스터디 버튼을 누르면 Study 라고만 나오고 별다른 페이지가 나오지 않습니다. 이 부분도 기능 구현은 안 해 놓으신 건지요?
혹시 Flex-direction: row이고, Flex-wrap이 Wrap으로 설정되어 있고, 아이템들은 width: 33.3333%의 크기를 가지며, Height들은 서로서로 다 다를때, Wrap되어 행이 2개가 생길때에 Flex-grow가 1로 Item들에 설정되어 있다면 모든 행의 높이가 가장 큰 높이에 맞춰지게 되는데요. https://blogpack.tistory.com/863 여기나 이 강의에서 학습한 대로 1행에서는 flex-grow의 이해가 쉽게 됬습니다. 그치만, 제가 언급한 지금 이 예처럼 2열이고 높이가 서로다른 3개의 아이템들일 경우에는 Flex-grow가 한 행의 영역에서 남은 여백을 참조하여 모든 높이를 최대까지 늘리는 것인가요? flex-grow 또는 flex-shrink가 적용되는 영역은 한 행이나 열에서 적용되나요? 각각의 Item들에 적용하는 속성이니 이해가 조금 어렵네요... 많은 조언 부탁드립니다.
안녕하세요 영한님! 질문드립니다. 고아 객체는 부모 엔티티와 연관관계가 끊어진 자식 엔티티 라고 이해했습니다. 고아 객체가 생성되는 조건은 부모 엔티티 삭제 부모 엔티티가 삭제 되면 자식 엔티티를 고아객체로 판단 합니다. e.g) em.remove(parent); 부모 엔티티에 있는 자식 엔티티 컬렉션 제거 연관관계가 끊어진 자식 객체를 고아객체로 판단 합니다. e.g) parent.getChild().remove(0); 결과적으로 orphanRemoval = true 를 설정하면 자식 엔티티(고아 객체)는 부모 엔티티와 함께 삭제 되거나 자식 엔티티(고아 객체)만 삭제 된다. 맞게 이해하고 있는 것 일까요? 감사합니다.^^