프레임워크(Framework)/Spring

[Spring] 스프링 프레임워크(Spring Framework)를 사용하는 이유

잇트루 2022. 10. 25. 17:59
반응형

JSP를 이용한 애플리케이션

JSP는 Java Server Page의 약자로 초창기 Java 기반의 웹 애플리케이션 개발은 JSP를 통해 이루어졌다. JSP 개발 방식은 사용자에게 보이는 View와 사용자의 요청을 처리하는 서버의 코드가 섞여있는 형태의 개발 방식이다.

 

JSP 예시

상당히 복잡하기 때문에 눈으로만 확인하는 것을 추천한다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!-- (1) 시작 -->
<%
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");

    System.out.println("Hello Servlet doPost!");

    String todoName = request.getParameter("todoName");
    String todoDate = request.getParameter("todoDate");

    ToDo.todoList.add(new ToDo(todoName, todoDate));

    RequestDispatcher dispatcher = request.getRequestDispatcher("/todo_model1.jsp");
    request.setAttribute("todoList", ToDo.todoList);

    dispatcher.forward(request, response);
%>
<!-- (1) 끝 -->
<html>
<head>
    <meta http-equiv="Content-Language" content="ko"/>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

    <title>TODO 등록</title>
    <style>
        #todoList {
            border: 1px solid #8F8F8F;
            width: 500px;
            border-collapse: collapse;
        }

        th, td {
            padding: 5px;
            border: 1px solid #8F8F8F;
        }
    </style>
    <script>
        function registerTodo(){
            var todoName = document.getElementById("todoName").value;
            var todoDate = document.getElementById("todoDate").value;

            if(!todoName){
                alert("할일을 입력해주세요..");
                return false;
            }
            if(!todoDate){
                alert("날짜를 입력해주세요.");
                return false;
            }

            var form = document.getElementById("todoForm");
            form.submit();

        }
    </script>
</head>
<body>
    <h3>TO DO 등록</h3>
    <div>
        <form id="todoForm" method="POST" action="/todo_model1.jsp">
            <input type="text" name="todoName" id="todoName" value=""/>
            <input type="date" name="todoDate" id="todoDate" value=""/>
            <input type="button" id="btnReg" value="등록" onclick="registerTodo()"/>
        </form>
    </div>
    <div>
        <h4>TO DO List</h4>
        <table id="todoList">
            <thead>
                <tr>
                    <td align="center">todo name</td><td align="center">todo date</td>
                </tr>
            </thead>
            <!-- (2) 시작 --->
            <tbody>
                <c:choose>
                    <c:when test="${fn:length(todoList) == 0}">
                        <tr>
                            <td align="center" colspan="2">할 일이 없습니다.</td>
                        </tr>
                    </c:when>
                    <c:otherwise>
                        <c:forEach items="${todoList}" var="todo">
                            <tr>
                                <td>${todo.todoName}</td><td align="center">${todo.todoDate}</td>
                            </tr>
                        </c:forEach>
                    </c:otherwise>
                </c:choose>
            </tbody>
            <!-- (2) 끝 -->
        </table>
    </div>
</body>
</html>

위 예제를 살펴보면, 클라이언트와 서버가 분리되어 있지 않고 html, javascript 코드와 java 코드가 하나의 페이지에서 작성한 것을 알 수 있다.

이러한 방식은 코드의 가독성이 떨어지며, 복잡하여 유지 보수 측면에서 매우 어려움을 겪는다.

또한, 프론트엔드와 백엔드 영역을 구분하지 않고 개발하는 방식으로 효율적인 협업이 불가능한 형태이다.

 

서블릿(Servlet)을 이용한 애플리케이션

JSP 방식은 엄밀히 말하면 내부적으로는 Servlet 방식을 사용한다. Servlet은 클라이언트 웹 요청 처리에 특화된 Java 클래스의 일종으로 볼 수 있다.

Spring을 사용한 웹 요청을 처리할 때에도 내부적으로는 Servlet을 사용한다.

 

서블릿 예시

서블릿 또한 상당히 복잡한 구조로 되어 있어 눈으로만 확인하는 것을 추천한다.

@WebServlet(name = "TodoServlet")
public class TodoServlet extends HttpServlet {
    // (1) Database를 대신한다.
    private List<ToDo> todoList;

