-
Notifications
You must be signed in to change notification settings - Fork 56
Jetty
Мы уже использовали Jetty в разделе про Spring MVC как плагин для Maven, а в этом разделе будет рассказано о непосредственно сервере 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 программно (без использования 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/
То есть web-сервер запущен и работает на порту 9090, но нет контента для отображения.
Репозиторий находится по адресу: https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_1 ветка pres_0_10_1
Фактически в предыдущем примере мы запустили минимальный 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 не настроен 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/ В окне браузера будет напечатано текущее дата и время. При обновлении страницы время будет изменяться.
Репозиторий находится по адресу: https://github.com/wizardjedi/my-spring-learning/tree/pres_0_10_2 ветка pres_0_10_2
В прошлом примере мы создали пример с поддержкой 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 программно, теперь добьёмся запуска с помощью 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.
Добавим в качестве ресурсов иконку сайта (favicon.ico) и Twitter bootstrap http://twitter.github.io/bootstrap/ .