http://static.springframework.org/spring/articles/2005/MVC-step-by-step/Spring-MVC-step-by-step.html

<div class="note"> part4까지 구성이 되어있는 문서.. 현재 대략 part2까지 작업. </div>

Developing a Spring Framework MVC application step-by-step#

Part 1 - Basic Application and Environment Setup#

Thomas Risberg July, 2003

(Revised April, 2005)

이 문서에서 Spring MVC를 사용해서 웹 애플리케이션을 개발하는 방법에 대해서 단계적으로 알아본다.

필수조건:

  1. Java SDK (I am currently using version 1.4.2)
  2. Ant (using version 1.6.2)
  3. Apache Tomcat (using version 5.0.28)

1 단계 - 개발 디렉토리

springapp라는 이름의 디렉토리를 만든다. 하위로 src와 war디렉토리를 생성하는데 src디렉토리엔 자바소스가 위치하고 war디렉토리에는 JSP같은 자바소스를 제외한 모든 소스파일이 위치한다.

2 단계 - index.jsp

war디렉토리에 index.jsp를 생성한다. 즉 위치는 다음과 같다.

springapp/war/index.jsp

<html>
<head><title>Example :: Spring Application</title></head>
<body>
<h1>Example - Spring Application</h1>
<p>This is my test.</p>
</body>
</html>
완벽한 웹애플리케이션을 위해 war디렉토리 하위의 WEB-INF 디렉토리에 web.xml을 생성한다.

springapp/war/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'>

<web-app>

</web-app>

3 단계 - 톰캣으로 애플리케이션 배치하기

애플리케이션을 빌드하고 배치하는 ant스크립트를 생성한다.

springapp/build.xml

<?xml version="1.0"?>

<project name="springapp" basedir="." default="usage">
    <property file="build.properties"/>

    <property name="src.dir" value="src"/>
    <property name="web.dir" value="war"/>
    <property name="build.dir" value="${web.dir}/WEB-INF/classes"/>
    <property name="name" value="springapp"/>

    <path id="master-classpath">
        <fileset dir="${web.dir}/WEB-INF/lib">
            <include name="*.jar"/>
        </fileset>
        <!-- We need the servlet API classes:        -->
        <!--   for Tomcat 4.1 use servlet.jar        -->
        <!--   for Tomcat 5.0 use servlet-api.jar    -->
        <!--   for Other app server - check the docs -->
        <fileset dir="${appserver.home}/common/lib">
            <include name="servlet*.jar"/>
        </fileset>
        <pathelement path="${build.dir}"/>
    </path>

    <target name="usage">
        <echo message=""/>
        <echo message="${name} build file"/>
        <echo message="-----------------------------------"/>
        <echo message=""/>
        <echo message="Available targets are:"/>
        <echo message=""/>
        <echo message="build     --> Build the application"/>
        <echo message="deploy    --> Deploy application as directory"/>
        <echo message="deploywar --> Deploy application as a WAR file"/>
        <echo message="install   --> Install application in Tomcat"/>
        <echo message="reload    --> Reload application in Tomcat"/>
        <echo message="start     --> Start Tomcat application"/>
        <echo message="stop      --> Stop Tomcat application"/>
        <echo message="list      --> List Tomcat applications"/>
        <echo message=""/>
    </target>

    <target name="build" description="Compile main source tree java files">
        <mkdir dir="${build.dir}"/>
        <javac destdir="${build.dir}" target="1.3" debug="true"
               deprecation="false" optimize="false" failonerror="true">
            <src path="${src.dir}"/>
            <classpath refid="master-classpath"/>
        </javac>
    </target>

    <target name="deploy" depends="build" description="Deploy application">
        <copy todir="${deploy.path}/${name}" preservelastmodified="true">
            <fileset dir="${web.dir}">
                <include name="**/*.*"/>
            </fileset>
        </copy>
    </target>

    <target name="deploywar" depends="build" description="Deploy application as a WAR file">
        <war destfile="${name}.war"
             webxml="${web.dir}/WEB-INF/web.xml">
            <fileset dir="${web.dir}">
                <include name="**/*.*"/>
            </fileset>
        </war>
        <copy todir="${deploy.path}" preservelastmodified="true">
            <fileset dir=".">
                <include name="*.war"/>
            </fileset>
        </copy>
    </target>