    @Override
    public void init() throws ServletException {
        super.init();
        this.todoList = new ArrayList<>();
    }

        // (2)
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String todoName = request.getParameter("todoName");
        String todoDate = request.getParameter("todoDate");

        todoList.add(new ToDo(todoName, todoDate));

        RequestDispatcher dispatcher = 
                request.getRequestDispatcher("/todo.jsp");
        request.setAttribute("todoList", todoList);

        dispatcher.forward(request, response);
    }

        // (3)
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("Hello Servlet doGet!");

        RequestDispatcher dispatcher = 
                request.getRequestDispatcher("/todo.jsp");
        dispatcher.forward(request, response);
    }
}

Servlet을 이용한다는 것은 Servlet을 위한 Java 코드가 클라이언트 측 코드에서 분리되어 별도의 Java 클래스로 관리되는 것을 뜻한다.

즉, JSP 코드에서 서버 측 Java 코드는 서블릿 클래스로 분리하여 클라이언트와 서버 간의 역할이 분리된 것이다.

 

하지만 서블릿 방식 또한 코드가 길어 가독성이 떨어지고 유지보수 측면에서 JSP보다는 나을지라도 사용하기에 상당히 어렵다.

 

Spring MVC를 이용한 애플리케이션

서블릿 방식의 코드에서는 클라이언트의 요청에 담긴 데이터를 꺼내오는 작업을 개발자가 직접 코드로 작성해야 한다.

Spring MVC 방식을 사용하면 코드에서는 눈에 보이지 않지만, 해당 작업들을 Spring에서 알아서 처리해준다.

 

Spring MVC 예시

@Controller
public class ToDoController {
    @RequestMapping(value = "/todo", method = RequestMethod.POST)
    @ResponseBody
    public List<ToDo> todo(@RequestParam("todoName")String todoName,
                           @RequestParam("todoDate")String todoDate) {
        ToDo.todoList.add(new ToDo(todoName, todoDate));
        return ToDo.todoList;
    }

    @RequestMapping(value = "/todo", method = RequestMethod.GET)
    @ResponseBody
    public List<ToDo> todoList() {
        return ToDo.todoList;
    }
}

위 코드는 서블릿 방식의 코드를 Spring MVC 방식의 코드로 변경한 모습으로 코드가 매우 간결해졌다.

 

하지만, Spring 기반의 애플리케이션의 기본 구조를 잡는 설정 작업이 불편한 단점이 존재한다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-config/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-config/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>CORSFilter</filter-name>
        <filter-class>com.codestates.filter.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CORSFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Spring 애플리케이션을 정상적으로 구동하기 위한 설정 파일들의 일부이다.

web.xml이라는 설정 파일 이외에도 다른 설정 파일들도 필요로 한다.

 

실제로 Spring MVC의 이런 복잡한 설정 때문에 Spring 학습을 포기하기 쉬웠으나 이러한 문제점을 대부분 개선한 Spring Boot가 등장하게 되었다.

 

Spring Boot를 이용한 애플리케이션

Spirng MVC 기반의 코드를 Spring Boot 기반에서 조금 더 개선한 코드이다.

@RestController
public class TodoController {
    private TodoRepository todoRepository;

    @Autowired
    TodoController(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    @PostMapping(value = "/todo/register")
    @ResponseBody
    public Todo register(Todo todo){ // (1)
        todoRepository.save(todo); // (2)
        return todo;
    }

    @GetMapping(value = "/todo/list")
    @ResponseBody
    public List<Todo> getTodoList(){
        return todoRepository.findAll(); // (3)
    }
}

위 코드는 위 예시의 코드들에서 실제로 데이터를 저장하는 기능을 추가한 코드임에도 불구하고 코드의 길이는 축소되고, 가독성이 높아졌다.

 

또한, Spring MVC 방식에서의 복잡한 설정 파일은 다음과 같이 간결해졌다.

spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true

따라서 Spring의 복잡한 설정 작업도 Spring이 대신 처리해주기 때문에 개발자는 애플리케이션의 핵심 비즈니스 로직에만 집중할 수 있게 되었다.

 

따라서 Spring Framework를 사용하는 이유는 개발자가 핵심 비즈니스 로직에만 집중하여 효율적인 개발을 할 수 있으며, 유지보수가 쉽기 때문이다.

반응형