프레젠테이션(웹) 계층의 CRUD 구현

myminimin·2023년 8월 24일
1

Spring/Springboot

목록 보기
8/21

URI와 URL의 차이 참고하기 🐷


웹 계층을 구현할 때 가장 먼저 중요한 것이 위의 표와 같은 URI 설계이다. 이 설계를 하기 위해서 참조해야 하는 것이

이러한 스토리보드다! 화면이 어떻게 만들어질건지....

이전에 사용했던 모델1은 URL로 바로 page를 만들었는데 (생각해보면 .jsp파일 하나하나가 페이지였고 그 jsp에서 jsp로 이동을 했음!)

모델2는 모든 링크는 Controller가 먼저 받아서 처리를 한다. 모델2, MVC의 목적자체가 로직과 화면의 분리 라는 것을 생각하자!

  • Get방식 - 조회가 가능하고 카톡에 링크 보내는 그런 방식
  • Post방식 - 실제 작업과 관련된 것

입력화면이 필요한 경우에는 get방식으로 입력하는 화면을 보고 post방식으로 결과를 본다. 대부분의 경우 결과를 목록(list)에서 보는데 그때 이용하는게 리다이렉트라는 걸 이해해야한다!!!

-> 게시글을 등록하는 register.jsp에서 게시글을 등록하면 BoardController.class에서 register() 메서드가 실행되고 등록이 완료 처리후에 redirect:/board/list 해서 list.jsp가 뜨는 것임! (redirect를 하지 않으면 사용자가 새로고침을 할 때마다 게시글이 작성되면서 도배를 할 수 있게 된다...)


구현 순서

  1. 목록 -> 2. 등록 입력/처리 -> 3. 조회 -> 4. 수정/삭제

1. 목록

목록 구현 중 따로 오류가 발생하지는 않았고 BoardControllerTests에서 mockMvc를 처음으로 사용했는데 얘를 왜 사용하는지에 대해서 한 번 짚고 넘어가야할 것 같아서 작성...

스프링의 장점 중 하나가 웹 계층mockMvc를 이용해서 테스트가 가능하다는 점이다.

  • 장점 : 화면이 없어도 테스트가 가능하다는 점이다!
    이게 왜 장점이냐면 내가 게시글을 등록하는 register() 메서드를 만들었는데 얘를 테스트 하려면 필요한 것이 글을 작성할 수 있는 페이지와 돌아갈 목록 페이지가 있어야 한다. 일단 이거를 만드는 것에도 시간이 걸릴 것이고 만약에 이 게시글을 등록하는 권한이 로그인을 한 유저에게만 있다면? 그러면 또 로그인을 할 수 있는 페이지와 그것을 검증하는 과정이............... 난 그저 register() 메서드가 돌아가는지를 확인하고 싶었을 뿐인데......🤯 (응애 퇴근 언제해...)

하지만 mockMvc를 이용하면 웹 계층도 페이지 없이 console창에서 테스트가 가능하기 때문에 무언가 하나를 테스트하기 위해서 다른 수많은 페이지들을 만들 필요가 없다!

또한 우리가 코드를 많이 작성하게되면 객체가 많아지게 된다. 그러면 나중에 문제가 생겼을 때 어디에서부터 문제가 발생했는지를 알아내기가 힘들어진다.

근데 테스트가 가능하다면!

아! 내가 여기까지는 테스트를 다 했지? 그러면 게시물을 등록할 때 서비스의 컨트롤러, 매퍼까지는 문제가 없었으니까 브라우저와 컨트롤러 사이에서 뭔가 문제가 발생했겠구나! 하고 깨달을 수 있기 때문에 테스트를 하는 것이 정말정말 중요하다!!

  • 단점? : 이라고 하자면 mockMvc를 사용하기 위한 과정이 조금 있다는 점이다! 10분만 투자하자!

