프로그래밍/Spring

[오류해결] Spring 헤더에서 선언한 *.js, *.css 등 리소스 파일을 찾을 수 없을 때

대두 2022. 1. 24. 15:53

[주의] Spring Boot가 아닌 Spring MVC Legacy Project를 생성해 공부 중인 자료입니다.

 

오늘 겪었던 일이다. 현재 개인공부로 스프링 프레임워크로 나만의 페이지를 제작하고 있다. 오늘은 오픈소스로 공개된 글 에디터를 사용해보기 위해 나는 다음에서 제작한 다음 에디터를 내 홈페이지 글쓰기 페이지에다가 입히려고 했다.

 

분명 리소스들의 경로도 제대로 설정 했고, 확인도 했다.

탐색기 모습
제대로 경로가 설정되어있음을 알 수 있다.

 

하지만 결과는...

보다시피 에디터가 아닌 뭔가다...

오류 코드를 보면 404 오류 천지, 그니깐 찾을 수 없단다. (net::ERR_ABORTED, .... is not defined ...)

 

구글링을 통해 알게 된 결론은 컨트롤러 단에서 매핑하지 않은 정적 리소스 파일들은 불러오지를 못하고 만다는 것이다.

(이게 정확한 워딩은 아니다. 나도 초보고, 이제 막 배우기 시작했다)

 

그렇다면 이제 해결해보자

 

방법은 두 가지를 찾았다.

 

첫 번째로는 직접 처리가 필요한 리소스 파일의 확장자를 매핑해주는 방법이다.

 

단축키를 쓰면 이렇게 빠르게 찾을 수 있다.

일단, <web.xml> 파일을 찾아가자 (단축키는 'Ctrl + Shift + R', 빠르게 필요한 파일을 찾을 때 유용하다)

여기에 도착하면 별 알 수 없는 여러 코드들이 우릴 마주한다.

대충 웹 어플리케이션 실행 시 우리가 어떻게 무엇을 할지에 대한 설정을 정의해주는 곳이다.

 

그렇다면 여기서 우리가 사용할 리소스 파일들을 선언해 실행시에 불러와 줄 수 있도록 하자.

 

<!-- Processes application requests --> 라는 주석을 발견할 수 있을 것이다.

직역하면 '애플리케이션 요청 처리'를 하는 곳이다. 우리가 필요한 부분이다.

(사실 아무대나 써도 되지만, 코드를 보기 좋게 처음부터 쓰면 나중에 유지보수가 용이하지 않을까)

 

<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
    
    <!-- *.js 확장자 파일의 요청이 오면 default 서블릿을 사용하겠다 -->
	<servlet-mapping>
        	<servlet-name>default</servlet-name>
        	<url-pattern>*.js</url-pattern>
    	</servlet-mapping>
    
	<servlet-mapping>
        	<servlet-name>default</servlet-name>
        	<url-pattern>*.css</url-pattern>
    	</servlet-mapping>

이와 같이 js 파일과 css 파일을 매핑해보자. 주석 내용 처럼 될까?

 

톰캣 서버를 다시 실행해보자.

 

뭔가 이상하다

뭔가 바뀌긴 했다. 근데 밋밋하게 느껴진다. 뭘까?

 

그렇다. 다른 gif, png, ico 파일 등 많은 다른 정적 리소스들이 누락되었다. 물론 필요한 확장자만 추가해서 불러오도록 하는 장점이 있지만, 위 캡쳐같이 다른 파일들을 놓칠 수도 있겠다는 생각이 들었다.

 

그렇다면 한번에 모든 정적 파일들을의 요청을 처리할 수는 없을까?

 

그렇다. 있었다.

 

바로 <servlet-context.xml>에

<default-servlet-handler />

라는 핸들러를 작성해주면 된다.

이게 무엇을 말하는 거냐면...

 

Servlet Context는 Servlet에 대한 설정을 작성하는 클래스라고 보면 되는데, Servlet과 Container의 연동시 사용하며, 웹 어플리케이션마다 하나의 Servlet Context가 생성된다. Bean을 찾는 순서가 Servlet Context가 Application Context 보다 먼저 실행되고, 컨테이너 종료시 소멸한다.

 

나도 더 공부해야겠다. 말이 많이 어려운 듯 하다.

(잘못된 점이 있다면 따끔하게 댓글 남겨주세요)

 

어쨌거나 저쨌거나 이제 사용을 해보자.

일단, 먼저 Namespaces를 추가해 주어야 한다.

 

Spring MVC 예제이니 당연하지만 mvc를 체크해야한다.

그렇다면 요렇게 추가가 된다. 그 후에 위에 적은 핸들러 코드를 잘 집어 넣어보자.

 

<servlet-context.xml 예제>

 

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

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>	
	
	<context:component-scan base-package="com.example.mvcboard" />
	
	<!-- .js .css 등 정적 리소스를 불러오지 못할 때 -->
	<default-servlet-handler />
	
</beans:beans>

 

서버를 다시 실행하면?

 

오류가 0개!

보다시피 오류 하나 없이 모든 리소스를 불러와 깔끔하게 화면이 출력됨을 알 수 있다.

 

이거 하나 찾느라 꽤 시간을 투자한 것 같다. 하지만 해결하면서 몰랐던 용어들도 공부할 수 있었고 좋았다.

 

 

하지만 더 찾아보고 이해해보려 노력해야겠다.

블로그를 통해 많은 공부, 복습을 할 수 있도록 하겠다.

 

 

 

도움 받은 곳들

- Spring에서 css,image,js 등의 정적 리소스를 찾을 수 없을때 :: 밍깅료의 블로그 (tistory.com)

- [Spring Framework] Spring MVC : <mvc:default-servlet-handler/> 개념 (tistory.com)

- Servlet에 대한 개념없이 스프링을 했네요? (급하게 알아보는 스프링 기반 기술 Servlet, Servlet Context, Application Context, ...) (tistory.com)

- 그외 구글링.....