Skip to content
wizardjedi edited this page Jun 23, 2013 · 16 revisions

Мы уже использовали Jetty в разделе про Spring MVC как плагин для Maven, а в этом разделе будет рассказано о непосредственно сервере Jetty.

Минимальный репозиторий с зависимостями для Jetty

Создадим минимальный проект maven и добавим зависимости, которые будут использоваться в дальнейшем.

Добавляем не только базовые зависимости, но зависимости, которые будут использованы позднее. Например, чтобы использовать знакомый стек технологий для Web-application, добавим зависимость jetty-webapp. Однако, для действительно минимального приложения это не требуется.

Добавим следующие зависимости:

  • jetty
  • Spring framework
  • jetty-jsp
  • jstl
  • slf4j
  • logback
  • apache tiles

И сконфигурируем плагины для сборки.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.a1systems</groupId>
	<artifactId>base_jetty</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>base_jetty</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<slf4j.version>1.7.5</slf4j.version>
		<logback.version>1.0.13</logback.version>
		<spring.version>3.2.3.RELEASE</spring.version>
		<junit.version>4.11</junit.version>
		<apache.tiles.version>3.0.1</apache.tiles.version>
		<jetty.version>9.0.3.v20130506</jetty.version>
		<jstl.version>1.2</jstl.version>

		<mcp.source.version>1.7</mcp.source.version>
		<mcp.target.version>1.7</mcp.target.version>
		<mcp.version>3.1</mcp.version>

		<maven.dependency.plugin.version>2.5.1</maven.dependency.plugin.version>
		<maven.jar.plugin.version>2.4</maven.jar.plugin.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<!-- logback -->
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
			<version>${logback.version}</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-access</artifactId>
			<version>${logback.version}</version>
		</dependency>

		<!-- SLF4J -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jul-to-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<type>jar</type>
		</dependency>

		<!-- Jetty -->
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-spring</artifactId>
			<version>${jetty.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-server</artifactId>
			<version>${jetty.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-servlet</artifactId>
			<version>${jetty.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-servlets</artifactId>
			<version>${jetty.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-webapp</artifactId>
			<version>${jetty.version}</version>
		</dependency>

		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-deploy</artifactId>
			<version>${jetty.version}</version>
		</dependency>

		<!-- JSP and JSTL SUPPORT -->
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-jsp</artifactId>
			<version>${jetty.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
			<scope>provided</scope>
		</dependency>

		<!-- Spring framework dependency -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
			<exclusions>
				<exclusion>
					<artifactId>commons-logging</artifactId>
					<groupId>commons-logging</groupId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Apache tiles -->
		<dependency>
			<groupId>org.apache.tiles</groupId>
			<artifactId>tiles-core</artifactId>
			<version>${apache.tiles.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.tiles</groupId>
			<artifactId>tiles-jsp</artifactId>
			<version>${apache.tiles.version}</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>${mcp.version}</version>
				<configuration>
					<source>${mcp.source.version}</source>
					<target>${mcp.target.version}</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<archive>
						<addMavenDescriptor>false</addMavenDescriptor>
						<compress>true</compress>
						<manifest>
							<addClasspath>true</addClasspath>
							<classpathPrefix>libs/</classpathPrefix>
							<mainClass>com.a1systems.base_jetty.App</mainClass>
						</manifest>
					</archive>
				</configuration>
				<version>${maven.jar.plugin.version}</version>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<outputDirectory>${project.build.directory}/libs</outputDirectory>
						</configuration>
					</execution>
				</executions>
				<version>${maven.dependency.plugin.version}</version>
			</plugin>
		</plugins>
	</build>
</project>

В проекте уже есть logback.xml с настройкой логирования.

Репозиторий находится по адресу https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_0 ветка pres_0_10_0.

Запуск минимального jetty программно на порту 9090

Теперь запустим jetty программно (без использования Spring). Для запуска jetty необходимо создать объект Server и передать ему в качестве параметра коннектор, отвечающий за принятие подключений. В нашем случае это будет NetworkTrafficSelectChannelConnector.

package com.a1systems.base_jetty;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.NetworkTrafficSelectChannelConnector;

public class App
{
    public static void main( String[] args ) throws Exception
    {
        Server server = new Server();

		NetworkTrafficSelectChannelConnector connector = new NetworkTrafficSelectChannelConnector(server);
		connector.setPort(9090);
		connector.setReuseAddress(true);

		server.setConnectors(new Connector[]{connector});

		server.start();
		server.join();
    }
}

server.start() - запускает сервер, а server.join() ожидает завершения потока web-сервера.

Соберём проект и посмотрим на вывод в браузере.

$ mvn clean compile exec:java -Dexec.mainClass=com.a1systems.base_jetty.App
...
2013-06-22 10:51:57.505 INFO  org.eclipse.jetty.server.Server - jetty-9.0.3.v20130506
2013-06-22 10:51:57.537 INFO  o.e.j.s.n.NetworkTrafficSelectChannelConnector - Started NetworkTrafficSelectChannelConnector@73520584{HTTP/1.1}{0.0.0.0:9090}

И перейдём в браузере по адресу http://127.0.0.1:9090/

jetty screenshot

То есть web-сервер запущен и работает на порту 9090, но нет контента для отображения.

Репозиторий находится по адресу: https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_1 ветка pres_0_10_1

Запуск Spring MVC Webapp из Jetty

Фактически в предыдущем примере мы запустили минимальный jetty. Теперь необходимо добавить поддержку сервлетов. Чтобы использовать уже знакомые технологии, воспользуемся запуском Spring MVC DispatcherServlet в jetty с использованием WebAppContext (фактически jetty будет искать web.xml для настройки сервлетов).

За запуск webapp в jetty отвечает WebAppContext. Настроим объект контекста данного класса:

WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
webAppContext.setResourceBase(Thread.currentThread().getContextClassLoader().getResource("webapp").toExternalForm());

В связи с тем, что в качестве базы для загрузки ресурсов jetty принимает URL, необходимо сделать ряд настроек, чтобы jetty мог получать ресурсы из classpath. Дело осложняется тем, что наш пример может быть запущен и из-под maven, так и как отдельный jar, кроме того мы можем не знать имя jar-файла. В зависимости от типа запуска вызов Thread.currentThread().getContextClassLoader().getResource("webapp").toExternalForm() будет возвращать разные значения:

  • target/classes/webapp - в случае, если запуск через mvn exec:java ...
  • jar:jetty-1.0-SNAPSHOT.jar!/webapp - в случае, если запуск собранного jar-файла

Сам jetty не может определить ресурс, если указать его через classpath:.

После настройки WebAppContext необходимо обернуть его в ряд обработчиков и установить обработчик в jetty.

Server server = new Server();

NetworkTrafficSelectChannelConnector connector = new NetworkTrafficSelectChannelConnector(server);
connector.setPort(9090);
connector.setReuseAddress(true);

server.setConnectors(new Connector[]{connector});

// setup web app
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
webAppContext.setResourceBase(Thread.currentThread().getContextClassLoader().getResource("webapp").toExternalForm());

ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
contextHandlerCollection.addHandler(webAppContext);

HandlerCollection handler = new HandlerCollection();

handler.addHandler(contextHandlerCollection);

server.setHandler(handler);

// Run jetty
server.start();
server.join();

Запустим приложение.

$ mvn clean compile exec:java -Dexec.mainClass=com.a1systems.base_jetty.App
...
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
	at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.NullPointerException
	at com.a1systems.base_jetty.App.main(App.java:25)
	... 6 more

Исключение говорит о том, что на этапе определения пути к ресурсу произошла ошибка. Создадим директорию src/main/resources/webapp/WEB-INF, в которой создадим файл web.xml и снова запустим приложение.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
</root>
$ mvn clean compile exec:java -Dexec.mainClass=com.a1systems.base_jetty.App
...
2013-06-22 11:23:52.655 INFO  org.eclipse.jetty.server.Server - jetty-9.0.3.v20130506
2013-06-22 11:23:52.775 INFO  o.e.j.server.handler.ContextHandler - Started o.e.j.w.WebAppContext@35aa1453{/,file:/home/wiz/TRASH/myspringlearning/target/classes/webapp/,AVAILABLE}
2013-06-22 11:23:52.790 INFO  o.e.j.s.n.NetworkTrafficSelectChannelConnector - Started NetworkTrafficSelectChannelConnector@35d858d9{HTTP/1.1}{0.0.0.0:9090}

Web-сервер запустился. Посмотрим результат в браузере.

jetty screenshot jetty screenshot

Пока в jetty не настроен Spring MVC DispatcherServlet, для этого необходимо внести изменения в web.xml.

Добавим стандартную конфигурацию Sping MVC.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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_3_0.xsd">
	<!-- Main servlet -->
	<servlet>
		<servlet-name>default</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>default</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

Теперь добавим файл webapp/WEB-INF/default-servlet.xml с настройками Spring MVC DispatcherServlet.

<?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:p="http://www.springframework.org/schema/p"
	   xmlns:c="http://www.springframework.org/schema/c"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:task="http://www.springframework.org/schema/task"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xmlns:util="http://www.springframework.org/schema/util"
	   xmlns:security="http://www.springframework.org/schema/security"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/task
			http://www.springframework.org/schema/task/spring-task.xsd
			http://www.springframework.org/schema/tx
			http://www.springframework.org/schema/tx/spring-tx.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/util
			http://www.springframework.org/schema/util/spring-util.xsd
			http://www.springframework.org/schema/security
			http://www.springframework.org/schema/security/spring-security.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
	<mvc:annotation-driven  />

	<context:component-scan base-package="com.a1systems.base_jetty" />

	<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
		<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
	</bean>

	<bean class="org.springframework.web.servlet.view.tiles3.TilesConfigurer" id="tilesConfigurer">
		<property name="definitions">
			<list>
				<value>/WEB-INF/layouts.xml</value>
				<value>/WEB-INF/views/**/views.xml</value>
			</list>
		</property>
	</bean>
</beans>

Если запустить приложение, то получим ошибку DispatcherServlet'а о том, что не удаётся инициализировать Apache Tiles.

2013-06-22 11:32:00.900 ERROR o.s.web.servlet.DispatcherServlet - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tilesConfigurer' defined in ServletContext resource [/WEB-INF/default-servlet.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: no URL for ServletContext resource [/WEB-INF/layouts.xml]

Добавим файл webapp/WEB-INF/layouts.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
	<definition name="default" template="/WEB-INF/views/default.jsp">
		<put-attribute name="body" value="IT works" />
	</definition>

	<definition name="*/*" extends="default">
		<put-attribute name="body" value="/WEB-INF/views/{0}.jsp" />
	</definition>
</tiles-definitions>

Создадим директорию webapp/WEB-INF/views/ и в ней 2 файла JSP-страниц.

webapp/WEB-INF/views/default.jsp

<%@page contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>

<%@taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
		<title></title>
    </head>

    <body>
		<tiles:insertAttribute name="body" />
	</body>
</html>

Создадим простую jsp-страницу для вывода значения.

webapp/WEB-INF/views/def/def.jsp

<%@page contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>

Time is ${var1}

Теперь создадим простой контроллер для вывода текущей даты в JSP-страницу.

package com.a1systems.base_jetty;

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

@Controller
public class MainController {

	@RequestMapping("/")
	public String main(Model ui) {
		ui.addAttribute("var1", (new Date()).toString());

		return "def/def";
	}
}

Запустим приложение:

$ mvn clean compile exec:java -Dexec.mainClass=com.a1systems.base_jetty.App
...
2013-06-22 11:40:42.847 INFO  org.eclipse.jetty.server.Server - jetty-9.0.3.v20130506
2013-06-22 11:40:43.035 INFO  / - Initializing Spring FrameworkServlet 'default'
2013-06-22 11:40:43.035 INFO  o.s.web.servlet.DispatcherServlet - FrameworkServlet 'default': initialization started
2013-06-22 11:40:43.053 INFO  o.s.w.c.s.XmlWebApplicationContext - Refreshing WebApplicationContext for namespace 'default-servlet': startup date [Sat Jun 22 11:40:43 MSK 2013]; root of context hierarchy
2013-06-22 11:40:43.083 INFO  o.s.b.f.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/default-servlet.xml]
2013-06-22 11:40:43.299 INFO  o.s.b.f.s.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@45b3f6ae: defining beans [mvcContentNegotiationManager,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,mainController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,tilesViewResolver,tilesConfigurer,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
2013-06-22 11:40:43.373 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.a1systems.base_jetty.MainController.main(org.springframework.ui.Model)
2013-06-22 11:40:43.580 DEBUG org.apache.commons.digester.Digester - register('-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN', 'jar:file:/home/wiz/.m2/repository/org/apache/tiles/tiles-core/3.0.1/tiles-core-3.0.1.jar!/org/apache/tiles/resources/tiles-config_3_0.dtd'
2013-06-22 11:40:43.588 INFO  org.apache.tiles.access.TilesAccess - Publishing TilesContext for context: org.springframework.web.servlet.view.tiles3.SpringWildcardServletTilesApplicationContext
2013-06-22 11:40:43.606 INFO  o.s.web.servlet.DispatcherServlet - FrameworkServlet 'default': initialization completed in 571 ms
2013-06-22 11:40:43.627 INFO  o.e.j.server.handler.ContextHandler - Started o.e.j.w.WebAppContext@c26e9b2{/,file:/home/wiz/TRASH/myspringlearning/target/classes/webapp/,AVAILABLE}
2013-06-22 11:40:43.643 INFO  o.e.j.s.n.NetworkTrafficSelectChannelConnector - Started NetworkTrafficSelectChannelConnector@4bc020a4{HTTP/1.1}{0.0.0.0:9090}

Перейдём в браузере по адресу: http://127.0.0.1:9090/ В окне браузера будет напечатано текущее дата и время. При обновлении страницы время будет изменяться.

jetty screenshot

Репозиторий находится по адресу: https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_2 ветка pres_0_10_2

Добавление возможности запуска jetty из jar-архива и добавление библиотек тэгов

В прошлом примере мы создали пример с поддержкой JSP и tiles, но к сожалению пример работает только при запуске через maven и отказывается работать при запуске через java -jar. Необходимо провести ряд работ для того, чтобы заставить работать пример при упаковке в jar-архив.

При запуске из jar директива <%@taglib uri="..." prefix="..." %> в jsp-файлах приводит к исключению, если указан URI в абсолютном формате. Поэтому необходимо создать директорию WEB-INF/tld, где разместить все используемые TLD-файлы. В нашем случае это будут:

  • c.tld
  • spring-form.tld
  • spring.tld
  • tiles-extras-jsp.tld
  • tiles-jsp.tld

tld файлы необходимо скопировать из соответствующих jar-архивов из директории META-INF/tld:

  • jstl-1.2.jar
  • spring-webmvc-3.2.3.RELEASE.jar
  • tiles-jsp-3.0.1.jar

Теперь необходимо переписать директивы подключения taglib на относительные пути:

<%@taglib uri="/WEB-INF/tld/c.tld" prefix="c" %>
<%@taglib uri="/WEB-INF/tld/spring.tld" prefix="spring" %>
<%@taglib uri="/WEB-INF/tld/spring-form.tld" prefix="form" %>

Изменим код JSP-страницы:

<%@page contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>

<%@taglib uri="/WEB-INF/tld/c.tld" prefix="c" %>
<%@taglib uri="/WEB-INF/tld/spring.tld" prefix="spring" %>
<%@taglib uri="/WEB-INF/tld/spring-form.tld" prefix="form" %>

Time is ${var1}

<c:if test="${var1 != null }"><div>Test JSTL</div></c:if>

<form:form modelAttribute="item" method="POST">
	<form:input path="name" /><br />
	<input type="submit" value="send" />
</form:form>

Код контроллера:

@Controller
public class MainController {

	public static class Cls {
		protected  String name;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
	}

	@RequestMapping("/")
	public String main(@ModelAttribute("item") Cls a, Model ui) {
		ui.addAttribute("var1", (new Date()).toString()+a.getName());

		return "def/def";
	}
}

Если запустить приложение через mvn clean compile exec:java или java -jar ..., то веб приложение будет работать в обоих случаях.

Репозиторий проекта располагается по адресу: https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_3 ветка pres_0_10_3

Запуск встроенного Jetty (embedded jetty) с помощью Spring context

Мы научились запускать встроенный jetty программно, теперь добьёмся запуска с помощью Spring application context.

Перенесём код создания jetty в spring context.

application-context.xml

<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
	<bean id="server" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
		<property name="connectors">
			<list>
				<bean id="connector" class="org.eclipse.jetty.server.nio.NetworkTrafficSelectChannelConnector">
					<constructor-arg name="server" ref="server" />
					<property name="port" value="9090" />
					<property name="idleTimeout" value="1000" />
				</bean>
			</list>
		</property>
		<property name="handler">
			<bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
				<property name="handlers">
					<list>
						<bean id="contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection">
							<property name="handlers">
								<list>
									<bean class="org.eclipse.jetty.webapp.WebAppContext">
										<property name="contextPath" value="/"/>
										<property name="resourceBase" value="#{T(java.lang.Thread).currentThread().getContextClassLoader().getResource('webapp').toExternalForm()}"/>
									</bean>
								</list>
							</property>
						</bean>
					</list>
				</property>
			</bean>
		</property>
	</bean>
</beans>

Единственным сложным моментов является настройка пути к ресурсам с помощью SpEL. Выражение #{T(java.lang.Thread).currentThread().getContextClassLoader().getResource('webapp').toExternalForm()} соответствует Thread.currentThread().getContextClassLoader().getResource("webapp").toExternalForm().

Добавим получение контекста в App.java.

package com.a1systems.base_jetty;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App
{
    public static void main( String[] args ) throws Exception
    {
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("application-context.xml");
    }
}

Если пересобрать приложение, то встроенный сервер запускается через контекст Spring.

Однако доступа к бинам объявленным в applciation-context.xml из контроллеров нет.

Исходники по адресу: https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_4 ветка pres_0_10_4.

Добавление загрузки ресурсов (JS, CSS, изображений)

Добавим в качестве ресурсов иконку сайта (favicon.ico) и Twitter bootstrap http://twitter.github.io/bootstrap/ .

Clone this wiki locally