BoardControllerTests에서 달라진 점은 @ContextConfiguration에서 root-context.xml만 가져오는 게 아니라 servlet-context.xml도 가져온다는 것과
@WebAppConfiguration이 추가되었다는 점이다.

그리고 테스트용 MockMvc도 추가해야 한다.

  • 재미있는 점이 testList()는 서버가 꺼져있어도 실행이 된다는 것이다!😃 콘솔에서 list를 정상적으로 불러오는 것을 확인하고서 서버를 켠 상태로 실행 후 localhost/board/list (list.jsp가 만들어져있어야 해당 화면이 띄워진다)를 입력하면 테스트했던 것처럼 정상적으로 실행이 된다!!


2. 등록 입력/처리

등록/수정/삭제의 최종 처리는 POST 방식을 이용하는데 두가지 방식이 있다.

  1. 별도의 결과 페이지를 만들어서 보여주는 방식
    • 중요한 작업을 할 때 사용한다.
    • ex) 회원가입
  2. 목록 페이지로 바로 이동하는 방식 (더 많이 쓰인다) -> 'redirect:/...'를 고려
    • ex) 게시판

RedirectAttributes는 언제 사용하는가?

  • GET방식의 입력 페이지 /board/register 에서 입력을 다 하고 등록 버튼을 누르면 POST방식으로 입력 처리가 진행이 된다.
    하지만 처리가 끝난 후에도 브라우저의 URL은 여전히 /board/register에 머물고 있기 때문에 이대로 브라우저를 새로고침을 하면 같은 내용의 글이 계속해서 작성이 된다. (도배! 문제 발생☠️)

  • 이러한 문제를 방지하기 위해서 강제로 'redirect:/board/list'를 이용해서 브라우저와 연결을 한 번 종료시키고 /board/list로 이동을 시킨다!


3. 조회

조회는 반드시 get방식으로 처리하는 것을 기억하자
조회페이지는 readonly 해주는 게 요즘 트렌드

DB를 통해서 새로운 데이터가 추가해서 나가야 하기때문에 model을 사용한다
model에다가 객체를 담는 과정 model.addAttribute("board", service.get(bno)); ...

@GetMapping({ "/get", "/modify" })
	public void get(@RequestParam("bno") Long bno, Model model) {

		log.info("/get or modify");
		model.addAttribute("board", service.get(bno));
	}

👻 뒤로 가기 문제

글을 작성하고나서 브라우저에 데이터가 남아있는 상태로 뒤로가기/앞으로가기 등을 눌렀을 때 이미 떴던 모달창이 중복해서 계속 뜨기 때문에 (서버를 다시 호출하는 것이 아니라 과거에 자신이 가진 모든 데이터를 활용하기 때문) 데이터가 있는 경우에는 동작을 하지 않게하고 없을 경우에는 modal창을 띄우게끔 변경을 해줘야 한다!


4. 수정/삭제

주석으로 적어놨지만 int count로 하는 이유가 BoardService에서 int modify(BoardVO board)라고 이미 만들어 놨기 때문에 int를 사용해야 값을 받아올 수 있다!

오전에 혼자 교재를 보면서 진행할 때는 타이핑을 하고 실행을 하면서 아 대충 이런식이구나... 하고 넘어갔는데 확실히 복습을 하면서 다시 보니까 왜 이렇게 타입을 정하고, 매개값을 왜 이거로 받고.. 등을 더 정확하게 알게된 것 같다 👍

HTML5부터 데이터 속성(data-xxx)을 이용해 커스텀으로 속성을 만들어서 쓸 수 있다! 이전처러 hidden으로 태그를 숨겨두고 데이터를 저장할 필요 없어 HTML 스크립트가 훨씬 간결해진다. 또한 하나의 HTML 요소에 여러 데이터 속성을 동시에 사용할 수 있다!

이벤트 처리할 때 e.preventDefault(); 를 하는 이유가 form태그 안에서 button을 누르면 자동으로 submit으로 하는 등의 기본 동작을 다 막아준다.


0개의 댓글