POJO로 개발 후 스프링으로 전환, 이후 JPA 전환하는 이유
미해결
실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
POJO로 개발 후 스프링으로 전환, 이후 JPA 전환하는 이유가 있나요?? 처음부터 JPA로 만들면 안되는지 궁금합니다
- tdd
- spring-boot
- pojo
- api
172만명의 커뮤니티!! 함께 토론해봐요.
미해결
실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
POJO로 개발 후 스프링으로 전환, 이후 JPA 전환하는 이유가 있나요?? 처음부터 JPA로 만들면 안되는지 궁금합니다
해결됨
[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
안녕하세요 몽고디비를 다시 복습하고자 공부하던중 저번에 brew update를 통해 해결 된줄 알았지만 또 다시 같은 오류가 발생하였습니다... 이 에러는 어떠한 에러인지 찾아보고 gpt에다가 물어봐도 안나오는데.. 혹시 무엇 때문에 몽고가 brew services start mongodb-community 를하게 되면 이 오류가 발생하게 됩니다.. 도와 주세요..ㅠㅠ
해결됨
Practical Testing: 실용적인 테스트 가이드
안녕하세요 강의 잘 보고 있습니다! 수업에서 서비스 계층을 테스트하실 때, @SpringBootTest를 이용해서 Repository 계층의 빈을 등록하고 주입받아서 사용하고 있습니다. 서비스 계층을 mock을 이용해 단위테스트로 하시지 않고 Repository 계층을 통합해서 사용하는게 많이 사용하는 방식인가요? 실제 현업에서는 Service 계층을 어떻게 테스트 하는 지 궁금합니다. (단위테스트or 통합테스트)
해결됨
Practical Testing: 실용적인 테스트 가이드
안녕하세요! 테스트 강의가 드문데 정말 친절하게 잘 알려주셔서 감사하게 듣고 있습니다 :) 아직 강의를 다 들은 것은 아니지만 강의 내용 중 궁금한 것이 있어 질문 드립니다. 제가 테스트를 제대로 공부해본 적이 없어 혼자서 독학을 하며 공부했던 단위테스트는 주로 Mock과 항상 연관지어 설명이 되어 있었습니다. 통합테스트(@SpringBootTest)는 스프링 컨테이너를 띄우고 bean으로 등록된 모든 빈을 가지고 테스트를 하는 것인데 반해, 단위테스트는 해당 계층(Layer)을 테스트할 때 꼭 필요한 bean만 가지고 와서 최소 단위(메서드나 클래스)로 테스트를 진행한다고 저는 알고 있었습니다. 그래서 예를 들어 Service 계층 테스트를 진행할 때면 Repository에 관련된 bean들은 Mockito 등을 사용해서 Mock을 만들고 InjectMocks를 해준다는 식으로 저는 공부를 하고 테스트 코드를 작성한 경험이 있습니다. 그런데 오늘 강의에서 강사님이 설명해주시는 내용을 듣다보니 @SpringBootTest 와 같은 어노테이션과 상관없이 단위테스트를 진행하시는 것 같다는 인상을 받았습니다. Order에 대한 테스트를 진행하실 때도 단위테스트라는 언급을 하셨고, OrderSerivice에 대한 테스트를 진행하실 때도 @SpringBootTest를 사용하고 있지만 단위테스트를 하신다고 표현을 하시더라구요. 혹시 통합테스트와 단위테스트를 구분하는 강사님만의 방법이 있는 것인지 궁금합니다! 장문 글 읽어주셔서 감사합니다!
미해결
실전! 스프링 데이터 JPA
@EntityGraph(attributePaths = "team") List<Member> findEntityGraphByUsername(@Param("username")String username); 이번 강의를 복습하다 보니까 강사님께서 @Param을 사용하셨더라구요.(강의 20:59) findByAge(), findOptionalByUsername()과 같은 메소드는 @Param 애노테이션 없이도 잘 동작 했는데 따로 특별한 이유가 있는 것일까요?
미해결
실전! Querydsl
됐던데 앞으로는 강의의 searchPageComplex와 같은 방법 (content따로, total따로)으로만 구현하고 사용하면 되는 건가요 ? searchPageSimple 부분은 필요가 없는 건가요?
미해결
실전! Querydsl
@Test public void tupleProjection() throws Exception { List<Tuple> result = queryFactory .select(member.username, member.age) .from(member) .fetch(); System.out.println("result = " + result); for (Tuple tuple : result) { String username = tuple.get(member.username); Integer age = tuple.get(member.age); System.out.println("username = " + username); System.out.println("age = " + age); } } result = [[member1, 10], [member2, 20], [member3, 30], [member4, 40]] username = member1 age = 10 username = member2 age = 20 username = member3 age = 30 username = member4 age = 40 출력값이 위와 같은데 .get()메소드로 꺼내는 걸로 보면 Map과 같은 자료구조인건가 싶기도 하면서, 통째로 출력하면 List<List<>>와 같은 자료구조의 모습이더라구요 tuple은 어떤 자료구조인가요?
미해결
실전! Querydsl
List<Member> result = queryFactory .selectFrom(member) .join(member.team, team) .where(team.name.eq("teamA")) .fetch(); 위의 QueryDSL문을 sql문으로 번역하면 select * from member as m join team as t on m.team _id = t.team _id where t.name ='teamA' 가 맞나요? 관계형DB를 객체 다루듯이 사용하기 위해 Member안에는 Team 클래스가 있고, Team 클래스 안에는 Member 클래스가 있지만 실제로는 .join(member.team, team) 와 같은 코드를 작성하면 내부적으론 DB의 테이블에 가서 외래키와 기본키를 비교해서 값을 가져오는 건가요 ?
해결됨
[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
핸드폰 번호를 입력하면 페이지 상에서는 개발자 도구에서 이렇게 잘 나오지만 vscode console에 찍어보면 myphone 번호가 아니라 undefined로 나옵니다. 아래는 phone.js 코드입니다. (length에서 자꾸 에러가 나서 그 부분만 수정된 코드입니다.) function checkPhone(myphone) { //1. 휴대폰 번호 자릿수 맞는지 확인하기(10-11자리) if (myphone && myphone.length < 10 || myphone && myphone.length > 11) { console.log("에러 발생!!! 휴대폰 번호를 제대로 입력해주세요."); return false; } else { return true; } } //2. 인증번호 6자리 만들기 function getToken() { const result = String(Math.floor(Math.random() * 1000000)).padStart(6, "0"); console.log(result); return result; } //3. 핸드폰 번호에 토큰 전송하기 function sendTokenToSMS(myphone, result) { console.log(myphone+ "번호로 인증번호" + result + "를 전송합니다."); } module.exports = { checkPhone, getToken, sendTokenToSMS }; 이건 signup.html <!DOCTYPE html> <html lang="ko"> <head> <title>회원가입 연습하기</title> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> function zzz(){ //1. 입력한 휴대폰 번호 가져오기 const myphone = document.getElementById("myphone").value console.log("나의 핸드폰 번호 : ", myphone) //2. 해당 휴대폰 번호로 인증번호 API 요청하기 axios.post("http://localhost:3000/tokens/phone", { qqq: myphone }).then((res) =>{ console.log(res.data) document.getElementById("result").innerText = res.data }) } </script> </head> <body> 휴대폰 번호 : <input id="myphone" type="text"/><button onclick="zzz()">인증하기</button> <div id="result">인증상태</div> <button>회원가입하기</button> </body> </html> index.js const express = require('express'); const { checkPhone, getToken, sendTokenToSMS } = require('./phone.js'); const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); const {options} = require('./swagger/config.js'); const swaggerSpec = swaggerJsdoc(options); const cors = require('cors'); const app = express(); //use : 모든 메소드에서 작동한다. app.use(express.json()) app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); app.use(cors()) //GET 방식의 API를 만들겠다. //endpoint는 /로 하겠다. // /qqq이쪽 endpoint로 누군가 요청을 하면 아래 함수를 실행을 시키겠다. app.get('/boards', function (req, res) { //1.DB에 접속 후, 데이터를 조회. 조회한 데이터를 객체로 담아온다. const result = [ {number : 1, writer: "철수", title : "제목입니다.", contents: "내용이에요."}, {number : 2, writer: "영희", title : "제목입니다.", contents: "내용이에요."}, {number : 3, writer: "훈이", title : "제목입니다.", contents: "내용이에요."}, ] //2.DB에서 꺼내온 결과를 브라우저에 응답(response)으로 주기 res.send(result) }, function (req, res){ }) app.post('/boards', function (req, res) { //1. 브라우저에서 보내준 데이터 확인하기 console.log(req) console.log("=====") console.log(req.body) //2. DB에 접속 후, 브라우저에서 받은 데이터를 디비에 저장해야 함. //3. DB에 저장된 결과를 브라우저에 응답(response) 주기 res.send('게시물 등록에 성공하였습니다.') }) app.post('/tokens/phone', function(req, res){ const myphone = req.body.phone //1. 휴대폰번호 자릿수 맞는지 확인 (10-11자리) const isValid = checkPhone(myphone) if(isValid === false) return //2. 핸드폰 토큰 6자리 만들기 const myToken = getToken() //3. 핸드폰 번호에 토큰 전송하기 sendTokenToSMS(myphone, myToken) res.send("인증완료!!!") }) //포스트맨에서 send 버튼 누르는 것 = 기다린다 = listen app.listen(3000)
미해결
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
QueryDSL까지 강의를 다 듣고 난 이후에 게시판이나 쇼핑몰 같은 포트폴리오를 만들기전에 자그맣게 배운걸 써보고 싶은데 html,css,js를 모르다보니 view쪽을 처리할 수가 없더라구요. 그래서 혹시 활용1편에 제공되는 HelloShop view단 파일을 사용해도 될지 궁금합니다. 깃허브에 올리려고 하고 백엔드단 코드는 전부 스스로 짤 생각입니다.!
미해결
실전! 스프링 데이터 JPA
즉시로딩을 사용하면 Member 객체를 불러 올 때 1+N문제가 발생하고 Lazy로딩을 사용하면 Team 객체를 사용할 때 쿼리문이 나가서 즉시로딩이든 지연로딩이든 결국 1+N 문제가 생기는 게 맞나요 ? 이 1+N 문제의 해결방법으로 fetchJoin이 나온 것 같은데 지연 로딩, 즉시 로딩보다 무조건 fetchJoin이 이점이 있는 것 아닌가요? 왜 디폴트값으로 지연로딩으로 설정하고 fetchJoin을 선택해서 사용하는지 궁금합니다. 기본적으로 fetchJoin을 사용하고 연관관계에 있는 객체를 사용하지 않을 것 같은 경우에만 지연로딩을 선택적으로 사용하는게 더 편하지 않나요? 사용하지 않는 객체를 가져오는 fetchJoin의 쿼리문 몇 줄이 성능에 그렇게 큰 영향을 미치나요?
미해결
실전! 스프링 데이터 JPA
Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); teamRepository.save(teamA); teamRepository.save(teamB); memberRepository.save(new Member("member1", 10, teamA)); memberRepository.save(new Member("member2", 10, teamB)); 강의에서 이렇게 한번에 하려다가 Member를 생성해주고 따로 save를 해주던데 한번에 하면 안되는 이유가 있을까요 ?
미해결
실전! 스프링 데이터 JPA
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Direction.DESC, "username")); int age = 10; //when Page<Member> page = memberRepository.findByAge(age, pageRequest); PageRequest.of 코드에서 첫 번째 파라미터가 무엇을 의미하는지 헷갈립니다. PageRequest.of 의 2번째 파라미터는 한 페이지의 element 개수이고(limit), 3번째 파라미터는 정렬 조건이 맞나요? List<Member> content = page.getContent(); assertThat(content.size()).isEqualTo(3); assertThat(page.getTotalElements()).isEqualTo(5); assertThat(page.getNumber()).isEqualTo(0); assertThat(page.getTotalPages()).isEqualTo(2); assertThat(page.isFirst()).isTrue(); assertThat(page.hasNext()).isTrue(); page.getContent()는 현재 페이지의 데이터를 가져오는 메소드인가요? page.getNumber()는 현재 페이지를 가져오는 메소드인가요? Page는 책처럼 0,1,2,3 ... 이렇게 페이지가 있는 거고 Content는 그 Page안에 있는 데이터를 의미하는 건가요? List<List<data>> 와 같은 구조로 되어 있는 것일까요? Page와 Content의 자료 구조가 어떻게 되어있는지가 궁금합니다.
해결됨
Practical Testing: 실용적인 테스트 가이드
강사님께서 올려주신 영상의 코드 폰트가 너무 작습니다.. 30분 정도 봤는데, 눈이 너무 아픕니다..ㅠㅜ 다른 강의 보면서 작다고 느낀적은 한번도 없는데 혹시, 녹화한 강의를 크게 보는 방법이 없을까요?
해결됨
자바 ORM 표준 JPA 프로그래밍 - 기본편
안녕하세요! 먼저 좋은 강의 감사하다는 말씀 드립니닷! 개인 프로젝트 수행 중에, 변경 감지와 관련한 이슈를 발견해서 질문드립니다. 물론 개인 프로젝트 관련한 질문은 안 받아주시는 것을 충분히 숙지하고 있지만, 개념적인(?) 내용이라 혹시 도움 받을 수 있을까 싶어 질문드립니다. (사실 아무리 생각해봐도 모르겠습니다..ㅠㅠ) 상황 한 트랜잭션 안에서, 엔티티 객체를 만들고 이를 영속성 컨텍스트에 올려 id 값을 받아와 이 id 값을 가지고 해시값을 만들어 해당 해시값을 다시 엔티티 객체에 할당하려 합니다. 문제 문제는 위 작업을 수행하는 메소드의 @Transactional 위치에 따라 변경감지가 될 때가 있고 안 될 때가 있다는 점입니다. 위 쪽의 create(ShortUrlCreateRequest request) 메서드를 호출하여 아래에 오버로딩된 create(String originUrl, Period expirationPeriod) 를 통해 위에 서술한 작업을 하려합니다. (Repository 객체는 Data Jpa Repository를 사용하고 있습니다.) create(ShortUrlCreateRequest request) 를 호출하면, 아래의 create(String originUrl, Period expirationPeriod) 메서드에 @Transactional 을 붙였음에도 아래와 같이 insert 문만 호출됩니다. 이번에는 위의 create() 에 @Transactionl 붙였을 때 입니다. insert 문과 update 문 모두 의도한 대로 호출되는 것을 확인할 수가 있습니다. 트랜잭션 진입 시점이 다른 것인데 왜 이에 따라 변경감지 가 일어나고/ 안 일어나는 지 감을 잡지 못하겠습니다. 일말의 힌트를 주실 수 있을까요? 항상 영한님과 서포터님들께 감사드립니닷!!
미해결
실전! 스프링 데이터 JPA
EntityManger를 주입받는 방법으로 private final EntityManager em; 이렇게 선언하고 @RequiredArgsConstructor로 받을 수도 있고, 이번 강의에서처럼 @PersistenceContext로 받을 수도 있는데 각각의 차이점이 무엇인가요 ? public long count() { return em.createQuery("select count(m) from Member m", Long.class) .getSingleResult(); } 또 여기서 메소드 선언문에는 long 타입을 반환타입으로 설정했는데 createQuery의 2번째 파라미터로는 Long값을 주는데 어떤 이유인지 궁금합니다.
미해결
실전! 스프링 데이터 JPA
member = Member(id=3, username=member1, age=10) -> member.getTeam() = Team(id=1, name=teamA) member = Member(id=4, username=member2, age=20) -> member.getTeam() = Team(id=1, name=teamA) member = Member(id=5, username=member3, age=30) -> member.getTeam() = Team(id=2, name=teamB) member = Member(id=6, username=member4, age=40) -> member.getTeam() = Team(id=2, name=teamB) Team을 먼저 persist 했기때문에 team의 id가 1,2가 됐고, 그 뒤에 순차적으로 member의 id가 3,4,5,6이 된 건가요 ? Team은 Team대로, Member는 Member대로 각 엔티티마다 id를 사용하는게 낫지 않나요? 실무에서는 어떤지 궁금하고, 만약 실무에서는 각 엔티티마다 id값을 공유한다면 강의에서는 모든 엔티티가 같은 id값을 공유하는지 궁금합니다.
해결됨
[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
안녕하세요 백엔드쪽로 준비하는 사람이면 로드맵으로 두개다 구매해도 우선 백엔드쪽 강의 수강만 집중하는것이 나을까요? 아님 프론트-> 백엔드 순으로 하면 더 도움이될까요?
미해결
따라하며 배우는 리액트 A-Z[19버전 반영]
안녕하세요 선생님 이번에 쇼핑몰 강의가 업데이트가 되었길래 강의를 들어보려고 합니다 그런데 제가 도커 강의도 한번 들어보고 싶은데 도커에 도자도 모르는 상태인데 수업을 따라갈만 할까요?? 항상 좋은 강의 감사합니다
미해결
더 자바, 코드를 조작하는 다양한 방법
'마무리' 한 강 남았네요. 덕분에 많이 배우고 많이 성장한 것 같습니다. 그런데, 어노테이션 프로세서 활용과 관련해서,, QueryDSL 사용 시 생성되는 엔티티의 Q파일도 어노테이션 프로세서를 활용한 기술인지 궁금합니다. 짐작으로는 맡긴 한데, 관련 언급이 없었어서요.