<!-- ============================================================== -->
<!-- Tomcat tasks - remove these if you don't have Tomcat installed -->
<!-- ============================================================== -->

    <taskdef name="install" classname="org.apache.catalina.ant.InstallTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="list" classname="org.apache.catalina.ant.ListTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="start" classname="org.apache.catalina.ant.StartTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>
    <taskdef name="stop" classname="org.apache.catalina.ant.StopTask">
        <classpath>
            <path location="${appserver.home}/server/lib/catalina-ant.jar"/>
        </classpath>
    </taskdef>

    <target name="install" description="Install application in Tomcat">
        <install url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"
                 war="${name}"/>
    </target>

    <target name="reload" description="Reload application in Tomcat">
        <reload url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"/>
    </target>

    <target name="start" description="Start Tomcat application">
        <start url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"/>
    </target>

    <target name="stop" description="Stop Tomcat application">
        <stop url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"
                 path="/${name}"/>
    </target>

    <target name="list" description="List Tomcat applications">
        <list url="${tomcat.manager.url}"
                 username="${tomcat.manager.username}"
                 password="${tomcat.manager.password}"/>
    </target>

<!-- End Tomcat tasks -->

</project>

이 스크립트는 우리의 개발을 좀더 쉽게 할 필요가 있는 모든 타겟을 포함한다. 당신은 위 빌드파일을 개발 디렉토리의 가장 상위에 둘수 있다. 우리는 당신의 서버설치에 적합하도록 커스터마이징 하는 build.properties파일이 필요할수도 있다. 그 파일은 build.xml파일과 같은 위치에 있어야 한다.

springapp/build.properties

# Ant properties for building the springapp

appserver.home=${user.home}/jakarta-tomcat-5.0.28
deploy.path=${appserver.home}/webapps

tomcat.manager.url=http://localhost:8080/manager
tomcat.manager.username=admin
tomcat.manager.password=tomcat

Ant스크립트를 실행한다.

[trisberg@localhost springapp]$ ant
Buildfile: build.xml
 
