본문 바로가기
DEV/Spring

[Spring] 2. 초기 프로젝트 설정

by 화트마 2019. 7. 13.

1. index.jsp 추가

- 기존에는 서버실행 시 home.jsp가 실행됨

- 하지만 보통 웹사이트의 경우 index.jsp가 실행됨

- src/main/webapp 디렉토리 밑에 index.jsp 추가

 

<body> 
  <h1>Hello World</h1> 
</body>

 

2. web.xml 변경

- web.xml에 다음 내용 추가

<?xml version="1.0" encoding="UTF-8"?> 
  <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 

    <welcome-file-list> 
      <welcome-file>index.jsp</welcome-file> 
    </welcome-file-list>

<web-app></web-app> 태그 사이에 추가

 

3. 서버 실행

- Tomcat Run

http://localhost:8080/"프로젝트명"/ 입력

 

4. 서블릿 설정 변경

- 서블릿(Servlet) : 자바에서 동적 웹 프로젝트를 개발할 때, 사용자의 요청과 응답을 처리해 주는 역할

- 보통 스프링에서는 servlet 설정이 .do로 되어있는데, 기본 프로젝트에서는 .do로 되어있지 않음. 따라서, 서블릿 설정을 변경

- web.xml에 <servlet> 및 <servlet-mapping> 부분 수정.

 

<!-- 기존 servlet 설정 
   <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> 
 -->

