Spring MVC 프레임워크 Support 추가 후 /web 패키지가 생성되는데, 이 아래에 있는 web.xml 파일의 아래 부분을

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.form</url-pattern>
  </servlet-mapping>

 

이렇게 바꿔줘야 한다.

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

 

톰캣의 web.xml파일은 톰캣의 실행환경에 대한 정보를 담당하는 환경설정 파일이다. 

각종 servlet의 설정과 servlet 매핑, 필터, 인코딩 등을 담당한다.
web.xml은 각 application이 deploy될 때 각 application의 'WEB-INF/web.xml' deployment descripter에 따라서 처리가 된다.


 

일단 서블릿과 웹 페이지 동작에 대해 잘 모르겠어서 관련 내용을 찾아 보았다.

 

서블릿이란 웹 프로그래밍에서 클라이언트의 요청을 처리하고 그 결과를 다시 클라이언트에게 전송하는 서블릿 클래스의 구현 규칙을 지킨 자바 프로그래밍 기술이다. 즉, 클라이언트의 HTTP 요청에 대해 특정 기능을 수행, HTML문서를 생성등의 응답을 하는 인터넷 서버 프로그램이다. 일반적으로 웹 서버는 정적인 페이지만을 제공한다. 따라서 동적인 페이지를 제공하기 위해서 웹 서버는 다른 곳에 도움을 요청하여 동적이 페이지를 작성해야 한다. 동적인 페이지로는 임의의 이미지만을 보여주는 페이지와 같이 사용자가 요청한 시점에 페이지를 생성해서 전달해 주는 것을 의미한다.

 

여기서 웹 서버가 동적인 페이지를 제공할 수 있도록 도와주는 어플리케이션이 서블릿이고, 동적인 페이지를 생성하는 어플리케이션이 Common Gateway Interface이다. CGI는 별도로 만들어 놓은 프로그램에 HTML의 GET/POST 방법으로 클라이언트의 데이터를 환경 변수로 전달하고, 프로그램의 표준 출력 결과를 클라이언트에게 전송한다.

 

서버와 클라이언트는 HTTP request/response로 통신하는데, 서버가 요청을 받으면 정적 자원에 대한 요청일 경우 자원을 반환해주고, 그렇지 않는 경우 CGI 프로그램을 실행하여 해당 결과를 리턴해준다. 이 때, 서버는 CGI 프로그램에게 클라이언트의 요청과 매개 변수를 전달해주고, 결과를 전달 받기 위한 파이프라인을 연결한다. 그래서 CGI 프로그램은 입력에 대한 서비스를 수행하고, 결과를 클라이언트에게 전달하기 위해 결과 페이지에 해당하는 MIME 타입의 컨텐츠 데이터를 웹 서버와 연결된 파이프라인에 출력하여 서버에 전달한다. 서버는 파이프라인을 통해 CGI 프로그램에서 출력한 결과 페이지의 데이터를 읽어 HTTP 응답헤더를 생성하여 데이터를 함께 반환해준다.

 

--> Servlet

  • 클라이언트의 요청에  대해 동적으로 작동하는 웹 어플리케이션 컴포넌트이다.
  • html을 사용하여 요청에 응답한다.
  • 자바 스레드를 이용하여 동작한다.
  • MVC 패턴에서 컨트롤러로 이용된다.
  • HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받는다.
  • UDP보다 속도가 느리다.
  • HTML 변경 시 Servlet을 재컴파일 해야 하는 단점이 있다.

 

이 서블릿을 관리해주는 서블릿 컨테이너가 있다. 서블릿 컨테이너는 서블릿의 생명주기를 관리하고 요청에 따른 스레드를 생성해준다. 또, 클라이언트의 request를 받아주고 response를 보낼 수 있게 웹 서버와 소켓을 만들어 통신을 해준다. 서블릿 컨테이너의 예가 톰캣이다. 톰캣은 실제로 웹 서버와 통신하여 Java Server Page(JSP)와 Servlet이 작동하는 환경을 제공해준다.

 

