본문 바로가기
Spring/스프링 MVC

[스프링 MVC 1편] 3 - (3) MVC 패턴

by Poorm 푸름 2023. 11. 8.

* 스프링 입문은 Window로 스프링 MVC 1편은 Mac으로 진행합니다  

 *  진도 : 섹션3 - (4) ~ (5) 
               섹션3 - (3) 부분은 잘 사용하지 않는 jsp 부분이라 생략 (강의를 참고해주세요)
 *          : 자바 클래스명,         : 코드,         : 단축키

 

 

1. 서블릿과 JSP


  Servlet JSP
코드 내 처리방법 자바 코드 속에서 HTML 태그로 문자열(””) 로 처리해야 함. HTML 속에서 자바코드를 <% 소스코드 %> 또는 <%= 소스코드 =%>형태로 처리.
(자바 소스코드로 작성된 부분은 웹 브라우저로 보내는 것이 아니라 웹 서버에서 실행됨)
한계(Servlet)와 보완(JSP) 1. 화면 인터페이스 구현에 너무 많은 코드를 필요로 하는 비효율성

2. 테스트할 때 빌드를 항상 다시해야 한다는 한계가 있음

3. HTML 변경 시 Servlet을 재컴파일해야 하는 단점

1. HTML 표준에 따라 작성되므로 서블릿과 달리 웹페이지 작성이 편리

2. WAS에서 자동으로 빌드하고 클라이언트 화면에 동적으로 보여준다.
MVC 패턴에서의 역할 Controller 역할 View 역할
출처 https://velog.io/@effirin/Servlet%EA%B3%BC-JSP%EC%97%90-%EB%8C%80%ED%95%B4

 

  • 서블릿 
    HTML을 만드는 작업이 자바 코드에 섞여서 지저분하고 복잡
  • JSP
    HTML 작업은 깔끔, 중간중간 동적으로 변경이 필요한 부분에만 자바 코드를 적용
    이또한 복잡하기는 하다

  • MVC
    비즈니스 로직은 서블릿 처럼 다른곳에서 처리, JSP는 목적에 맞게 HTML로 화면(View)을 그린다

 

 

2. MVC 패턴 개요

 

https://m.blog.naver.com/sejun3278/221575009683

 

더보기
https://kotlinworld.com/326

 

https://velog.io/@dbsrud9126/Spring-MVC

 

  • Controller (컨트롤러)
    • HTTP 요청을 받아서 파라미터를 검증, 비즈니스 로직 실행
    • 컨트롤러에 비지니스 로직을 바로 담으면 너무 복잡해서 서비스 계층을 따로 만들어 별도로 처리
    • 비지니스 로직 변경하면 비지니스 로직을 호출하는 컨트롤러의 코드도 변경될 수 있다
    • 뷰에 전달할 결과 데이터를 조회해서 모델에 담기
  • Model (모델)
    • 뷰에 출력할 데이터를 담기
  • View (뷰)
    • 모델에 담겨있는 데이터를 사용해서 화면을 그린다 (HTML 생성)
    • 비즈니스 로직이나 데이터 접근을 몰라도 되고, 화면을 렌더링 하는 일에 집중

 

3. MVC 패턴 적용_회원 등록
 [ src - java - hello - servlet - web - servletmvc - MvcMemberFormServlet ]

 

컨트롤러 → 서블릿 사용

JSP 사용

모델 HttpServletRequest 객체 사용

           (데이터 보관 및 조회 request.setAttribute() , request.getAttribute())

 

 

- 상속 extends HttpServlet 

  • 서블릿을 사용하기 위해 HttpServlet을 상속받는다

- 컨트롤러 = 서블릿 생성 @WebServlet

  • 해당 어노테이션에 경로를 입력하면 클라이언트에서 톰캣서버가 찾아서 실행한다
  • /servlet/members/new-form 입력하면 하위 메서드 실행
