Żeby nie było, że jest to trudne, bo nie jest. Przedstawię tu metodę zintegrowania Vaadin ze Springiem w wersji 2.0. Z nowszym 2.5 jest to jeszcze łatwiejsze, ale nie dotykałem się tamtej wersji jeszcze i nie miałem okazji się pobawić. Zatem będzie trochę bardziej oldschoolowo, ale też ładnie. Tworzymy nowy projekt Vaadin za pomocą Mavena i dodajemy kilka informacji do pom.xml.

Listing 1. Springowo-Vaadinowy pom.xml

<?xml version="1.0" encoding="UTF-8"??><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/maven-v4_0_0.xsd"><modelversion>4.0.0</modelversion><groupid>pl.koziolekweb.blog.vaadin</groupid><artifactid>vaadin-spring-integration-example</artifactid><packaging>war</packaging><version>1.0</version><name>Vaadin Web Application</name><properties><project.build.sourceencoding>UTF-8</project.build.sourceencoding><spring.version>2.0.3</spring.version></properties><build><plugins><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-compiler-plugin</artifactid><configuration><source>1.6</source><target>1.6</target></configuration></plugin><plugin><groupid>org.mortbay.jetty</groupid><artifactid>maven-jetty-plugin</artifactid><version>6.1.19</version><configuration><systemproperties><systemproperty><name>jetty.port</name><value>23030</value></systemproperty></systemproperties><stopport>9966</stopport><stopkey>vaadin-spring-integration-example</stopkey><scanintervalseconds>25</scanintervalseconds><webappconfig><contextpath>/vaadin-spring-integration-example</contextpath><baseresource implementation="org.mortbay.resource.ResourceCollection"><resourcesascsv>src/main/webapp,${project.build.directory}/${project.build.finalName}</resourcesascsv></baseresource></webappconfig></configuration></plugin><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-eclipse-plugin</artifactid><version>2.8</version><configuration><downloadjavadocs>true</downloadjavadocs><downloadsources>true</downloadsources></configuration><executions><execution><id>eclipse</id><phase>clean</phase><goals><goal>clean</goal><goal>eclipse</goal></goals></execution></executions></plugin></plugins></build><repositories><repository><id>vaadin-snapshots</id><url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository></repositories><dependencies><dependency><groupid>com.vaadin</groupid><artifactid>vaadin</artifactid><version>6.2.0</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-core</artifactid><version>${spring.version}</version></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>junit</groupid><artifactid>junit</artifactid><version>4.8.1</version></dependency></dependencies></project>

Teraz czas na wprowadzenie kilku zmian w web.xml. No niestety tu trzeba dołożyć kilka rzeczy. Wynika to bardziej z wykorzystania Springa, bo dla Vaadin wsio ryba.

Listing 2. Dodatkowe informacje w web.xml

<web-app>
...
	<context-param><param-name>contextConfigLocation</param-name><param-value>WEB-INF/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
...
</web-app>

Czyli standardowo dokładamy listener kontekstu dla Springa i lokalizację applicationContext.xml. Sam plik applicationContext.xml wygląda tak:

Listing 3. applicationContext.xml naszej aplikacji

<?xml version="1.0" encoding="UTF-8"??><beans><bean class="pl.koziolekweb.blog.vaadin.beans.PicassoImpl" id="picasso" name="picasso"></bean><bean class="pl.koziolekweb.blog.vaadin.beans.ManagerImpl" id="picassoMng" name="picassoMng"><property name="picasso" ref="picasso"></property></bean></beans>

Będziemy robili taką samą aplikację jak poprzednio, ale tym razem ze Springiem na pokładzie.

Dodatkowe bajery

W tej wersji musimy stworzyć sobie małą fabryczkę, która będzie nam pośredniczyła w tworzeniu beanów. W przypadku wersji 2.5 można pominąć ten krok i dodać konfigurację z adnotacji.

Listing 4. SpringContextHelper

package pl.koziolekweb.blog.vaadin;

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class SpringContextHelper {

	private ApplicationContext context;

	public SpringContextHelper(Application application) {
		ServletContext servletContext = ((WebApplicationContext) application
				.getContext()).getHttpSession().getServletContext();
		context = WebApplicationContextUtils
				.getRequiredWebApplicationContext(servletContext);
	}

	public <t> T getBean(Class<t> beanClass, final String beanRef) {
		return beanClass.cast(context.getBean(beanRef));
	}

}
</t></t>

Lubię genericsy 😉

Aplikacja

Na koniec aplikacja. Nie podam wam tu klas implementujących interfejsy, bo chcę mieć co pokazać na WJUGu 20 kwietnia 🙂 Gdzie oczywiście zapraszam 🙂

Listing 5. Efekt końcowy naszych prac

/*
 * Copyright 2009 IT Mill Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package pl.koziolekweb.blog.vaadin;

import java.awt.Color;
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import pl.koziolekweb.blog.vaadin.beans.Manager;

import com.vaadin.Application;
import com.vaadin.terminal.StreamResource;
import com.vaadin.terminal.StreamResource.StreamSource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

/**
 * The Application's "main" class
 */
@SuppressWarnings("serial")
public class MyVaadinApplication extends Application {
	private Window window;
	private SpringContextHelper helper;
	private Manager manager;
	private Image job;
	private Embedded image;
	private Button orderJobBtn;

	@Override
	public void init() {
		window = new Window("My Vaadin Application");
		setMainWindow(window);

		helper = new SpringContextHelper(this);
		manager = helper.getBean(Manager.class, "picassoMng");
		job = manager.getJob(Color.RED);
		orderJobBtn = new Button("Order Job");

		orderJobBtn.addListener(new ClickListener() {

			public void buttonClick(ClickEvent event) {

				StreamSource gallery = new StreamSource() {
					private ByteArrayOutputStream imagebuffer = null;

					public InputStream getStream() {
						try {
							imagebuffer = new ByteArrayOutputStream();
							ImageIO.write((RenderedImage) job, "png",
									imagebuffer);
							return new ByteArrayInputStream(imagebuffer
									.toByteArray());

						} catch (IOException e) {
							return null;
						}
					}
				};

				StreamResource imageresource = createStreamResource(gallery);
				if (image != null) {
					window.removeComponent(image);
				}
				image = new Embedded("Image title", imageresource);
				window.addComponent(image);

			}
		});

		window.addComponent(orderJobBtn);

	}

	private StreamResource createStreamResource(
			StreamResource.StreamSource imagesource) {
		return new StreamResource(imagesource, "myimage.png", this);
	}

}

Jak widać pierwszego beana pobieram wprost po nazwie. Można przyjąć, że w tym miejscu będzie tworzony też kontekst Spring Security. Oczywiście całość tylko raz przy starcie aplikacji.

No to by było na tyle.