usage:
 
     [echospringapp build file
     [echo-----------------------------------
 
     [echoAvailable targets are:
 
     [echobuild     --> Build the application
     [echodeploy    --> Deploy application as directory
     [echodeploywar --> Deploy application as a WAR file
     [echoinstall   --> Install application in Tomcat
     [echoreload    --> Reload application in Tomcat
     [echostart     --> Start Tomcat application
     [echostop      --> Stop Tomcat application
     [echolist      --> List Tomcat applications
 
 
BUILD SUCCESSFUL
Total time: seconds

마지막으로 할 것은 실제 배치과정이다. deploy나 deploywar라는 값의 target을 지정해서 Ant스크립트를 실행하라.

[trisberg@localhost springapp]$ ant deploy
Buildfile: build.xml
 
build:
    [mkdirCreated dir: /Users/trisberg/projects/springapp/war/WEB-INF/classes

deploy:
     [copyCopying files to /Users/trisberg/jakarta-tomcat-5.0.28/webapps/springapp

BUILD SUCCESSFUL
Total time: seconds

4 단계 - 애플리케이션 테스트하기

애플리케이션을 확인하기 위해 톰캣을 시작하자. 만약 톰캣이 새로운 애플리케이션을 가져가는지 보기 위해 빌드파일에서 "list" 작업을 사용하자.

[trisberg@localhost springapp]$ ant list
Buildfile: build.xml
 
list:
     [listOK - Listed applications for virtual host localhost

     [list/admin:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/server/webapps/admin

     [list/webdav:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/webdav

     [list/servlets-examples:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/servlets-examples

     [list/springapp:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/springapp

     [list/jsp-examples:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/jsp-examples

     [list/balancer:running:0:balancer

     [list/tomcat-docs:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/tomcat-docs

     [list/:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/webapps/ROOT

     [list/manager:running:0:/Users/trisberg/jakarta-tomcat-5.0.28/server/webapps/manager
 
 
BUILD SUCCESSFUL
Total time: second

위처럼 되지 않는다면 톰캣내에서 설치하기 위해 "install" 작업을 사용하자.

[trisberg@localhost springapp]$ ant install
Buildfile: build.xml
 
install:
  [installOK - Installed application at context path /springapp
 
 
BUILD SUCCESSFUL
Total time: seconds

브라우저를 열어서 다음 주소를 확인해보자.

http://localhost:8080/springapp/index.jsp

SpringMVC1.png

5 단계 - Spring배포판 다운로드하기

다운로드한 Spring 프레임워크 릴리즈 파일이 없다면 spring-framework-1.2.zip과 spring-framework-1.2-with-dependencies.zip 이름의 파일을 다운로드 받는다.

6 단계 - WEB-INF디렉토리의 web.xml파일 변경하기

모든 요청에 대한 제어를 담당하는 DispatcherServlet과 서블릿 맵핑을 설정한다.

springapp/war/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'>

<web-app>

  <servlet>
    <servlet-name>springapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

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

</web-app>

WEB-INF디렉토리밑에 springapp-servlet.xml파일을 생성한다. 이것은 DispatcherServlet에 의해 사용되는 정의들이 있는 파일이다. 이 파일이름은 web.xml파일내 servlet-name값에 기반해서 -servlet접미사를 사용한다.

springapp/war/WEB-INF/springapp-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<!--
  - Application context definition for "springapp" DispatcherServlet.
  -->

<beans>
    <bean id="springappController" class="SpringappController"/>

    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.htm">springappController</prop>
            </props>
        </property>
    </bean>
</beans>

7 단계 - WEB-INF/lib 디렉토리밑에 jar파일들을 복사

WEB-INF디렉토리밑에 lib디렉토리를 생성한다. spring.jar, commons-logging.jar, log4j-1.2.9.jar 파일들을 lib디렉토리밑에 복사한다.

8 단계 - 컨트롤러 생성하기

src디렉토리밑에 SpringappController.java파일을 생성한다.

springapp/src/SpringappController.java

import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;

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

import java.io.IOException;

public class SpringappController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        return new ModelAndView("");
    }
}

이것은 당신이 사용할수 있는 기본 컨트롤러이다.

9 단계 - 애플리케이션 빌드하기

build.xml에서 "build"작업을 실행한다. 아마 코드는 완벽하게 컴파일될것이다.

[trisberg@localhost springapp]$ ant build
Buildfile: build.xml
 
build:
    [javacCompiling source file to /Users/trisberg/projects/springapp/war/WEB-INF/classes
 
BUILD SUCCESSFUL
Total time: seconds

10 단계 - log4j.properties복사하고 변경하기

Spring프레임워크는 log4j를 사용한다. log4j속성파일(spring-framework-1.2/samples/petclinic/war/WEB-INF/log4j.properties)을 war/WEB-INF/classes밑으로 복사하자.

springapp/war/WEB-INF/classes/log4j.properties

# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
log4j.rootLogger=INFO, stdout, logfile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c- <%m>%n

log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=/Users/trisberg/jakarta-tomcat-5.0.28/logs/springapp.log
log4j.appender.logfile.MaxFileSize=512KB
# Keep three backup files.
log4j.appender.logfile.MaxBackupIndex=3
# Pattern to output: date priority [category- message
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c- %m%n

11 단계 - 애플리케이션 배치하기

build.xml에서 "deploy"작업을 수행하고 나서 "stop"와 "start"작업을 수행한다. 이것은 애플리케이션을 다시 강제로 리로드한다.

(/Users/trisberg/jakarta-tomcat-5.0.28/logs/springapp.log)

2005-04-24 14:58:18,112 INFO [org.springframework.web.servlet.DispatcherServlet- Initializing servlet 'springapp'
2005-04-24 14:58:18,261 INFO [org.springframework.web.servlet.DispatcherServlet- FrameworkServlet 'springapp': initialization started
2005-04-24 14:58:18,373 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader- Loading XML bean definitions from ServletContext resource [/WEB-INF/springapp-servlet.xml]
2005-04-24 14:58:18,498 INFO [org.springframework.web.context.support.XmlWebApplicationContext- Bean factory for application context [WebApplicationContext for namespace 'springapp-servlet']: org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [springappController,urlMapping]; root of BeanFactory hierarchy
2005-04-24 14:58:18,505 INFO [org.springframework.web.context.support.XmlWebApplicationContextbeans defined in application context [WebApplicationContext for namespace 'springapp-servlet']
2005-04-24 14:58:18,523 INFO [org.springframework.core.CollectionFactory- JDK 1.4+ collections available
2005-04-24 14:58:18,524 INFO [org.springframework.core.CollectionFactory- Commons Collections 3.x available
2005-04-24 14:58:18,537 INFO [org.springframework.web.context.support.XmlWebApplicationContext- Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@8dacb]
2005-04-24 14:58:18,539 INFO [org.springframework.web.context.support.XmlWebApplicationContext- Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@5674a4]
2005-04-24 14:58:18,549 INFO [org.springframework.ui.context.support.UiApplicationContextUtils- No ThemeSource found for [WebApplicationContext for namespace 'springapp-servlet']: using ResourceBundleThemeSource
2005-04-24 14:58:18,556 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory- Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [springappController,urlMapping]; root of BeanFactory hierarchy]
2005-04-24 14:58:18,557 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory- Creating shared instance of singleton bean 'springappController'
2005-04-24 14:58:18,603 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory- Creating shared instance of singleton bean 'urlMapping'
2005-04-24 14:58:18,667 INFO [org.springframework.web.servlet.DispatcherServlet- Using context class [org.springframework.web.context.support.XmlWebApplicationContextfor servlet 'springapp'
2005-04-24 14:58:18,668 INFO [org.springframework.web.servlet.DispatcherServlet- Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided
2005-04-24 14:58:18,670 INFO [org.springframework.web.servlet.DispatcherServlet- Unable to locate LocaleResolver with name 'localeResolver': using default [org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@318309]
2005-04-24 14:58:18,675 INFO [org.springframework.web.servlet.DispatcherServlet- Unable to locate ThemeResolver with name 'themeResolver': using default [org.springframework.web.servlet.theme.FixedThemeResolver@c11e94]
2005-04-24 14:58:18,681 INFO [org.springframework.web.servlet.DispatcherServlet- No HandlerAdapters found in servlet 'springapp': using default
2005-04-24 14:58:18,700 INFO [org.springframework.web.servlet.DispatcherServlet- No ViewResolvers found in servlet 'springapp': using default
2005-04-24 14:58:18,700 INFO [org.springframework.web.servlet.DispatcherServlet- FrameworkServlet 'springapp': initialization completed in 439 ms
2005-04-24 14:58:18,704 INFO [org.springframework.web.servlet.DispatcherServlet- Servlet 'springapp' configured successfully

12 단계 - 뷰 생성하기

이제 처음으로 뷰를 생성할것이다. hello.jsp파일을 생성하자.

springapp/war/hello.jsp

<html>
<head><title>Example :: Spring Application</title></head>
<body>
<h1>Hello - Spring Application</h1>
<p>Greetings.</p>
</body>
</html>

이 뷰를 포워드하기 위해 SpringappController를 변경하자.

springapp/src/SpringappController.java

import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;

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

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SpringappController implements Controller {

    /** Logger for this class and subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        logger.info("SpringappController - returning hello view");

        return new ModelAndView("hello.jsp");
    }
}

브라우저에서 다음주소를 보자. http://localhost:8080/springapp/hello.htm

SpringMVC2.png

우리는 로그를 확인할수 있다. (/Users/trisberg/jakarta-tomcat-5.0.28/logs/springapp.log)

2005-04-24 15:01:56,217 INFO [org.springframework.web.servlet.DispatcherServlet- FrameworkServlet 'springapp': initialization completed in 372 ms
2005-04-24 15:01:56,217 INFO [org.springframework.web.servlet.DispatcherServlet- Servlet 'springapp' configured successfully
2005-04-24 15:03:57,908 INFO [SpringappController- SpringappController - returning hello view

13 단계 - index.jsp개선하기

우리는 JSTL을 사용할것이다. WEB-INF/lib디렉토리밑에 필요한 파일(jstl.jar, standard.jar)을 복사하자. include.jsp파일을 생성해서 헤더정보만 넣는다.

springapp/war/WEB-INF/jsp/include.jsp

<%page session="false"%>

<%taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>        

우리의 컨트롤러로 리다이렉트를 하기 위해 <c:redirect>태그를 사용한다. 이것은 index.jsp를 우리의 애플리케이션 프레임워크를 묶는다.

springapp/war/index.jsp

<%include file="/WEB-INF/jsp/include.jsp" %>

<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
<c:redirect url="/hello.htm"/>

14 단계 - 뷰와 컨트롤러 개선하기

JSTL <c:out> 태그를 사용해서 오늘 날짜와 시각을 화면에 표시한다.

springapp/war/WEB-INF/jsp/hello.jsp

<%include file="/WEB-INF/jsp/include.jsp" %>

<html>
<head><title>Hello :: Spring Application</title></head>
<body>
<h1>Hello - Spring Application</h1>
<p>Greetings, it is now <c:out value="${now}"/>
</p>
</body>
</html>

springapp/src/SpringappController.java

import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;

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

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SpringappController implements Controller {

    /** Logger for this class and subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String now = (new java.util.Date()).toString()
        logger.info("returning hello view with " + now);

        return new ModelAndView("WEB-INF/jsp/hello.jsp""now", now);
    }
}

http://localhost:8080/springapp는 hello.htm으로 리다이렉트된다.

15 단계 - 뷰와 컨트롤러 분리하기

springapp/war/WEB-INF/springapp-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<!--
  - Application context definition for "springapp" DispatcherServlet.
  -->

<beans>
    <bean id="springappController" class="SpringappController"/>

    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.htm">springappController</prop>
            </props>
        </property>
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
        <property name="prefix"><value>/WEB-INF/jsp/</value></property>
        <property name="suffix"><value>.jsp</value></property>
    </bean>
</beans>        

지금 컨트롤러내 뷰이름으로 부터 접두사, 접미사를 제거할수 있다.

springapp/src/SpringappController.java

import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;

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

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SpringappController implements Controller {

    /** Logger for this class and subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String now = (new java.util.Date()).toString();
        logger.info("returning hello view with " + now);

        return new ModelAndView("hello""now", now);
    }
}

컴파일하고 배치하고 애플리케이션은 여전히 작동할것이다.

16 단계 - 비지니스 로직을 위해 몇몇 클래스를 추가하기

So far our application is not very useful. I would like to add a little bit of business logic in form of a Product class and a class that will manage all the products. I name this management class ProductManager. In order to separate the web dependent logic from the business logic I will create two separate packages for the Java source - web and bus. If this was an application for a real company I would name the packages something like com.mycompany.web and com.mycompany.bus, but since this is just a demo application I will keep the package names real short. The Product class is implemented as a JavaBean - it has the default constructor (automatically provided if we don't specify any constructors) and getters and setters for the two instance variables description and price. I also make it Serializable, not necessary for our application, but could come in handy later on if we have to pass this class between different application layers.

springapp/src/bus/Product.java

package bus;

import java.io.Serializable;

public class Product implements Serializable {

    private String description;
    private Double price;

    public void setDescription(String s) {
        description = s;
    }

    public String getDescription() {
        return description;
    }

    public void setPrice(Double d) {
        price = d;
    }

    public Double getPrice() {
        return price;
    }

}

The ProductManager holds a List of Products, and again this this class is implemented as a JavaBean.

springapp/src/bus/ProductManager.java

package bus;

import java.io.Serializable;
import java.util.List;

public class ProductManager implements Serializable {

    private List products;

    public void setProducts(List p) {
        products = p;
    }

    public List getProducts() {
        return products;
    }

}

Next, I modify the SpringappController to hold a reference to this ProductManager class. As you can see, it is now in a separate package called web - remember to move the source to this new location. I also add code to have the controller pass some product information to the view. The getModelAndView now returns a Map with both the date and time and the product manager reference.

springapp/src/web/SpringappController.java

package web;

import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;

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

import java.io.IOException;
import java.util.Map;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import bus.Product;
import bus.ProductManager;

public class SpringappController implements Controller {

    /** Logger for this class and subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    private ProductManager prodMan;

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String now = (new java.util.Date()).toString();
        logger.info("returning hello view with " + now);

        Map myModel = new HashMap();
        myModel.put("now", now);
        myModel.put("products", getProductManager().getProducts());

        return new ModelAndView("hello""model", myModel);
    }

    public void setProductManager(ProductManager pm) {
        prodMan = pm;
    }

    public ProductManager getProductManager() {
        return prodMan;
    }
}

17 단계 - 비지니스 데이터를 보여주기 위한 뷰를 변경하고 메시지 묶음을 위한 지원을 추가하자

Using the JSTL <c:forEach> tag, I add a section that displays product information. I have also replaced the title, heading and greeting text with a JSTL <fmt:message> tag that pulls the text to display from a provided 'message' source - I will show this source in a later step.

springapp/war/WEB-INF/jsp/hello.jsp

<%include file="/WEB-INF/jsp/include.jsp" %>

<html>
<head><title><fmt:message key="title"/></title></head>
<body>
<h1><fmt:message key="heading"/></h1>
<p><fmt:message key="greeting"/> <c:out value="${model.now}"/>
</p>
<h3>Products</h3>
<c:forEach items="${model.products}" var="prod">
  <c:out value="${prod.description}"/> <i>$<c:out value="${prod.price}"/></i><br><br>
</c:forEach>
</body>
</html>

18 단계 - 몇몇 비지니스 객체를 자동으로 활성화시키기 위해 몇몇 테스트 데이터를 추가하기

I am not going to add any code to load the business objects from a database just yet. Instead, we can “wire up” a couple of instances using Spring's bean and application context support. I will simply put the data I need as a couple of bean entries in springapp-servlet.xml. I will also add the messageSource entry that will pull in the messages resource bundle ('messages.properties') that I will create in the next step.

springapp/war/WEB-INF/springapp-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<!--
  - Application context definition for "springapp" DispatcherServlet.
  -->


<beans>
    <bean id="springappController" class="web.SpringappController">
        <property name="productManager">
            <ref bean="prodMan"/>
        </property>
    </bean>

    <bean id="prodMan" class="bus.ProductManager">
        <property name="products">
            <list>
                <ref bean="product1"/>
                <ref bean="product2"/>
                <ref bean="product3"/>
            </list>
        </property>
    </bean>

    <bean id="product1" class="bus.Product">
        <property name="description"><value>Lamp</value></property>
        <property name="price"><value>5.75</value></property>
    </bean>
        
    <bean id="product2" class="bus.Product">
        <property name="description"><value>Table</value></property>
        <property name="price"><value>75.25</value></property>
    </bean>

    <bean id="product3" class="bus.Product">
        <property name="description"><value>Chair</value></property>
        <property name="price"><value>22.79</value></property>
    </bean>

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename"><value>messages</value></property>
    </bean>

    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.htm">springappController</prop>
            </props>
        </property>
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
        <property name="prefix"><value>/WEB-INF/jsp/</value></property>
        <property name="suffix"><value>.jsp</value></property>
    </bean>
</beans>        

19 단계 - 메시지 묶음을 추가하고 build.xml에 "clean"타겟을 추가하기

I create a 'messages.properties' file in the war/WEB-INF/classes directory. This properties bundle so far has three entries matching the keys specified in the <fmt:message> tags that we added to the hello.jsp.

springapp/war/WEB-INF/classes/messages.properties

title=SpringApp
heading=Hello :: SpringApp
greeting=Greetings, it is now

Since we moved some source files around, it makes sense to add a 'clean' and an 'undeploy' target to the build scripts. I add the following entries to the build.xml file.

    <target name="clean" description="Clean output directories">
        <delete>
            <fileset dir="${build.dir}">
                <include name="**/*.class"/>
            </fileset>
        </delete>
    </target>

    <target name="undeploy" description="Un-Deploy application">
        <delete>
            <fileset dir="${deploy.path}/${name}">
                <include name="**/*.*"/>
            </fileset>
        </delete>
    </target>

Now stop the Tomcat server, run the clean, undeploy and deploy targets. This should remove all old class files, re-build the application and deploy it. Start up Tomcat again and you should see the following:

Add new attachment

Only authorized users are allowed to upload new attachments.

List of attachments

Kind Attachment Name Size Version Date Modified Author Change note
png
SpringMVC1.png 30.2 kB 1 06-Apr-2006 09:45 61.83.100.237
png
SpringMVC2.png 29.0 kB 1 06-Apr-2006 09:45 61.83.100.237
htm
환선굴.htm 28.9 kB 1 29-Jul-2006 22:01 211.209.15.66
pdf
흥덕지구토지이용계획도[1].pdf 963.1 kB 1 29-Jul-2006 22:00 211.209.15.66
« This page (revision-1) was last changed on 06-Apr-2006 09:45 by UnknownAuthor