@WebServlet(name = "mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
public class MvcMemberFormServlet extends HttpServlet

 

- 서비스 생성 protected service 

  • servlet 호출되면 서비스 메서드도 호출
  • 위에서 만든 urlPatterns 대로 검색하면 콘솔 로그에 해당 명령어 출력
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

 

- 컨트롤러에서 뷰로 이동 (option + command + v)

String viewPath ="/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
  • viewPath에 JSP 경로 넣기
    • /WEB-INF
      이 경로 안에 있는 자원들은 외부에서 직접 JSP를 호출 X
      항상 컨트롤러를 통해서 JSP를 호출
  • dispatcher.forward() : 다른 서블릿이나 JSP로 이동할 수 있는 기능(서버 내부에서 호출)
    • [ 웹 브라우저 요청 - 컨트롤러 서버 - 뷰 렌더링 ] 완료해도 url 변경 없다
    • 클라이언트에서 서버를 호출하고 서버 안에서 자기네들끼리 호출

 

< redirect vs forward >

  • 리다이렉트 클라이언트(웹 브라우저)에 응답이 나갔다가, 클라이언트가 redirect 경로로 다시 요청
    (URL 경로 변경)
  • 반면에 포워드는 서버 내부에서 일어나는 호출이기 때문에 클라이언트가 인지 불가

 

- 출력 (JSP 작성) [ src - main - webapp - WEB_INF - views - New-form.jsp ]

<form action="save" method="post">
  username: <input type="text" name="username" />
  age: <input type="text" name="age" />
  <button type="submit">전송</button>
</form>
  • 나머지 코드는 강의 자료 참고
  • 상대경로 = 현재 URL이 속한 계층 경로 + action
    • 보통 action에 /경로를 적는데 여기서는 상대 경로라 /를 빼고 입력
    • 예시)
      현재 계층 경로
      : /servlet-mvc/members/
      결과: /servlet-mvc/members/save  

 < 결과 >

  • 실행
    http://localhost:8080 실행 후 서블릿 MVC 회원가입 클릭

  • 결과
    form 화면에서 데이터 입력하면 주소가 아래와 같이 변경된다
    변경 전 주소 (localhost:8080/servlet-mvc/members/new-form)
    변경 후 주소 (localhost:8080/servlet-mvc/members/save) = 상대 경로

 

 

4. MVC 패턴 적용_ 회원 저장
 [ src - java - hello - servlet - web - servletmvc - MvcMemberSaveServlet ]

 

  1. 파라미터를 조회해서 Member 객체 생성
  2. Member 객체를 MemberRepository를 통해서 저장
  3. Member 객체를 사용해서 결과 화면용 HTML을 동적으로 만들어서 응답

 

- 상속 extends HttpServlet 

  • 서블릿을 사용하기 위해 HttpServlet을 상속받는다

