SPRING/Spring MVC

[SpringMVC] MVC 패턴 구현하기(1) - View

IT록흐 2023. 8. 8. 20:15
반응형

 

 

[SpringMVC] 응답(Response)의 종류 ( Text, Html, Json )

[SpringMVC] 요청(Request)의 종류 ( GET, POST, JSON ) [SpringMVC] 웹서비스에서 Request(요청)가 처리되는 원리 ( + Servlet ) JAVA Runtime Enviroment(JRE)는 하나의 프로세스, 다수의 스레드 환경이다. JVM은 하나의 프로

lordofkangs.tistory.com

 

지난 포스팅에서 서버가 클라이언트로 보내는 응답데이터의 종류에 대해서 다루어 보았다.  크게 두 가지 종류가 있다. 

 

1) 서버에서 동적으로 화면을 생성하는 경우 ( JSP, Thymleaf )

2) 클라이언트에서 동적으로 화면을 생성하는 경우 ( 리액트, vue.js )

 

 

1)의 경우, 서버쪽에서 동적으로 화면을 생성하여 정적인 html 페이지를 클라이언트로 보낸다. 2)의 경우, 클라이언트가 화면을 동적으로 생성하니, 서버는 JSON 데이터를 클라이언트에 전달하기만 한다. 

 

이번 포스팅에서 다룰 내용은 1)의 경우 서블릿과 화면생성(view)을 어떻게 분리하는지를 다루어 보겠다.

 

원시적인 초기 Servlet 코드

@WebServlet(name = "memberSaveServlet",urlPatterns = "/servlet/members/save")
public class MemberSaveServlet extends HttpServlet {

    MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        // [ Request 요청 데이터 가져오기 ]
        String username = request.getParameter("username");
        int age =Integer.parseInt(request.getParameter("age")) ;

        // [ 비즈니스 로직 ] 
        Member member =new Member(username,age);
        memberRepository.save(member);

        // [ 응답 Header 영역 데이터 설정 ]
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");

        // [ 응답 Body 영역 데이터 설정 ]
        PrintWriter w = response.getWriter();
        w.write("<html>\n" +
                "<head>\n" +
                " <meta charset=\"UTF-8\">\n" + "</head>\n" +
                "<body>\n" +
                "성공\n" +
                "<ul>\n" +
                "    <li>id="+member.getId()+"</li>\n" +
                "    <li>username="+member.getUsername()+"</li>\n" +
                "    <li>age="+member.getAge()+"</li>\n" + "</ul>\n" +
                "<a href=\"/index.html\">메인</a>\n" + "</body>\n" +
                "</html>");

    }
}

 

service 메소드는 3가지 순서로 동작한다. 

 

1) 요청 데이터 가져오기 ( Request )

2) 회원 저장하기 ( 비즈니스 로직 )

3) 응답 데이터 설정하기 ( Response )

 

3가지 과정을 모두 Servlet이 책임지다보니 service 메소드가 커져버린다. 더욱 심각한 것은 html을 동적으로 생성하는 로직이다. 이번 포스팅에서는 동적으로 HTML을 생성하는 로직을 Servlet으로부터 분리해보겠다. html 동적 생성 책임을 Servlet으로부터 분리해야 한다. JSP는 html 동적 생성을 책임지는 대표적인 서버사이드 스크립트 언어이다. 

 

 

[JSP] JSP 코드블록

[JSP] JSP의 역할 HTML 문서를 Dynamic하게 만드는 언어 중 하나가 JSP이다. 이번 포스팅에서는 HTML 문서를 Dynamic하게 만드는 과정에서 JSP의 역할을 알아보겠다. HTML 문서를 서블릿(Servlet)으로 만들기 HTM

lordofkangs.tistory.com

( JSP가 어떤 원리로 HTML을 동적생성하는지는 위 포스팅을 참고하면 된다. )

 

JSP가 html을 동적 생성하니 Servlet은 데이터만 넘겨주면 된다. 이때, Servlet과 JSP 사이를 연결해주는 객체가 있는데, 바로 RequestDispatcher이다. 

 

 

 

 

 

Servlet이 JSP 페이지가 위치한 경로와 전달할 데이터를 RequestDispatcher에 넘기면, RequestDispatcher는 이를 JSP에게 전달하는 원리이다. 그러면 JSP는 동적으로 html 화면을 생성한다. 

 

@WebServlet(name = "mvcMemberSaveServlet",urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {

    MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        // [ 요청 데이터 가져오기 ]
        String username = request.getParameter("username");
        int age =Integer.parseInt(request.getParameter("age")) ;
        
        // [ 비즈니스 로직 ]
        Member member =new Member(username,age);
        memberRepository.save(member);

        // [ 응답 데이터 JSP로 보내기 ]
        request.setAttribute("member",member); // 전달할 데이터를 request의 내부저장소에 보관 

        String viewPath = "/WEB-INF/views/save-result.jsp"; // JSP 페이지 경로 
        RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewPath); // RequestDispatcher 객체 호출 
        requestDispatcher.forward(request,response); // JSP로 request, response 데이터 전달 
    }
}

 

위는 서블릿이 RequestDispatcher를 호출하여 HTML 동적 생성 책임을 분리한 코드이다. RequestDispatcher는 서블릿으로 부터 JSP 경로와 전달 데이터를 넘겨받아 JSP에게 넘긴다.  

 

그럼 이제 VIEW 영역을 분리해보자. 

 

public class MyView {
    private String viewPath;

    public MyView(String viewPath){
        this.viewPath = viewPath;
    }

    public void render(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
        RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewPath);
        requestDispatcher.forward(request,response);
    }
}

 

MyView 클래스를 하나 만들었다. MyView는 render 메소드를 갖는다. render 메소드는 RequestDispatcher를 호출하여 JSP에게 데이터를 전달하는 기능을 한다.  그럼 Servlet 코드를 수정해보자. 

 

@WebServlet(name = "mvcMemberSaveServlet",urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {

    MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        // [ 요청 데이터 가져오기 ]
        String username = request.getParameter("username");
        int age =Integer.parseInt(request.getParameter("age")) ;
        
        // [ 비즈니스 로직 ]
        Member member =new Member(username,age);
        memberRepository.save(member);

        // [ 응답 데이터 JSP로 보내기 ]
        request.setAttribute("member",member); // 전달할 데이터를 request의 내부저장소에 보관 

        String viewPath = "/WEB-INF/views/save-result.jsp"; // JSP 페이지 경로 
        MyView myView = new MyView(viewPath); //MyView 생성
        myView.render(request,response); // 렌더링
    }
}

 

 

서블릿이 직접 Response의 Header영역과 Body영역을 설정하지 않으니 코드가 굉장히 깔끔해졌다. 이로써 서블릿은 이전보다 한층 더 비즈니스 로직에 집중할 수 있게 되었다. 이렇듯 View를 분리하므로써 서블릿이 Response를 신경쓰지 않아도 된다.  Response는 View영역에서 처리하므로 서블릿은 Response 객체를 그대로 파라미터로 전달만 하면 된다. 서블릿은 그저 비즈니스 로직을 처리한 결과를 Request에 담아 View 영역에 전달만 하면 된다. 

 

그런데 아직 완전한 분리가 이루어진 것이 아니다. View는 분리했지만 모든 서블릿이 MyView를 호출하는 공통로직을 가지게 되었다. 이는 많은 중복코드를 만들어낸다. 다음 포스팅에서는 Controller를 분리하여 비즈니스 로직에 더 집중된 코드를 만들어 보겠다. 

 

 


 

 

참고자료 

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com

 

반응형