5. 스프링부트(블로그만들기) 게시글 목록 보기

윤주헌's avatar
Aug 21, 2024
5. 스프링부트(블로그만들기) 게시글 목록 보기

1. 더미 데이터 만들어 주기

notion image
지금은 정적 페이지 글쓰기 해서 db있는 데이터 뿌릴거다
 
데이터 더미 2건 이상을 미리 넣어둘거다 (왜 2개냐 Colleaction이기 때문이다)
 

1.1 resources폴더에 db폴더 만들어 준다

notion image
 

1.2 db 폴더 안에 data.sal 파일 만들어준다

notion image
 

보통의 경우

보통 폴더 2개를 만드는데 ddl(create drop,) 이런 스키마 테이블 만들고 , 더미 데이터 만든다.

궁금증 왜 우리는 스키마파일을 안 만들어도 괜찮은가?

→ 우리는 Entitiy로 자동 Create 할 거니까 application-properties에서 spring.jpa.hibernate.ddl-auto=create했기 때문이다
보통은 스키마 파일 만들어야 함
 

이제 신경써야 할 부분

data.sql 이게 들어가는 들어가는 타이밍, create 스키마가 먼저 실행되는 타이밍이 있는데 테이블이 먼저create 돼야 해서 타이밍 손봐야 함
 

1.3 테이블 생성, 쿼리문 실행 순서 정하기

다시 data sql로 넘어가서
💡
insert into board_tb(title, content, created_at) values(’제목1’, ‘내용1’, now());
5개 만들어 주기
notion image
notion image
 
  • 주의 !!
오타 내지 말자
💡
오타 나서 values인데 vlaues해서 오류남 바보야
  • 주의
💡
테스트를 위한 더미 파일이라고 내용을 대충 asdkfljaskdjf;as 이렇게 적지 말자 나중에 파악하기 힘들기 때문이다
 
application.properties에서 발동시킴
notion image
 
notion image
💡
spring.sql.inti.data-locations=db/data.sql
이렇게 적고 실행하면 오류가 난다

오류 보는 법

  1. 콘솔창 다 지우고 다시 시작
  1. 제일 위에서부터 내려 오면서 ERROR찾기

1번오류

notion image
빈이 안 만들어 졌어!
  • bean은 객체를 의미한다 (boarController 같이 new해서 만들어 지면 객체가 만들어진다 bean만들어짐)
 
notion image
notion image
db/data.sql 못 찾겠다
 

1번 오류 해결 방법

notion image
notion image
💡
spring.sql.init.data-locations=classpath:db/data.sql
적어야지 리소스 폴더에 도착할 수 있음
 
classpath이게 뭐야? 나중에 할 수 있게 설명 해주실 거임 일단 반복 숙달
 

2번 오류

notion image
notion image
아까는 데이터를 찾을 수 없다는 오류는 없어졌는데 테이블을 찾을 수 없다고 나온다
 

2번 해결 실행시간 변경해줌

notion image
💡
spring.jpa.defer-datasource-initialization=true
위에가 먼저 실행 되고 아래가 실행 된다 결국 sql 테이블이 먼저 Create한 후 쿼리문 실행한다
 
notion image
 
h2에 더미들이 들어가짐
 

더미를 사용하는 이유!!

  1. 만약 10명에서 협업한다면 3명이서 따로 하고 있다 (페이징 중) 한 페이지당 3개씩 5개 데이터 있다면 2페이지 나오겠지 사람 마다 데이터 마다 페이징 개수가 달라진다 → 테스트 할 때 데이터 개수 같게 설정 하고 만들어야 한다.
💡
동일한 환경에서 협업할 때 같은 데이터를 볼 수 있기 때문에
 
  1. 더미 데이터 만들어두면 (원래 회원가입 먼저 개발, 한명은 로그인 개발 → 로그인 하는애는 아직 회원가입 못 만들어서 로그인 못해요.. → 회원 데이터 더미로 만들면 할 수 있지 않냐? 라고 말 할 수 있다 순서대로 할 필요가 없다) 더미만 있다면 테스트 시간이 확 줄어든다! 일이 편해짐 모든 프로그램은 독립적으로 만들 수 있어야 한다!! 자동차를 만드는 사람이 바퀴 안 만들어 졌다고 프래임을 못 만드는 경우가 없다
💡
모든 프로그램은 독립적으로 만들 수 있어야 한다!!
 

번 외 h2 연결 기본

jdbc:h2:~/test → 이거는 하드디스크에 저장한다 (이러면 하드디스크에 쌓인 데이터 보이기 때문에 위험)
그래서 jdbc:h2:mem:test → 메모리에 저장한다
 

2. 목록 만들기 연결

만약 목록 보기 만들 때 쓰기가 안돼도 만들 수 있게 해야 한다
notion image
 
클라이언트는 보통 웹 브라우저다 → C는 MODEL(java모양)을 브라우저에 보내야 하는데 자바는 이해 못해서html파일로 만들어 줘야 한다. → 템플릿 엔진(머스테치 같은 것)(html파일에 java 파일을 끼워 넣을 수 있는 것) 이거를 VIEW라고 한다
 