<!-- servlet 설정 변경 -->
  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class> org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value> /WEB-INF/config/*-servlet.xml </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

여기서 볼 것은 <url-pattern>*.do</url-pattern> 부분이다.

이는 앞으로 서블릿에 어떠한 요청을 할 때, .do를 통해서만 요청을 전달하고, 다른 방식의 요청, 예를 들어 .html의 직접적인 호출등은 이제 허락되지 않는다.

 

그 다음 확인할 부분은 contextConfigLocation의 설정이다. 

기존에는 dispatcher 의 설정인 contextConfigLocation이 /WEB-INF/spring/appServlet/servlet-context.xml에 존재하였는데, 이를 /WEB-INF/config/action-servlet.xml로 변경하고, 인터셉터(Intercepter)도 추가하려는 목적이다. 인터셉터에 대한 설명은 다음 글에서 하려고 한다.

 

5. contextConfigLocation 변경

 - /WEB-INF 디렉토리 밑에 config 라는 폴더를 만듦

 - /WEB-INF/spring/appServlet 디렉토리에 있는 servlet-context.xml을 복사해서, /WEB-INF/config 폴더에 붙여넣고, 이름을 action-servlet.xml로 변경

 - /WEB-INF/에 있는 spring이라는 디렉토리를 삭제한다.


6. 설정파일 변경 (web.xml, action-servlet.xml 등)
 - web.xml 수정. 다음 내용 추가 (UTF-8설정)

<filter> 
    <filter-name>encodingFilter</filter-name> 
    <filter-class> org.springframework.web.filter.CharacterEncodingFilter </filter-class> 
    <init-param> 
		<param-name>encoding</param-name> 
		<param-value>utf-8</param-value> 
	</init-param> 
</filter> 
<filter-mapping> 
	<filter-name>encodingFilter</filter-name> 
	<url-pattern>*.do</url-pattern> 
</filter-mapping>

 Spring 설정파일 추가

기존 <context-param> 태그의 <param-value> 태그안에는 아마 아무것도 작성되지 않았을 것임. 스프링 설정파일을 읽어오기 위해서 다음과 같이 바꾼다.

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value> classpath*:config/spring/context-*.xml
		</param-value>
	</context-param>

7. Log4j 설정

- log4j.xml 변경

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- 변경된 log4j.xml -->
	<!-- Appenders -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %5p [%c] %m%n" />
        </layout>   
    </appender>
    
    <appender name="console-infolog" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %5p %m%n" />
        </layout>   
    </appender>
	
	<!-- Application Loggers -->
	<logger name="hmg" additivity="false"> <!-- logger name은 최상위 package 명으로 설정 -->
		<level value="debug" />
		<appender-ref ref="console"/>
	</logger>
	
	<!-- Query Loggers -->
	<logger name="jdbc.sqlonly" additivity="false">  
    	<level value="INFO"/>  
        <appender-ref ref="console-infolog"/>  
    </logger>
    
    <logger name="jdbc.resultsettable" additivity="false">  
    	<level value="INFO"/>  
        <appender-ref ref="console"/>  
    </logger>  

	<!-- Root Logger -->
	<root>
		<priority value="off"/>
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

 

8. Interceptor 설정

인터셉터는 중간에 무엇인가를 가로챈다는 의미이다. 스프링에서도 말 그대로 중간에 요청을 가로채서 어떠한 일을 하는것을 의미한다. 서블릿(Servlet)을 사용해본 사람이라면 필터(Filter)를 들어봤을텐데, 비슷한 의미로 사용된다. 그럼 어느 중간에서 요청을 가로채서 무엇을 하는지를 간단히 살펴보자.

사진 출처 :  http://blog.daum.net/gunsu0j/165

 

인터셉터는 위 이미지의 빨간색 박스 부분에서 동작한다. 인터셉터의 정확한 명칭은 핸들러 인터셉터 (Handler Interceptor)이다. 인터셉터는 DispatcherServlet이 컨트롤러를 호출하기 전,후에 요청과 응답을 가로채서 가공할 수 있도록 해준다. 
예를 들어, 로그인 기능을 구현한다고 했을때, 어떠한 페이지를 접속하려고 할때, 로그인된 사용자만 보여주고, 로그인이 되어있지 않다면 메인화면으로 이동시키려고 해보자. 기존에는 로그인 체크 로직을 만들어서 각 화면마다 일일이 Ctrl + C,V로 만들기도 했다. 

스프링에서는 인터셉터를 사용하여 위의 기능을 간단히 만들 수 있다. 

인터셉터에서 어떠한 요청이 들어올 때, 그 사람의 로그인 여부를 판단해서 로그인이 되어있으면 요청한 페이지로 이동시키고, 로그인이 되어있지 않을경우 바로 메인 페이지로 이동시키면 끝이다. 

즉, 단 하나의 인터셉터로 프로젝트내의 모든 요청에서 로그인여부를 관리할 수 있는것이다.

 

먼저 src/main/java/"hmg"(상위패키지명) 패키지 내에 common 패키지를 생성하고 그 밑에 logger 패키지를 생성

  마찬가지로 HomeController.java도 삭제한다.


logger 패키지 밑에 LoggerInterceptor.java를 생성 (현재 호출된 URI이 무엇인지 출력해주는 인터셉터)
  인터셉터는 HandlerInterceptorAdapter 클래스를 상속받아서 만든다. 

  HandlerInterceptorAdapter에서는 사용할 수 있는 몇가지 메서드들이 있는데 우리는 일단 두가지만 구현하려고 한다. 전처리기와 후처리기가 바로 그것인데, 위에서 client -> controller 로 요청할 때, 그 요청을 처리할 메서드 하나(전처리기)와 controller -> client 로 응답할 때, 그 요청을 처리할 메서드 하나(후처리기)를 만들 예정이다. 

package hmg.comm.logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LoggerInterceptor extends HandlerInterceptorAdapter {
	protected Logger log = LoggerFactory.getLogger(LoggerInterceptor.class);

	// 전처리기 (Client -> Controller(Dispatcher) 요청 시 처리 작업)
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("====================================== START ======================================");
			log.debug(" Request URI \t: " + request.getRequestURI());
		}
		return super.preHandle(request, response, handler);
	}

	// 후처리기 (Controller(Dispatcher) -> Client 요청 시 처리 작업)
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("====================================== END ======================================\n");
		}
	}
}

 

방금 만든 인터셉터를 등록한다.

 action-servlet.xml 다음으로 수정

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

	<!-- base-package는 자신의 상위패키지명으로 변경 -->
	<context:component-scan base-package="hmg"></context:component-scan>
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
            <!-- class는 자신의 상위패키지명으로 변경 -->
			<bean id="loggerInterceptor"
				class="hmg.comm.logger.LoggerInterceptor"></bean>
		</mvc:interceptor>
	</mvc:interceptors>
	<bean
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
	<bean
		class="org.springframework.web.servlet.view.BeanNameViewResolver"
		p:order="0" />
		
	<bean id="jsonView"
		class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />	
	<bean
		class="org.springframework.web.servlet.view.UrlBasedViewResolver"
		p:order="1"
		p:viewClass="org.springframework.web.servlet.view.JstlView"
		p:prefix="/WEB-INF/jsp/" p:suffix=".jsp">
	</bean>
</beans>

 

스프링 3.2 이상에서는 mvc를 설정하는게 많이 바뀌었다. 

<mvc:mapping path/>를 통해서 인터셉터가 동작할 URL을 지정할 수 있다. 지금 작성하는 로거는 모든 요청에서 동작을 하기때문에 전체 패스를 의미하는 "/**" 로 설정하였다.

그 후, bean을 수동으로 등록한다.

 

중요!!! 위에서 이야기 했듯이, Interceptor는 Controller가 요청되기 전에 수행된다. 즉, Interceptor는 DispatcherServlet과 같은 위치에 등록이 되어있어야지 정상적으로 수행이 된다. 

 

사진출처 :  http://egloos.zum.com/springmvc/v/504151

DispatcherServlet은 사용자(클라이언트)의 요청을 받아서 해당 요청에 매핑되는 컨트롤러와 연결한 후, 컨트롤러에서 정의된 view를 사용자의 브라우저에 출력하는 역할을 수행한다.

web.xml을 다시한번 살펴보자.

 

	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class> org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value> /WEB-INF/config/*-servlet.xml </param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

우리는 여기서 이미 DispatcherServlet을 정의하였다. 그리고 그 DispatcherServlet의 설정파일의 위치는 /WEB-INF/config/ 폴더 밑의 -servlet.xml 로 끝나는 모든 xml 파일이라고 명시한 것이다.

 

즉, action-servlet.xml에 interceptor를 설정함으로써, 우리는 DispatcherServlet과 Interceptor를 같은 위치에 등록을 한것이다. 

만약, action-servlet에서 Interceptor의 설정을 분리하여 다른 파일로 만들고싶으면, action-servlet.xml이 있는 폴더에 *-servlet.xml의 이름 형식 (예를 들어 interceptor-servlet.xml )으로 만들면 된다. 


 이제 인터셉터가 제대로 동작하는지 확인하자.

- src/main/java/hmg 밑에 sample.controller 패키지를 만든다.
controller 패키지에 SampleController 클래스를 생성하고 다음 소스 입력

package hmg.sample.controller;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class SampleController {
	Logger log = LoggerFactory.getLogger(this.getClass());
	@RequestMapping(value = "/sample/openSampleList.do")
	public ModelAndView openSampleList(Map<String, Object> commandMap) throws Exception {
		ModelAndView mv = new ModelAndView("");
		log.debug("인터셉터 테스트");
		return mv;
	}
}

 

index.jsp 변경, /sample/openSampleList.do 호출하도록 변경

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"%>
<jsp:forward page="/sample/openSampleList.do" />

-  서버실행 후 http://localhost:8080/"프로젝트명"/ 접속

  eclipse에 다음과 같은 로그 찍히는지 확인

2019-07-13 01:32:55,000 DEBUG [hmg.comm.logger.LoggerInterceptor] ====================================== START ======================================
2019-07-13 01:32:55,001 DEBUG [hmg.comm.logger.LoggerInterceptor]  Request URI 	: /hmgWebapp/sample/openSampleList.do
2019-07-13 01:32:55,020 DEBUG [hmg.sample.controller.SampleController] 인터셉터 테스트
2019-07-13 01:32:55,021 DEBUG [hmg.comm.logger.LoggerInterceptor] ====================================== END ======================================

 

 


출처: https://addio3305.tistory.com/39?category=772645 [흔한 개발자의 개발 노트]

댓글