- 서블릿 생성 @WebServlet

  • 해당 어노테이션에 경로를 입력하면 클라이언트에서 톰캣서버가 찾아서 실행한다
  • /servlet/members/save 입력하면 하위 메서드 실행
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {

 

- 리포지토리 가져오기  private MemberRepository.getInstance 

  • 싱글톤 패턴이므로
    • static 영역에 객체 instance를 하나만 미리 생성
       MemberRepository 에서 생성해놨었다 ([스프링 MVC 1편] 3-(1) 참고)
    • private 생성자를 사용  외부에서 임의로 new 사용 X
    • getInstance() 메서드를 통해서만 조회
 private MemberRepository memberRepository = MemberRepository.getInstance();

 

- 서비스 생성 protected service 

  • servlet 호출되면 서비스 메서드도 호출
  • 위에서 만든 urlPatterns 대로 검색하면 콘솔 로그에 해당 명령어 출력
protected void service(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {

 

- form data 값 읽어오기

  • request.getParameter()는 문자로만 읽어올 수 있다
    • age는 숫자 타입으로 변환하기
      String username = request.getParameter("username");
      int age = Integer.parseInt(request.getParameter("age"));

 

- Member 객체 생성

  • 비지니스 로직 관리
        Member member = new Member(username, age);
        memberRepository.save(member);

 

- 모델에 데이터 담기 request.setAttribute()

        request.setAttribute("member", member);

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
  • request.setAttributerequest 객체에 데이터를 보관해서 뷰에 전달

    ( 뷰는 request.getAttribute() 를 사용해서 데이터를 꺼낸다 )

  • viewPath에 JSP 경로 넣기
    • /WEB-INF
      이 경로 안에 있는 자원들은 외부에서 직접 JSP를 호출 X
      항상 컨트롤러를 통해서 JSP를 호출
  • request.getDispatcher ( option + command + v )

  • dispatcher.forward() : 다른 서블릿이나 JSP로 이동할 수 있는 기능(서버 내부에서 호출)
    • [ 웹 브라우저 요청 - 컨트롤러 서버 - 뷰 렌더링 ] 완료해도 url 변경 없다
    • 클라이언트에서 서버를 호출하고 서버 안에서 자기네들끼리 호출

 

 - 출력 (only JSP)  [ src - main - webapp - WEB_INF - views - save-result.jsp ]

<li>id=${member.id}</li>
<li>username=${member.username}</li>
<li>age=${member.age}</li>
  • ${} 문법을 사용해 request의 attribute에 담긴 데이터를 편리하게 조회

    (<%= request.getAttribute("member")%> 로 모델에 저장한 member 객체를 꺼낼 수 있지만 너무 복잡)

  • 나머지코드는 강의자료 참고

  • 서블릿 방식에서는 w.wrtie()로 직접 출력하고 JSP 방식에서는 JSP 파일 자체에 자바코드를 넣어 실행했다
  • MVC 방식에서는 자바코드는 서블릿에는 자바코드만 넣어 비지니스 로직 실행하고 JSP에는 html만 입력해서 뷰 역할을 맡는다

  • 실행 : http://localhost:8080/servlet/members/new-form 실행 후 데이터 입력
  • 결과

 

 

5. MVC 패턴 적용_ 회원 목록
 [ src - java - hello - servlet - web - servletmvc - MvcMemberListServlet ]

 

- 상속 extends HttpServlet 

  • 서블릿을 사용하기 위해 HttpServlet을 상속받는다

- 서블릿 생성 @WebServlet

  • 해당 어노테이션에 경로를 입력하면 클라이언트에서 톰캣서버가 찾아서 실행한다
  • /servlet-mvc/members 입력하면 하위 메서드 실행
@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members")
public class MvcMemberListServlet extends HttpServlet {

 

- 리포지토리 가져오기  private MemberRepository.getInstance 

  • 싱글톤 패턴이므로
    • static 영역에 객체 instance를 하나만 미리 생성
       MemberRepository 에서 생성해놨었다 ([스프링 MVC 1편] 3-(1) 참고)
    • private 생성자를 사용  외부에서 임의로 new 사용 X
    • getInstance() 메서드를 통해서만 조회
 private MemberRepository memberRepository = MemberRepository.getInstance();

 

- 서비스 생성 protected service 

  • servlet 호출되면 서비스 메서드도 호출
  • 위에서 만든 urlPatterns 대로 검색하면 콘솔 로그에 해당 명령어 출력
protected void service(HttpServletRequest request, HttpServletResponse response)

 

- 데이터 조회 (option + command + v)

List<Member> members = memberRepository.findAll();

 

- 모델에 데이터 담기 request.setAttribute()

        request.setAttribute("member", member);

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
  • request.setAttribute request 객체에 데이터를 보관해서 뷰에 전달

    ( 뷰는 request.getAttribute() 를 사용해서 데이터를 꺼낸다 )

  • viewPath에 JSP 경로 넣기
    • /WEB-INF
      이 경로 안에 있는 자원들은 외부에서 직접 JSP를 호출 X
      항상 컨트롤러를 통해서 JSP를 호출
  • request.getDispatcher ( option + command + v )

  • dispatcher.forward() : 다른 서블릿이나 JSP로 이동할 수 있는 기능(서버 내부에서 호출)
    • [ 웹 브라우저 요청 - 컨트롤러 서버 - 뷰 렌더링 ] 완료해도 url 변경 없다
    • 클라이언트에서 서버를 호출하고 서버 안에서 자기네들끼리 호출

 

- 출력 (only JSP)  [ src - main - webapp - WEB_INF - views - members.jsp ]

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<c:forEach var="item" items="${members}">
       <tr>
            <td>${item.id}</td>
            <td>${item.username}</td>
            <td>${item.age}</td>
       </tr>
  </c:forEach>
  • 자바코드 for문 대신에 <c:forEach>을 사용하면 members 리스트에서 member 를 순서대로 꺼내서 item 변수에 담고 출력하는 과정을 반복할 수 있다

  • <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 필요
  • 나머지코드는 강의자료 참고
  • 실행 : http://localhost:8080에서 서블릿 MVC - 회원가입에서 회원 등록 후 회원목록 조회
  • 결과