Цель

 Создать простое приложение на технологии Spring MVC

Что требуется для начала
  1. Установленная JDK 6+,
  2. Maven 2
  3. Настроенные переменные окружения: JAVA_HOME=<путь к JDK>, M2_HOME=путь к мавен, PATH=JAVA_HOME\bin;M2_HOME\bin;%PATH%;
  4. Среда разработки, например IntelliJ Idea 11 Ultimate (в Community будет не так удобно работать с Spring и JSP)

 

 

Шаг 1: Создание maven проекта

Создайте новую директорию для проекта, например project и выполните команду:

mvn archetype:generate -DgroupId=ru.mai.dep806.mvcapp -DartifactId=webapp -Dversion=1.0-SNAPSHOT -Dpackage=ru.mai.dep806.mvcapp -DarchetypeArtifactId=maven-archetype-webapp -B

Названия groupId, artifactId, version и package можно заменить, если проект будет называться по-другому. Но слово webapp в имени лучше оставить на случай если в проект добавятся другие модули в той же папке project рядом с webapp.

C:\...06\Autumn2012\Java8\7 - Spring MVC\project>pp -DarchetypeArtifactId=maven-archetype-webapp -B
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO] task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: ru.mai.dep806.mvcapp
[INFO] Parameter: packageName, Value: ru.mai.dep806.mvcapp
[INFO] Parameter: package, Value: ru.mai.dep806.mvcapp
[INFO] Parameter: artifactId, Value: webapp
[INFO] Parameter: basedir, Value: C:\Private\Dep806\Autumn2012\Java8\7 - Spring MVC\project
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: C:\Private\Dep806\Autumn2012\Java8\7 - Spring MVC\project\webapp
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9 seconds
[INFO] Finished at: Sat Oct 20 02:12:25 MSD 2012
[INFO] Final Memory: 18M/33M
[INFO] ------------------------------------------------------------------------

Теперь можно открыть проект в среде разработки, обычно надо выбрать New Project -> Import from External Model -> Maven

 

 

Шаг 2: Добавление библиотек Spring в проект

В pom.xml в раздел <dependencies> добавьте следующие зависимости:

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId>
 <version>3.1.2.RELEASE</version>
</dependency>

Если среда разработки автоматически подхватывает изменения в maven проектах (см. настройку на скриншоте выше), то должно пройти некоторое время, пока мавен выкачает указанные и все зависимые от них библиотеки с исходниками, после чего IDE их проиндексирует для быстрого поиска. Подождите пока процесс завершится.

Также стоит сразу добавить конфигурацию плагина-компилятора в секцию <build> </build> для того, чтобы указать версию языка java, которую мы будем использовать. Даже если вы используете самую новую jdk 7, версия языка по умолчанию стоит 1.3, а на 1.6.

 <plugins>
    <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <version>2.5.1</version>
       <configuration>
          <source>1.6</source>
          <target>1.6</target>
       </configuration>
    </plugin>
 </plugins>

 

Шаг 3: Добавление диспетчера Spring MVC

Для того, чтобы Spring MVC мог обрабатывать HTTP запросы, нужно прописать сервлет-диспетчер. Откройте web.xml и добавьте следующие строки в <web-app>:

<servlet>
   <servlet-name>action</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>action</servlet-name>
   <url-pattern>*.html</url-pattern>
</servlet-mapping>