모델 → 응답되는 데이터
 
먼저 개발할 때 한꺼번에 만드는 것이 아니고 select하는 레파지토리 먼저 할거다 그 다음 → 프리젠테이션 계층만 신경쓰면 끝난다

2.1 보드 레파지토리에서 findAll메서드 만들어서 목록 띄워주자

notion image
  • findAll 메서드의 책임
💡
보드 테이블 모든 것 다 가지고 오는 것
notion image
  • 뒤에 Board.class 붙이는 이유
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
Board.class 하면 보드 클래스로 만들어서 준다
 
notion image
public void findAll() { Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class); }
  • 주의
💡
여기 들어갈 수 있는 애는 @Entity들어간 애들만 매핑된다!!! 일반 클래스는 안됨!!
여러건이냐?
notion image
한 개 뿐인가?
notion image

2.1.1 findAll 메서드

notion image
public List<Board> findAll() { Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class); List<Board> boardList = query.getResultList(); return boardList; }
 
데이터 소스가 내장되어 있다 → 그래서 클로스 안해도 된다(수영장 튜브 생각하자 미리 만들어 두고 끝나면 객체를 죽이지 않는다.)
트랜잭션 안 붙여도 됨? → insert 등 할 때만 붙이면 됨

2.2 테스트 해보자

notion image
@Test public void findAll_test() { //given findall할때 필요한 매개변수를 적어준다 //when boardRepository.findAll(); //eye }
쿼리문 잘 되면 된다!!
notion image

만약 쿼리 틀린다면 어떤 오류가 뜰까?

리퍼지토리에서 id를 ids로 바꾼다면
notion image
 
notion image
 

결과가 궁금하지 않나? 5개 리턴하는지? select는 결과 확인 가능

  1. 사이즈 찾아보자
@Test public void findAll_test() { //given findall할때 필요한 매개변수를 적어준다 //when List<Board> boardList = boardRepository.findAll(); //eye //싸이즈 부터 보자 System.out.println("사이즈 : " + boardList.size()); }
notion image
notion image
  1. 값을 확인해보자
@Test public void findAll_test() { //given findall할때 필요한 매개변수를 적어준다 //when List<Board> boardList = boardRepository.findAll(); //eye //싸이즈 부터 보자 System.out.println("사이즈 : " + boardList.size()); //값 확인 타이틀 컨텐트만 보자 일단 for (Board board : boardList) { System.out.println(board.getTitle()); System.out.println(board.getContent()); } }
notion image

인텔리J에서 한글 깨지는거

notion image
notion image
notion image

개념 잡기@

🚀
통신 및 기초
 

2.3 보드 컨트롤러

모델이 reqeust객체다 모델에 넣으면 개념이 안 잡혀서 request객체에 넣을 거다

2.3.1 이해

notion image
//디스페처 서블릿이 (컨트롤러의 메서드 찾아주는놈) 알아서 주입해줌
  • 디스페처 서블릿?
💡
컨트롤러의 메서드 찾아주는 놈 및 여러가지 해줌
notion image
@GetMapping("/board") public String list(HttpServletRequest request) { //디스페처 서블릿이 (컨트롤러의 메서드 찾아주는놈) 알아서 주입해줌 System.out.println(request.getRemoteAddr()); System.out.println(request.getRequestURI()); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }

결과

notion image
Spring이 uri 분석해서 의존성 주입한다
만약 Board board 넣으면 어떻게 될까 안됨
디스페처 서블릿은 보드 객체 안 들고 있기 때문에
@GetMapping("/board") public String list(Board board) { //디스페처 서블릿이 (컨트롤러의 메서드 찾아주는놈) 알아서 주입해줌 System.out.println(board.getRemoteAddr()); System.out.println(board.getRequestURI()); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }
만약 session을 치면 어떻게 될까?
 
세션에 접근할 때 request.getSession()하면 reqeust객체를 통해서 session메모리에 접근할 수 있다는 거임 가지고 있는게 아님
 
@GetMapping("/board") public String list(HttpServletRequest request) { return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }
 
IoC에 리포지토리, 컨트롤러, 엔티티 메니저 들고있다. 여기서 스프링 세션에 담아두면 편할까? 편하다
 
세션 객체는 1개다 싱글톤으로 관리 가능해서 넣어놔 (서랍만 다르게 쓰는것 key로 찾는것)
 
notion image
 
세션 하면 따로 적을 필요가 없다
못 적음.. 뭐였지?
@GetMapping("/board") public String list() { return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }
적으면 됨
톰켓이 만든 reqeust객체 넣지 않는다 request는 요청할 때마다 생기기 때문에 못 넣음
 
  • 중요!!!
IoC에서 관리할 수 없음(오직 한 개인 애들만 다 띄워둠(싱글톤인 애들))
 
@Autowird
HttpServletRequest
이 말은 헬스장에 가방 한개뿐이라는 말임
 
(세션에 저장 안함) request에 저장함
@GetMapping("/board") public String list() { List<Board> boardList = boardRepository.findAll(); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }
 
requset에 저장
@GetMapping("/board") public String list(HttpServletRequest request) { List<Board> boardList = boardRepository.findAll(); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) } 이거를 모델로 사용함
모델이 request다
 
이렇게도 가능하다
@GetMapping("/board") public String list(Model model) { List<Board> boardList = boardRepository.findAll(); //key값 모델스 //외부에서 /board요청 -> 톰캣에 감 rqeust객체로 만들어둠 -> 때림 -> Model에 rqeust객체 주입됨 -> 이 데이터를 reqeust객체에 넣어버림 model.addAttribute("models", boardList); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }

2.3.2 list.mustache 파일로 이동

notion image
 
for문으로 돌릴거임 지우기
notion image
for 문임(가방에서 꺼냄)
notion image
list.mustache 파일임
{{>layout/header}} <div class="container p-5"> {{#models}} <div class="card mb-3"> <div class="card-body"> <h4 class="card-title mb-3">{{title}}</h4> <a href="/board/{{id}}" class="btn btn-primary">상세보기</a> </div> </div> {{/models}} </div> {{>layout/footer}}
 

mustache에서 중괄호 사용

requset나 세션 때릴 때는 중괄호 두개
언제 # for문 때 사용
 
JSP는 <% %> 이런거 쓰는데 머스테치는 reqeust된 객체 뿌릴 수 만 있다.
JSP가 기능 많아서 좋기는 하지만 연산 같은거는 view에서 필요 없기 때문이다!!
머스테치는 자바코드 못 적음 == 비교도 할 수 없다
 

결과

notion image

2.4 머스테치 세팅

머스테치는 reqeust, session 객체에 접근하는 것이 금지되어 있어서 설정하는거임
 

application.properties에서 넣어줘야 할 것

notion image
spring.mustache.servlet.expose-request-attributes=true spring.mustache.servlet.allow-session-override=true

2.5 보드 컨트톨러로 이동

  • 모델이 하는 게 아닌 request객체가 하는 것이라 공부하기 좋으라고 Model model을 HttpServletRequest request로 변경
notion image
@GetMapping("/board") public String list(HttpServletRequest request) { List<Board> boardList = boardRepository.findAll(); //key값 모델스 //외부에서 /board요청 -> 톰캣에 감 rqeust객체로 만들어둠 -> 때림 -> Model에 rqeust객체 주입됨 -> 이 데이터를 reqeust객체에 넣어버림 request.setAttribute("models", boardList); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }
 
 
notion image
머스테치에서는 그냥 rqeust객체 담은 거를 찾아내는 거다
 

이러면 어떻게 될까? session에 넣으면

@GetMapping("/board") public String list(HttpServletRequest request) { List<Board> boardList = boardRepository.findAll(); //key값 모델스 //외부에서 /board요청 -> 톰캣에 감 rqeust객체로 만들어둠 -> 때림 -> Model에 rqeust객체 주입됨 -> 이 데이터를 reqeust객체에 넣어버림 //리퀘스트 끝나면 지워짐 request.setAttribute("models", boardList); //이래 적으면 어떨까? 리턴되도 살아 있다 HttpSession session = request.getSession(); session.setAttribute("num", 1); return "board/list";//파일의 경로 넣으면 되는데 고정적으로 되어 있음 확장자 자동으로 해주는가? 라이브러리로 머스테치 설정해줘서(templates에 머스테치로 찾아줌) }
list 머스테치 가서
notion image
 
1 이 세션 데이터
notion image
 

Stateful한 서버, stateless한 서버

요청했을 때 받은 놈이 reqeust돼도 클라이언트 상태 저장하고 싶으면 stateful한 서버
상태가 없는 서버 → stateless서버
상태가 있는 서버 → stateful 서버
스태틱은 메인이 시작되기 전 끝까지 있음 용량너무 잡아먹음 진짜 필요한 애들만 넣어둔다!!
힙은 프로그램 저장되다 동적으로 띄우고 싶으면 이 때 사용함
 
rqeuest객체 요청되고 응답할 때 버리는것 → stateless 서버
session 요청되고 응답이 끝나도 저장하고 싶다 → stateful 서버
 

주의!

리다이랙트 하는데 rqeuset안에 두면 사라짐(응답 후 요청이니까)
만약 다시 하고 싶으면 session에 저장하자
 

최종코드

컨트롤러 →
@GetMapping("/board") public String list(HttpServletRequest request) { List<Board> boardList = boardRepository.findAll(); request.setAttribute("models", boardList); return "board/list"; }
list.mustache →
{{>layout/header}} <div class="container p-5"> {{#models}} <div class="card mb-3"> <div class="card-body"> <h4 class="card-title mb-3">{{title}}</h4> <a href="/board/{{id}}" class="btn btn-primary">상세보기</a> </div> </div> {{/models}} </div> {{>layout/footer}}
 
Share article

code-sudal