Pull to refresh

Делаем простое веб приложение на Spring Framework MVC

Reading time 13 min
Views 252K
image
В данной статье я хочу рассказать начинающим Java разработчикам, как написать простое веб приложение, используя популярный фреймворк Spring Framework.

При разрабокте приложения мы будем использовать утилиту Ant для автоматизации действий и изучим, как писать простой тест с помощью библиотеки JUnit. Весь код будем писать в Eclipse IDE.

Статья написана на основе первой части руководства «Introduction to Spring MVC». Вам достаточно иметь лишь общее представление о Spring, чтобы прочитать статью с пользой.

Так что милости просим :)


Для конфигурирования приложения в Spring можно использовать несколько спобов. Наиболее популярный путь – вынесение конфигурации в xml-файлы. Также это наиболее традиционный путь, который используется в фреймворке с первого релиза. С введением аннотаций в языке Java 5 появилась возможность настраивать фреймворк с помощью них (с версии 2.5). В данной статье мы будем использовать традиционный XML-стиль.

Необходимые инструменты


  • Java SDK 1.5,
  • Apache Tomcat 6,
  • Ant 1.7,
  • Junit 4.x,
  • Eclipse 3.

Важное замечание: при копировании кода замените кавычки «елочки» на обыкновенные. Это избавит Ваш код от ошибок :)

1. Создание структуры проекта


На установленный Eclipse поставим плагин Spring IDE. Создадим Spring-проект springapp, добавим папку war.
image

2. Создадим 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'?>
<web-app version='2.4'
    xmlns='java.sun.com/xml/ns/j2ee'
    xmlns:xsi='www.w3.org/2001/XMLSchema-instance'
    xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee
    java.sun.com/xml/ns/j2ee/web-app_2_4.xsd>
    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>


3. Деплоим приложение в Tomcat


Для развертывания приложения на сервере воспользуемся ant-скриптом (для начала работы с 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 5/6 use servlet-api.jar -->
        <!-- * for other app servers - check the docs -->
        <fileset dir='${appserver.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='' />
    </target>
    <target name='build' description='Compile main source tree java files'>
        <mkdir dir='${build.dir}' />
        <javac destdir='${build.dir}' source='1.5' target='1.5' 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>
</project>


springapp/build.properties
# Ant properties for building the springapp
appserver.home=  C:/Program Files/Apache Software Foundation/Tomcat 6.0/

# for Tomcat 5 use $appserver.home}/server/lib
# for Tomcat 6 use $appserver.home}/lib
appserver.lib=${appserver.home}/lib
deploy.path=${appserver.home}/webapps
tomcat.manager.url=http://localhost:8080/manager
tomcat.manager.username=tomcat
tomcat.manager.password=s3cret


Установите корректно переменную appserver.home. У меня она указывает на C:/Program Files/Apache Software Foundation/Tomcat 6.0/.

Для создания пользователя Tomcat в файле appserver.home/conf/tomcat-users.xml сделайте запись:
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
   <role rolename="manager"/>
   <user username="tomcatpassword="s3cretroles="manager"/>
</tomcat-users>


Выполним build-скрипт: Контекстное меню файла build.xml > Run As > Ant Build > Выбрать цели build, deploy во вкладке Targets.

4. Проверим работоспособность приложения


Запустите Tomcat и откройте в браузере страницу localhost:8080/springapp/.
image

5. Скачиваем Spring Framework


Скачайте фреймворк, если вы ещё этого не сделали, и распакуйте его.

На этом настройка окружения закончена. Далее мы приступаем к конфигурированию самого приложения на Spring MVC.

6. Изменим web.xml в папке WEB-INF


Мы определим сервлет-дисптечер DispatcherServlet (также называемый Front Controller). Его цель – диспетчеризация поступающих запросов. Сделаем для этого сервлета маппинг. Мы решили все запросы с урлами вида '.htm' направлять на сервлет-дисптечер.

springapp/war/WEB-INF/web.xml
<?xml version="1.0encoding="UTF-8"?>
<web-app version="2.4xmlns="java.sun.com/xml/ns/j2ee"
    xmlns:xsi="www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="java.sun.com/xml/ns/j2ee
    java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
">
    <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>


Создадим файл springapp-servlet.xml. Этот файл содержит описания бинов (Java-файлов), которые будет использовать DispatcherServlet. Иными словами файл определяет контекст сервлета (WebApplicationContext). По стандартному соглашению именования для Spring Web MVC, сервлет springapp будет иметь файл описания бинов с именем springapp-servlet.xml.

Добавим описание бина (bean entry) '/hello.htm' с классом springapp.web.HelloController. Эта запись определяет Контроллер, который будет использовать приложение для обслуживания запроса с урлом '/hello.htm'. Для маппинга урла на объект, что его будет обрабатывать, фреймворк Spring Web MVC использует класс, реализующий интерфейс HandlerMapping. По умолчанию для маппинга используется класс BeanNameUrlHandlerMapping.

В отличие от DispatcherServlet, HelloController ответственный за обработку запроса на конкретную страницу. Его также называют 'Page Controller'.

springapp/war/WEB-INF/springapp-servlet.xml
<?xml version="1.0" encoding="UTF-8"?><br/>
<beans xmlns="http://www.springframework.org/schema/beans"<br/>
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br/>
	xsi:schemaLocation="http://www.springframework.org/schema/beans<br/>
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><br/>
	<!-- the application context definition for the springapp DispatcherServlet --><br/>
	<bean name="/hello.htm" class="springapp.web.HelloController" /><br/>
</beans>


7. Скопируем библиотеки в 'WEB-INF/lib'


Создадим директорию war/WEB-INF/lib и скопируем в нее необходимые библиотеки Spring:
  • spring.jar (из spring-framework-2.5/dist);
  • spring-webmvc.jar (из spring-framework-2.5/dist/modules);
  • commons-logging.jar (из spring-framework-2.5/lib/jakarta-commons);
  • junit-4.4.jar (из spring-framework-2.5/lib/ junit).


Добавим в Eclipse-проект необходимые библиотеки:
  • Контекстное меню проекта > Build Path > Configure Build Path > Add External JARs > 'war/WEB-INF/lib';
  • Контекстное меню проекта > Build Path > Configure Build Path > Add Library > Server Runtime > Tomcat.


8. Создадим Контроллер


Создадим Контроллер HelloController в пакете springapp.web.

springapp/src/springapp/web/HelloController.java
package springapp.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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;

public class HelloController implements Controller {
    protected final Log logger = LogFactory.getLog(getClass());

    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        logger.info(«Returning hello view»);
        return new ModelAndView(«hello.jsp»);
    }
}