--> Servlet Container이란

  • 웹 서버와의 통신 지원: 일반적으로 소켓을 만들어서 listen, accept를 함으로써 통신을 하지만, 서블릿 컨테이너는 서블릿과 웹 서버가 쉽게 통신할 수 있도록 API를 제공해준다. 
  • 서블릿 생명주기 관리: 서블릿 컨테이너는 서블릿 클래스를 로딩하여 인스턴스화 하고, 초기화 메소드를 호출하고, 요청이 들어오면 적절한 서블릿 메소드를 호출한다. 또한, 서블릿이 생명이 다 한 순간에는 적절하게 가비지 컬렉션을 진행한다.
  • 멀티 스레드 지원 및 관리: 서블릿 컨테이너는 요청이 들어올 때마다 새로운 자바 스레드를 하나 생성하는데, HTTP 메소드 실행 후에 스레드는 죽는다. 원래는 스레드를 관리해야 하지만 서버가 다중 스레드를 생성 및 운영해주기 때문에 스레드의 안정성에 대해서 걱정하지 않아도 된다.
  • 보안 관리: 서블릿 컨테이너를 사용하면 보안 관련 내용을 서블릿 또는 자바 클래스에 구현하지 않아도 된다. 일반적으로 보안 관리는 xml 서술자에 기록하기 때문에, 보안에  대해 수정할 일이 생기더라도 자바 소스 코드를 수정하여 다시 컴파일 하지 않아도 보안 관리가 가능하다. 

 


 

다시 web.xml 설정으로 돌아가서

톰캣의 ${TOMCAT_HOME}/conf/web.xml 파일에는 3개의 서블릿 매핑이 존재한다.

 

즉 *.jsp, *.jspx와 같은 url 패턴은 JspServlet이 처리하고,

DefaultServlet은 spring Controller mapping과 jsp 패턴에 걸리지 않는 요청 들을 처리한다.

(png, jpg, js, html등 정적인 content)

 

<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

...

<servlet-mapping>
	<servlet-name>jsp</servlet-name>
	<url-pattern>*.jsp</url-pattern>
</servlet-mapping>

...

<servlet-mapping>
	<servlet-name>jsp</servlet-name>
	<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

처음에 servlet-mapping을 /로 설정하면서 default 서블릿을 dispatcher 서블릿으로 덮어쓴 것이다.

그런데 이렇게만 해준다면 기존의 jsp 패턴에 걸리지 않던 png, jpg, js, html과 같은 정적인 content를 요청할 때 오류가 날 것이다.

 

.jsp든 .js, .css든 WAS만 구동하는경우 해당 파일에 직접접근하는 경우는 없다. 일단 요청은 톰캣이 모두 받게된다.

그리고 톰캣은 서블릿에 패턴을 통해서 요청을 처리하게되는데 /로 지정하게되면 *.jsp로 오는 요청은 jsp 서블릿이 처리하겠지만,

그 외에는 default 서블릿이 처리를 해야하는데 이 default 설정을 덮어써서 default 서블릿이 작동하지 않으면 문제가 발생한다.

 

이를 해결하기 위해서는 서블릿 필터 등을 통해 정적인 요청은 default 서블릿으로 명시적으로 위임하도록 하는 2가지 방법이 있다.

이 핸들러를 구성하면 dispatcher가 모든 요청을 default servlet으로 전달한다.

 

WebConfig.java

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {

  @Bean
  public ViewResolver getViewResolver(){
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/");
    resolver.setSuffix(".html");
    return resolver;
  }

  @Override
  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
  }
}

 

servlet-context.xml: Default ServletHandler가 Bean으로 등록되며 동작

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  <mvc:annotation-driven/>
  <mvc:default-servlet-handler/>
</beans>

 

마지막으로 project structure - articats에 들어가서 필요한 라이브러리를 추가해주도록 한다.

- Spring_5_2_3_RELEASE

- Spring_MVC_5_2_3_RELEASE

 

참고

https://lng1982.tistory.com/97

https://multifrontgarden.tistory.com/145

 

+ Recent posts