Название сервлета может быть произвольное, но должно совпадать в обеих секциях, а также в имени spring-файла на следующем шаге. Все запросы пользователя, которые будет обрабатывать наше MVC приложение должны удовлетворять url-pattern. Т.е. его лучше выбрать в самом начале (например, *.do или *.action или /app/*), иначе придется потом менять ссылки по всему приложению. 

 

Шаг 4: Создание action-servlet.xml 

Корнем конфигурации Spring MVC является файл спринг-контекста, название которого по-умолчанию принимается <имя сервлета-диспетчера>-servlet.xml

В нашем случае - это action-servlet.xml, который требуется положить в WEB-INF

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 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">

    <context:component-scan base-package="ru.mai.dep806.mvcapp.controllers"/>

</beans>

Основной смысловой строкой тут является <context:component-scan/> - тег, который говорит "собери все Spring-бины в пакете ru.mai.dep806.mvcapp.controllers". Забегая вперед, Spring-бинами являются обычные классы, помеченные Spring-аннотациями. В нашем случае это будут контроллеры, но вообще могут быть и любые другие бины реализующие произвольную логику.

 

Шаг 5: Создание пакетов общей структуры проекта

Подсвечивая красным имя пакета, IDE нам указывает что такого пакета в проекте нет. Значит нужно его создать. Мало того, у нас в проекте даже нет папки, где должны лежать исходники. Для этого мы в папке main создаем подпапку java. Также заодно можно создать src/test/java и src/test/resources для будущих тестов и тестовых ресурсов. Но IDE пока не знает о назначении этих папок, нужно либо сделать вид, что мы изменили pom.xml (добавив пустую строку), либо сделать Reimport All Maven Projects в правой панели Maven. После этого новые папки окрасятся в синий и зеленый цвета, что означает что среда поняла их назначение (по-умолчанию, в мавене исходники и тесты лежат именно по этим путям).

Дальше, в контекстном меню папки src/main/java, выбрав new package создадим пакет ru.mai.dep806.mvcapp.controllers

 

(lightbulb)Замечание для Idea: по-умолчанию пустые пакеты отображаются в дереве одной строкой компактно, если требуется их развернуть, например, для создания подпакета в середине пути, снимите флаг Compact empty middle package в меню над деревом)

Шаг 6: Добавление контроллера для главной страницы

Наконец то мы можем создать первый класс-контроллер  WelcomeController (в пакете controllers):

package ru.mai.dep806.mvcapp.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Контроллер для главной страницы приложения.
 */
@Controller
public class WelcomeController {

 private int visitorCount = 0;

 @RequestMapping("/index.html")
 public String index(Model model) {
    model.addAttribute("visitorCount", visitorCount++);
    return "WEB-INF/jsp/index.jsp";
 }

}

Аннотация @Controller говорит component-scan что нужно создать спринг-бин из этого класса (поэтому рекомендуется оставлять в нем конструктор по-умолчанию без параметров). Аннотация @RequestMapping говорит, что метод index будет обрабатывать запросы по URL /index.html от корня приложения (если приложение развернуто на сервере под контекстом /mvc то соответственно полный URL будет http://localhost:8080/mvc/index.html). Посмотрите какие другие параметры есть у этой аннотации, также она может принимать wildcards и использовать в качестве пути переменные, значения которых можно получить в параметре метода - фактически можно добиться практически любой сложности URL.

Далее, метод index (название произвольное, главное чтобы он был public) принимает на вход объект модели, которую может заполнить в теле метода, и возвращает String - имя jsp страницы, которая представляет собой view. Забегая вперед, можно сказать что параметры у метода и возвращаемое значение могут быть самые разнообразные, в зависимости от потребностей конкретной логики контроллера. Никакого интерфейса или жесткой модели тут нет.

Все объекты-бины в спринге по-умолчанию являются синглтонами. Т.е. на все приложение создается один единственный экземпляр нашего контроллера, который обрабатывает все запросы, в том числе может и параллельно. Попробуйте предположить какое значение будет у переменной visitorCount после нескольких обращений к index.html. Что есть плохого в реализации этого метода? Как это можно исправить?

 

Шаг 7: Добавление JSP-файла (view) для главной страницы

Теперь пока добавить "лицо" нашего приложения - view для главной страницы. Для этого, создадим папку jsp в WEB-INF и в ней файл index.jsp, чтобы наш контроллер нашел ее по полному пути внутри сервера: WEB-INF/jsp/index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
 <title>Добро пожаловать</title>
</head>
<body>
<h4> Добро пожаловать! </h4>
Поздравляем, вы <b>${visitorCount}</b> посетитель и можете выиграть поездку в столицу Java - Джакарту <br/>

<a href="http://clck.yandex.ru/redir/dtype=stred/pid=7/cid=1228/*http://pogoda.yandex.ru/jakarta"><img src="http://info.weather.yandex.net/jakarta/2.ru.png" border="0" alt=""/><img width="1" height="1" src="http://clck.yandex.ru/click/dtype=stred/pid=7/cid=1227/*http://img.yandex.ru/i/pix.gif" alt="" border="0"/></a>

</body>
</html>

Тут кроме HTML из интересного используется синтаксис Expression Language (EL) - ${visitorCount} для вывода значения переменной модели, которую мы установили в контроллере.

Для того, чтобы можно было использовать EL, необходимо установить флаг isELIgnored="false", который по-умолчанию true для совместимости с предыдущими версиями JSP, где EL не интерпретировался.

 

Шаг 8: Конфигурация проекта для запуска  в Tomcat

Теперь мы можем собрать проект с помощью цели maven package, в результате чего получим файл target/webapp.war готовый к развертыванию на любом сервере приложений или web-контейнере java. Но maven предоставляет возможность запускать встроенный web-контейнер Tomcat, который перед запуском надо сконфигурировать в pom.xml:

 <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat6-maven-plugin</artifactId>
    <version>2.0</version>
 </plugin>

 

Шаг 9: Launch! 

Запускаем проект с помощью команды mvn tomcat6:run (из командной строки или IDE).

C:\Java\jdk1.6.0_10\bin\java -Dclassworlds.conf=C:\Java\apache-maven-2.2.1\bin\m2.conf -Dmaven.home=C:\Java\apache-maven-2.2.1 -Didea.launcher.port=7534 "-Didea.launcher.bin.path=C:\Program Files\JetBrains\IntelliJ IDEA 11.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Java\apache-maven-2.2.1\boot\classworlds-1.1.jar;C:\Program Files\JetBrains\IntelliJ IDEA 11.1.2\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher --no-plugin-registry --fail-fast --strict-checksums --update-snapshots -f "C:\Private\Dep806\Autumn2012\Java8\7 - Spring MVC\project\webapp\pom.xml" org.apache.tomcat.maven:tomcat6-maven-plugin:2.0:run
+ Enabling strict checksum verification on all artifact downloads.
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building webapp Maven Webapp
[INFO] task-segment: [org.apache.tomcat.maven:tomcat6-maven-plugin:2.0:run]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing tomcat6:run
[INFO] [resources:resources {execution: default-resources}]
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [tomcat6:run {execution: default-cli}]
[INFO] Running war on http://localhost:8080/webapp
[INFO] Using existing Tomcat server configuration at C:\Private\Dep806\Autumn2012\Java8\7 - Spring MVC\project\webapp\target\tomcat
20.10.2012 3:38:41 org.apache.catalina.startup.Embedded start
INFO: Starting tomcat server
20.10.2012 3:38:41 org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.35
20.10.2012 3:38:42 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'action'
20.10.2012 3:38:42 org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet 'action': initialization started
20.10.2012 3:38:42 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing WebApplicationContext for namespace 'action-servlet': startup date [Sat Oct 20 03:38:42 MSD 2012]; root of context hierarchy
20.10.2012 3:38:42 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from ServletContext resource [/WEB-INF/action-servlet.xml]
20.10.2012 3:38:42 org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
INFO: JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
20.10.2012 3:38:42 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1891172: defining beans [welcomeController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
20.10.2012 3:38:43 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/index.html] onto handler 'welcomeController'
20.10.2012 3:38:43 org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet 'action': initialization completed in 1390 ms
20.10.2012 3:38:43 org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
20.10.2012 3:38:43 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080

Если все прошло успешно (в логах есть строка  INFO: FrameworkServlet 'action': initialization completed), то можно зайти на страницу по адресу http://localhost/webapp/index.html 

Поздравляем с созданием первого MVC приложения!

2 Comments

  1. Шаг 2

     

    <plugins>
     <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>2.5.1</version>
     <configuration>
     <source>1.6</source>
     <target>1.6</target>
     </configuration>
     </plugin>
     </plugins>
    
    

    Данный кусок кода следует поместить в pom.xml в раздел <build> ... </build>

    1. Исправлено, спасибо!