Это очень упрощенная реализация Контроллера. Мы будем её расширять в дальнейшем, и также будем использовать готовые реализации контроллеров из фреймворка.

В модели MVC Контроллер обрабатывает запрос и возвращает Модель-и-Вид (ModelAndView) – в нашем случае страницу 'hello.jsp'. Модель, которую возвращает Контроллер, на самом деле разрешается через ViewResolver. Так как мы не указали явно ViewResolver, то будет использоваться резолвер по-умолчанию, который просто направляет запрос на адрес ресурса, указанный в Модели-и-Виде. В дальнейшем мы это изменим.

Также мы указали логгер, с помощью которого сможем проверить выполненную приложением работу. При использовании Tomcat журнал работы приложения мы сможем просмотреть в файле catalina.out, который можно найти по адресу ${Tomcat.home}/log.

9. Напишем тест для Контроллера


Тестирование – это один из самых важных этапов разработки сложных программных систем. Также это основополагающая практика при Agile software development. Многие считают, что наилучшее время написания тестов – втечение разработки, а не после. Так что, несмотря на простоту разработанного нами контроллера, мы напишем к нему тест.

Создадим тест HelloControllerTests, расширяющий класс TestCase из библиотеки Junit: New > Other > JUnit > JUnit Test Case.

Это модульный тест (unit test). Он проверяет, совпадает ли имя Вида, возвращаемое через handleRequest() с Видом, которое мы ожидаем: 'hello.jsp'.
image

springapp/src/springapp/web/HelloControllerTests.java
package springapp.web;

import org.springframework.web.servlet.ModelAndView;
import springapp.web.HelloController;
import static org.junit.Assert.*;
import org.junit.Test;

public class HelloControllerTests {

    @Test
    public void testHandleRequestView() throws Exception {
        HelloController controller = new HelloController();
        ModelAndView modelAndView = controller.handleRequest(nullnull);
        assertEquals(«hello.jsp», modelAndView.getViewName());
    }
}


Для запуска теста используем меню: Run > Run As > JUnit Test.
Результат выполнения теста:
image

Ещё одной практикой Agile-разработки является непрерывная интеграция (Continuous Integration). Хорошей идеей будет запуск тестов с каждым билдом (build), для того, чтобы быть уверенным в правильном поведении своего кода (в идеальном варианте тесты запускаются автоматически при каждом билде).

10. Создадим Вид


Настало время создать Вид. В нашем случае это будет JSP-страница hello.jsp.

springapp/war/hello.jsp
<html>
    <head>
        <title>Hello :: Spring Application</title>
    </head>
    <body>
        <h1>Hello - Spring Application</h1>
        <p>Greetings.</p>
    </body>
</html>


11. Скомпилируем и развернём приложение на сервере


Для файла build.xml добавим в Classpath библиотеку springapp\war\WEB-INF\lib\junit-4.4.jar, и выполним цели Build и Deploy (Контекстное меню файла build.xml > Run As > Ant Build… > вкладки Targets, Classpath).

12. Попробуем запустить приложение


В браузере наберем адрес http://localhost:8080/springapp/hello.htm.
image

13. Резюме


Давайте бегло просмотрим, что было сделано.
  1. Стартовая страница приложения – index.jsp. Служит для того, чтобы удостовериться в правильности установки окружения. Позднее мы ее изменим.
  2. Сервлет-диспетчер (DispatcherServlet или Front controller) с соответствующим файлом описания springapp-servlet.xml.
  3. Контроллер (Page controller) HelloController с базовой функциональностью – просто возвращает Модель-И-Вид. На данный момент Модель пустая. Полная реализация Модели будет сделана в дальнейшем.
  4. Модульный тест для контроллера HelloControllerTests, проверяющий, соответствует ли имя вида ожидаемому.
  5. Вид приложения – hello.jsp.


Ниже представлена структура проекта, которая должна быть после выполнения всех инструкций.
image

Готовый Eclipse-проект можно скачать здесь.

Спасибо за внимание. Желаю успехов!
Tags:
Hubs:
+30
Comments 81
Comments Comments 81

Articles