<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>j2ee.pl - związani z javą &#187; JSP</title>
	<atom:link href="http://j2ee.pl/category/jsp/feed/" rel="self" type="application/rss+xml" />
	<link>http://j2ee.pl</link>
	<description>związani z Javą</description>
	<lastBuildDate>Mon, 24 Aug 2009 11:45:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Stripes framework</title>
		<link>http://j2ee.pl/2008/04/16/stripes-framework/</link>
		<comments>http://j2ee.pl/2008/04/16/stripes-framework/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 09:07:05 +0000</pubDate>
		<dc:creator>Piotr Święciak</dc:creator>
				<category><![CDATA[Inne biblioteki]]></category>
		<category><![CDATA[JSP]]></category>
		<category><![CDATA[stripes]]></category>

		<guid isPermaLink="false">http://j2ee.pl/?p=125</guid>
		<description><![CDATA[
Stripes jest frameworkiem wspomagającym implementowanie warstwy prezentacji w aplikacjach webowych. Jest podobny do znanego wszystkim frameworka Struts. Jednak Stripesy nie wymagają konfigurowania warstwy widoku w plikach xml co w przypadku poznawania nowego frameworka jest kłopotliwe i wymaga więcej czasu. W tym wypadku cała konfiguracja obsługiwana jest za pomocą adnotacji wprowadzonych w Javie 5.

Jako przykład przedstawiający [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="float: left; margin: 30px;" src="http://j2ee.pl/wp-content/uploads/2008/04/stripes3.png" alt="" width="160" height="42" /></p>
<p style="text-align: justify">Stripes jest frameworkiem wspomagającym implementowanie warstwy prezentacji w aplikacjach webowych. Jest podobny do znanego wszystkim frameworka Struts. Jednak Stripesy nie wymagają konfigurowania warstwy widoku w plikach xml co w przypadku poznawania nowego frameworka jest kłopotliwe i wymaga więcej czasu. W tym wypadku cała konfiguracja obsługiwana jest za pomocą adnotacji wprowadzonych w Javie 5.</p>
<p><span id="more-125"></span></p>
<p style="text-align: justify">Jako przykład przedstawiający kilka możliwości tego frameworka stworzymy prostą aplikację webową, która służyć będzie do zarządzania książkami w bibliotece (dodawanie nowych pozycji, usuwanie, edycja). Do stworzenia projektu będzie potrzebny właściwie tylko Maven2 oraz serwer aplikacji w naszym wypadku wystarczy Tomcat (oczywiście pomocny będzie również Eclipse choć nie jest konieczny).</p>
<p style="text-align: justify">Zaczynamy oczywiscie od wygenerowania szkieletu projektu :</p>
<p class="MsoNormal"><span lang="EN-US"><strong>mvn archetype:create -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=pl.jcommerce.biblioteka -DartifactId=Stripes-Biblioteka</strong></span></p>
<p class="MsoNormal">Następnie jeżeli chcemy korzystać z Eclipse w katalogu projektu wykonujemy instrukcje<strong> mvn eclipse:eclipse </strong>i importujemy projekt w Eclipse.</p>
<p class="MsoNormal">Kolejnym krokiem jest konfiguracja pliku pom.xml</p>
<pre class="prettyprint">&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
	&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
	&lt;groupId&gt;pl.jcommerce.biblioteka&lt;/groupId&gt;
	&lt;artifactId&gt;Stripes-Biblioteka&lt;/artifactId&gt;
	&lt;packaging&gt;war&lt;/packaging&gt;
	&lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
	&lt;name&gt;stripesexample Maven Webapp&lt;/name&gt;
	&lt;url&gt;http://maven.apache.org&lt;/url&gt;
	&lt;build&gt;
		&lt;defaultGoal&gt;package&lt;/defaultGoal&gt;
		&lt;finalName&gt;stripesexample&lt;/finalName&gt;
		&lt;plugins&gt;
			&lt;plugin&gt;
				&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
				&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
				&lt;configuration&gt;
					&lt;encoding&gt;utf8&lt;/encoding&gt;
					&lt;source&gt;1.6&lt;/source&gt;
					&lt;target&gt;1.6&lt;/target&gt;
				&lt;/configuration&gt;
			&lt;/plugin&gt;
		&lt;/plugins&gt;
	&lt;/build&gt;
	&lt;dependencies&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;net.sourceforge.stripes&lt;/groupId&gt;
			&lt;artifactId&gt;stripes&lt;/artifactId&gt;
			&lt;version&gt;1.4.3&lt;/version&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;javax.servlet&lt;/groupId&gt;
			&lt;artifactId&gt;jstl&lt;/artifactId&gt;
			&lt;version&gt;1.2&lt;/version&gt;
		&lt;/dependency&gt;
	&lt;/dependencies&gt;
&lt;/project&gt;</pre>
<p>Teraz zajmiemy się konfiguracją deskryptora aplikacji webowej. W przypadku naszej aplikacji wystarczy najprostsza konfiguracja czyli ustawienie Stripes Filter oraz Stripes Dispatcher.</p>
<pre class="prettyprint">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot;
	version=&quot;2.4&quot;&gt;
	&lt;filter&gt;
		&lt;display-name&gt;Stripes Filter&lt;/display-name&gt;
		&lt;filter-name&gt;StripesFilter&lt;/filter-name&gt;
		&lt;filter-class&gt;
			net.sourceforge.stripes.controller.StripesFilter
		&lt;/filter-class&gt;
	&lt;/filter&gt;
	&lt;filter-mapping&gt;
		&lt;filter-name&gt;StripesFilter&lt;/filter-name&gt;
		&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;
		&lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
	&lt;/filter-mapping&gt;
	&lt;filter-mapping&gt;
		&lt;filter-name&gt;StripesFilter&lt;/filter-name&gt;
		&lt;servlet-name&gt;StripesDispatcher&lt;/servlet-name&gt;
		&lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
	&lt;/filter-mapping&gt;
	&lt;servlet&gt;
		&lt;servlet-name&gt;StripesDispatcher&lt;/servlet-name&gt;
		&lt;servlet-class&gt;
			net.sourceforge.stripes.controller.DispatcherServlet
		&lt;/servlet-class&gt;
		&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
	&lt;/servlet&gt;
	&lt;servlet-mapping&gt;
		&lt;servlet-name&gt;StripesDispatcher&lt;/servlet-name&gt;
		&lt;url-pattern&gt;*.action&lt;/url-pattern&gt;
	&lt;/servlet-mapping&gt;
&lt;/web-app&gt;</pre>
<p>Nasza aplikacja ma służyć do zarządzania książkami, dlatego zaczniemy od stworzenie modelu danych.</p>
<pre class="prettyprint">package pl.jcommerce.entity;
import java.util.Date;

public class Book {

	private int id;
	private String title;
	private String author;
	private Date date;
	private int amount;

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public int getAmount() {
		return amount;
	}

	public void setAmount(int amount) {
		this.amount = amount;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

}</pre>
<p style="text-align: justify">W końcu przyszedł czas na warstwą prezentacji, która zarządzana będzie przez framework Stripes. Kontrolery będą odpowiedzialne za akcje wykonywane przez użytkownika. Pierwszy z nich będzie miał za zadanie przekierowanie i wyświetlenie strony startowej, oraz stworzenie listy książek.<br />
Ponieważ nie korzystamy z bazy danych, dlatego wykorzystamy do tego celu statyczną listą książek, na której będziemy operować.</p>
<pre class="prettyprint">package pl.jcommerce.action;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;

@UrlBinding(&quot;/index.action&quot;)
public class IndexActionBean implements ActionBean {

	private ActionBeanContext context;

	public ActionBeanContext getContext() {
		return context;
	}

	public void setContext(ActionBeanContext context) {
		this.context = context;
	}

	@DefaultHandler
	public Resolution getListBooks() {
		return new ForwardResolution(ListBooksActionBean.class);
	}

}</pre>
<p style="text-align: justify">Kontroler ten jak i wszystkie inne implementuje interface ActionBean, ponieważ każdy kontroler musi zawierać pole context (informacje o aktualnym stanie aplikacji) typu ActionBeanConext. Adnotacja @UrlBinding(&#8221;/index.action&#8221;) przypisuje do kontrolera nazwę, według której będziemy sie odwoływać ze stron jsp. Kolejną adnotacją znajdującą się w tym kontrolerze jest @DefaultHandler. Metoda poprzedzona tą adnotają wykonana zostanie jeżeli będziemy się odwoływać do danego kontrolera, a nie podamy nazwy zdarzenia, które ma zostać obsłużone. W naszym wypadku w momencie odwołania sie do tego kontrolera zostaje wywołana domyślna metoda, która z kolei przekierowuje nas do kolejnego kontrolera ListBooksActionBean.</p>
<pre class="prettyprint">package pl.jcommerce.action;

import java.util.HashMap;
import java.util.Map;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.HandlesEvent;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import pl.jcommerce.entity.Book;

@UrlBinding(&quot;/listBooks.action&quot;)
public class ListBooksActionBean implements ActionBean {

	public static Map&lt;Integer, Book&gt; books = new HashMap&lt;Integer, Book&gt;();

	private ActionBeanContext context;

	public ActionBeanContext getContext() {
		return context;
	}

	public void setContext(ActionBeanContext context) {
		this.context = context;
	}

	@DefaultHandler
	public Resolution getListBooks() {
		return new ForwardResolution(&quot;/jsp/listBooks.jsp&quot;);
	}

	@HandlesEvent(&quot;addBook&quot;)
	public Resolution addBook() {
		return new ForwardResolution(AddBookActionBean.class);
	}

	public Map&lt;Integer, Book&gt; getBooks() {
		return books;
	}

	public void setBooks(Map&lt;Integer, Book&gt; books) {
		ListBooksActionBean.books = books;
	}

}</pre>
<p style="text-align: justify">W tym kontrolerze widzimy adnotację @HandlesEvent(&#8221;addBook&#8221;), która powoduje przypisanie nazwy zdarzenie do metody. Jeżeli przed metodą w kontrolerze nie użyjemy tej adnotacji  domyślne zdarzenia nazywają się tak samo jak nazwa metody. Ostatni kontroler w naszej aplikacji odpowiada za dodawanie i edycje książek.</p>
<pre class="prettyprint">package pl.jcommerce.action;import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.HandlesEvent;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrors;
import net.sourceforge.stripes.validation.ValidationMethod;
import pl.jcommerce.entity.Book;

@UrlBinding(&quot;/addBook.action&quot;)
public class AddBookActionBean implements ActionBean {

	private static final String SAVE_EVENT = &quot;save&quot;;

	private static int counter;

	@ValidateNestedProperties( {
	@Validate(field = &quot;title&quot;, on = SAVE_EVENT, required = true, minlength = 3, maxlength = 15),
	@Validate(field = &quot;author&quot;, on = SAVE_EVENT, required = true, maxlength = 25),
	@Validate(field = &quot;date&quot;, on = SAVE_EVENT, required = true, maxlength = 25),
	@Validate(field = &quot;amount&quot;, on = SAVE_EVENT, required = true) })
	private Book book;

	private ActionBeanContext context;

	public ActionBeanContext getContext() {
		return context;
	}

	public void setContext(ActionBeanContext context) {
		this.context = context;
	}

	public Book getBook() {
		return book;
	}

	public void setBook(Book book) {
		this.book = book;
	}

	@DefaultHandler
	public Resolution view() {
		return new ForwardResolution(&quot;/jsp/addBook.jsp&quot;);
	}

	@HandlesEvent(SAVE_EVENT)
	public Resolution save() {
		if (book.getId() == 0) {
			book.setId(++counter);
		}
		ListBooksActionBean.books.put(book.getId(), book);
		return new ForwardResolution(ListBooksActionBean.class);
	}

	@HandlesEvent(&quot;edit&quot;)
	public Resolution edit() {
		book = ListBooksActionBean.books.get(book.getId());
		return new ForwardResolution(&quot;/jsp/addBook.jsp&quot;);
	}

	@HandlesEvent(&quot;delete&quot;)
	public Resolution delete() {
		ListBooksActionBean.books.remove(book.getId());
		return new ForwardResolution(ListBooksActionBean.class);
	}

	@ValidationMethod(on = &quot;save&quot;)
	public void validateSave(ValidationErrors errors) {
		if (book.getId() == 0) {
			for (Book s : ListBooksActionBean.books.values()) {
				if (book.getTitle().equals(s.getTitle())) {
					errors.add(&quot;book.title&quot;, new LocalizableError(&quot;er.book.title&quot;));
					getContext().setValidationErrors(errors);
				}
			}
		}
	}

}</pre>
<p style="text-align: justify">W naszym ostatnim kontrolerze widzimy adnotacje związane z walidacją danych. Jeżeli mamy do czynienia z obiektem możemy walidować wszystkie jego pola oraz okreslić w przypadku jakich akcji dane pola maja być walidowane. W naszym przypadku wszystkie pola bedą sprawdzane w czasie zgłoszenia zdarzenia „save”.  Adnotacja @ValidateMethod(on=&#8221;save) powoduje wywołanie tej metody walidującej jedynie podczas zgłaszania zdarzenie &#8220;save&#8221;.</p>
<p style="text-align: justify">Walidacja oraz internacjonalizacja opisana jest w pliku StripesResources .properties</p>
<pre class="prettyprint">validation.required.valueNotPresent=Pole {0} jest wymagane polem
validation.minlength.valueTooShort=Pole {0} wymaga wpisania conajmniej {2} znakow
validation.maxlength.valueTooLong=Pole {0} moze miec max {2} znaki

converter.number.invalidNumber=Warto\u015B\u0107 ({1}) wprowadzona w polu "{0}" musi by\u0107 liczb\u0105
converter.date.invalidDate=Warto\u015B\u0107 ({1}) wprowadzona w polu "{0}" musi by\u0107 prawid\u0142ow\u0105 dat\u0105

book.title=Tytul
book.amount=Liczba dostepnych
book.date=Data wydania
book.author=Autor
er.book.title=Ksiazka o podanym tytule znajduje sie juz w bibliotece</pre>
<p style="text-align: justify">Wszystkie kontrolery już gotowe a więc teraz czas na strony jsp:</p>
<p style="text-align: justify">index.jsp</p>
<pre class="prettyprint">&lt;%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%&gt;
&lt;jsp:forward page="/index.action"/&gt;</pre>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;">listBooks.jsp</p>
<pre class="prettyprint">&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot;%&gt;
&lt;%@ taglib prefix=&quot;fn&quot; uri=&quot;http://java.sun.com/jsp/jstl/functions&quot;%&gt;
&lt;%@ taglib prefix=&quot;fmt&quot; uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot;%&gt;
&lt;%@ taglib prefix=&quot;stripes&quot; uri=&quot;http://stripes.sourceforge.net/stripes.tld&quot;%&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html&gt;
	&lt;head&gt;
		&lt;title&gt;Stripes example&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;stripes:form action=&quot;/index.action&quot;&gt;
			&lt;stripes:submit name=&quot;addBook&quot; value=&quot;Add book&quot; /&gt;
			&lt;table&gt;
				&lt;tr&gt;
					&lt;td&gt;&lt;stripes:label for=&quot;book.title&quot; /&gt;&lt;/td&gt;
					&lt;td&gt;&lt;stripes:label for=&quot;book.author&quot; /&gt;&lt;/td&gt;
					&lt;td&gt;&lt;stripes:label for=&quot;book.date&quot; /&gt;&lt;/td&gt;
					&lt;td&gt;&lt;stripes:label for=&quot;book.amount&quot; /&gt;&lt;/td&gt;
				&lt;/tr&gt;
				&lt;c:forEach var=&quot;book&quot; items=&quot;${actionBean.books}&quot;&gt;
					&lt;tr&gt;
						&lt;td&gt;${book.value.title}&lt;/td&gt;
						&lt;td&gt;${book.value.author}&lt;/td&gt;
						&lt;td&gt;&lt;fmt:formatDate value=&quot;${book.value.date}&quot; pattern=&quot;yyyy-MM-dd&quot; /&gt;&lt;/td&gt;
						&lt;td&gt;${book.value.amount}&lt;/td&gt;
						&lt;td&gt;
							&lt;stripes:link href=&quot;/addBook.action&quot; event=&quot;edit&quot;&gt;Edit &lt;stripes:param name=&quot;book.id&quot; value=&quot;${book.value.id}&quot; /&gt;&lt;/stripes:link&gt;
						&lt;/td&gt;
						&lt;td&gt;
							&lt;stripes:link href=&quot;/addBook.action&quot; event=&quot;delete&quot;&gt;Delete&lt;stripes:param name=&quot;book.id&quot; value=&quot;${book.value.id}&quot; /&gt;&lt;/stripes:link&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
				&lt;/c:forEach&gt;
			&lt;/table&gt;
		&lt;/stripes:form&gt;
	&lt;/body&gt;
&lt;/html&gt;</pre>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;">addBook.jsp</p>
<pre class="prettyprint">&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot;%&gt;
&lt;%@ taglib prefix=&quot;fn&quot; uri=&quot;http://java.sun.com/jsp/jstl/functions&quot;%&gt;
&lt;%@ taglib prefix=&quot;stripes&quot; uri=&quot;http://stripes.sourceforge.net/stripes.tld&quot;%&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html&gt;
&lt;head&gt;
&lt;META http-equiv=&quot;contentType&quot; content=&quot;text/html;charset=UTF-8&quot;&gt;
&lt;meta http-equiv=&quot;Content-Language&quot; content=&quot;pl&quot;&gt;
&lt;title&gt;Stripes example&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;stripes:form action=&quot;/addBook.action&quot;&gt;
	&lt;stripes:errors globalErrorsOnly=&quot;true&quot; /&gt;
	&lt;table&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;stripes:label for=&quot;book.title&quot; /&gt;:&lt;/td&gt;
			&lt;td&gt;&lt;stripes:text name=&quot;book.title&quot;&gt;&lt;/stripes:text&gt;&lt;/td&gt;
			&lt;td&gt;&lt;stripes:errors field=&quot;book.title&quot; /&gt;&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;stripes:label for=&quot;book.author&quot; /&gt;:&lt;/td&gt;
			&lt;td&gt;&lt;stripes:text name=&quot;book.author&quot;&gt;&lt;/stripes:text&gt;&lt;/td&gt;
			&lt;td&gt;&lt;stripes:errors field=&quot;book.author&quot; /&gt;&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;stripes:label for=&quot;book.date&quot; /&gt;:&lt;/td&gt;
			&lt;td&gt;&lt;stripes:text name=&quot;book.date&quot; formatPattern=&quot;yyyy-MM-dd&quot;&gt;&lt;/stripes:text&gt;&lt;/td&gt;
			&lt;td&gt;&lt;stripes:errors field=&quot;book.date&quot; /&gt;&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;stripes:label for=&quot;book.amount&quot; /&gt;:&lt;/td&gt;
			&lt;td&gt;&lt;stripes:text name=&quot;book.amount&quot;&gt;&lt;/stripes:text&gt;&lt;/td&gt;
			&lt;td&gt;&lt;stripes:errors field=&quot;book.amount&quot; /&gt;&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;
	&lt;c:choose&gt;
		&lt;c:when test=&quot;${actionBean.book.id &gt; 0}&quot;&gt;
			&lt;stripes:hidden name=&quot;book.id&quot; value=&quot;book.id&quot;&gt;&lt;/stripes:hidden&gt;
		&lt;/c:when&gt;
		&lt;c:otherwise&gt;&lt;/c:otherwise&gt;
	&lt;/c:choose&gt;
	&lt;stripes:submit name=&quot;save&quot; value=&quot;Save&quot; /&gt;
&lt;/stripes:form&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p style="text-align: justify">Mamy już wszystkie pliki potrzebne nam w aplikacji zatem wykonujemy polecenie <strong> mvn install </strong> i plik war wrzucamy na serwer.<br />
Mam nadzieje, że ten krótki artykuł choć trochę przybliżył zasadę działania tego frameworka. Oczywiście możliwości jego są dużo większe niż przedstawiłem w tym artykule, dlatego na temat jego wszystkich możliwości odsyłam na stronę domową frameworka.</p>
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;">
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/04/16/stripes-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DWR = Direct Web Remoting = ?</title>
		<link>http://j2ee.pl/2008/03/16/dwr-direct-web-remoting/</link>
		<comments>http://j2ee.pl/2008/03/16/dwr-direct-web-remoting/#comments</comments>
		<pubDate>Sun, 16 Mar 2008 17:17:03 +0000</pubDate>
		<dc:creator>Michał Mally</dc:creator>
				<category><![CDATA[Inne biblioteki]]></category>
		<category><![CDATA[JS]]></category>
		<category><![CDATA[JSP]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[direct web remoting]]></category>
		<category><![CDATA[dwr]]></category>
		<category><![CDATA[java script]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2008/03/16/dwr-direct-web-remoting/</guid>
		<description><![CDATA[Słowem wstępu
Mroczna historia na dobry początek
Przed monitorem jednego z terminali Biblioteki Uniwersyteckiej spędzałem kolejną dłużącą się bez końca godzinę. Na zewnątrz niebo nabierało coraz ciemniejszych barw. Poszukiwałem ciekawego tematu na nowy artykuł na j2ee.pl.
Wielogodzinna praca powodowała, że zaczynałem odczuwać nadchodzące zmęczenie. Postanowiłem podarować sobie chwilę odpoczynku od zagadnień IT. Nierozsądnie wpisałem w pasku przeglądarki tvn24.pl [...]]]></description>
			<content:encoded><![CDATA[<h2>Słowem wstępu</h2>
<h3>Mroczna historia na dobry początek</h3>
<p style="text-align: justify"><img src="http://getahead.org/images/dwr-logo-200.gif" style="float: left" />Przed monitorem jednego z terminali <em>Biblioteki Uniwersyteckiej</em> spędzałem kolejną dłużącą się bez końca godzinę. Na zewnątrz niebo nabierało coraz ciemniejszych barw. Poszukiwałem ciekawego tematu na nowy artykuł na <strong>j2ee.pl</strong>.</p>
<p style="text-align: justify">Wielogodzinna praca powodowała, że zaczynałem odczuwać nadchodzące zmęczenie. Postanowiłem podarować sobie chwilę odpoczynku od zagadnień IT. Nierozsądnie wpisałem w pasku przeglądarki <em>tvn24.pl</em> &#8211; strona chwilę się wczytywała. Wziąłem ostatni już łyk <em>Red Bulla</em>. Jak przez mgłę spoglądałem na treści atakujące moją bezbronną świadomość. W prawym dolnym rogu ujrzałem umieszczoną sondę. Zupełnie bez powodu ogarnęła mnie nagła, nieodparta ochota na to, żeby zagłosować&#8230; Lecz nagle poczułem na skórze powiew mroźnego powietrza, który w parnej sali <em>Biblioteki</em> wydawał się pojawić jakby znikąd. To co działo się następnie nie sposób opisać jakimikolwiek słowami. Przez chwilę zdawało mi się, że tuż za moimi plecami bezgłośnie niczym rycerz ciemności przemknął <strong>Premier Jarosław Kaczyński</strong> cenzurując swym wzrokiem oglądane przeze mnie treści. Modliłem się, żeby to wszystko nie było prawdą &#8211; nie chciałem, żeby Premier zobaczył oglądania jakich <em>pornograficznych</em> treści dopuszczają się studenci. Wciąż oszołomiony tym, co wydarzyło się przed chwilą postanowiłem zaczerpnąć świeżego powietrza.</p>
<p><span id="more-115"></span></p>
<p style="font-size: 0.8em; color: #aaaaaa">(Aby przejść do części praktycznej kliknij <a href="#czesc_praktyczna">tutaj</a>.)</p>
<h3>DWR?</h3>
<p style="text-align: justify">Po krótkiej przerwie powróciłem pełen energii do dalszej pracy.  Początkowo miałem kilka pomysłów, aby w końcu zdecydować się na przedstawienie frameworka <strong>Direct Web Remoting</strong>, czyli jak twierdzą jego autorzy łatwego sposobu na <em>Ajax</em> dla programistów <em>Javy</em>. Przyznam się, że dałem się im przekonać. W jakim jednak celu tworzyć kolejne wprowadzenie do tak dobrze znanego i jeszcze lepiej udokumentowanego szkieletu programistycznego. To zupełnie tak jakby dzisiaj pisać kolejną książkę o podstawowych zagadnieniach <em>Springa</em>, czy <em>Hibernate</em>&#8216;a. Jest na <em>sali</em> dzisiaj ktokolwiek, kto by nie miał do czynienia z bardzo dobrymi publikacjami opisującymi te zagadnienia?&#8230; Tak właśnie myślałem!</p>
<h3>A może jednak?</h3>
<p style="text-align: justify">Mimo tych szargających mną wątpliwości postanowiłem dokonać krótkiej prezentacji frameworka <strong>DWR</strong>, gdyż zachowując wszystkie podobieństwa do wyżej wymienionych technologii – z <strong>DWR</strong> wydaje się być jednak nieco inaczej. Ja osobiście bliżej przyjrzeć się temu frameworkowi miałem dopiero okazję stosunkowo niedawno. Z badań opinii publicznej ;), jakie pozwoliłem sobie przeprowadzić okazało się, że nie jestem jedyną osobą, która do niedawana o <strong>DWR</strong> niewiele wiedziała – a nawet jeżeli wiedziała, to była to wiedza czysto teoretyczna.</p>
<h3>DWR + Spring</h3>
<p style="text-align: justify">Aktualną stabilną <em>gałęzią</em> jest <em>branch</em> <strong>2.0.x</strong>, ale trwają intensywne prace nad wersją <strong>3.0</strong>, która już niebawem powinna ujrzeć światło dzienne. W tym artykule będę korzystał z ostatniej dostępnej wersji stabilnej, czyli na dzień dzisiejszy – <strong>2.0.3</strong>. Swoją uwagę skupię przede wszystkim na możliwościach integracji tego frameworka ze <em>Springiem</em>. Po tym nieco teoretycznym wstępie przedstawię działający przykład aplikacji webowej zwracając uwagę na szczególnie interesujące i pomocne elementy z punktu widzenia developera. Przedstawione rozwiązanie będzie miało charakter <em>Proof of Concept</em>, stąd też przykład którym się posłużę będzie wyjątkowo trywialny.</p>
<h3>Cel</h3>
<p style="text-align: justify">Gdy inwestuje się w coś swój (czy też czyjś) czas warto wiedzieć, co właściwie ma być finalnym efektem włożonej pracy. Moim celem będzie pokazanie w jaki sposób umożliwić bezpośrednie wywoływania z poziomu <em>JavaScript</em> metod serwisów zdefiniowanych (jako <em>beany</em>) w kontekście aplikacyjnym Springa.</p>
<h3>Narzędzia, frameworki i biblioteki wykorzystane do wykonania tego ćwiczenia</h3>
<ul>
<li> 		Narzędzia
<ul>
<li><strong>Eclipse/JDT</strong></li>
<li><strong>maven2</strong> &#8211; posłuży nam do budowania, <em>deployowania</em> oraz testowania aplikacji</li>
<li><strong>maven-jetty-plugin</strong> – wtyczka do <em>mavena</em> pozwalająca na uruchamianie serwera aplikacji, jakim jest <em>Jetty</em> z poziomu <em>mavena</em> (bardzo przyjemne oraz efektywne narzędzie)</li>
</ul>
</li>
<li> 		Framworki i biblioteki
<ul>
<li><strong>Spring Framework</strong></li>
<li><strong>DWR</strong></li>
<li><strong>jQuery</strong></li>
</ul>
</li>
</ul>
<p><a title="czesc_praktyczna" name="czesc_praktyczna"></a></p>
<h2>Część praktyczna</h2>
<p style="font-size: 0.8em; color: #aaaaaa">(Aby pobrać pełne źródła tworzonej aplikacji kliknij <a href="http://j2ee.pl/wp-content/uploads/2008/03/dwr-example-src.zip" title="j2ee.pl DWR example source">tutaj</a>.)</p>
<h3>Przygotowanie standardowego <em>szablonu</em> aplikacji <em>webowej</em></h3>
<p style="text-align: justify">Rozpocznę od utworzenia pliku <em>pom.xml</em> z myślą o aplikacji sieciowej korzystającej ze <em>Spring Web MVC</em>. Z pewnością robiłeś już takie rzeczy wiele razy.</p>
<pre class="prettyprint">pom.xml:
&lt;?xml version="1.0" encoding="UTF-8"?&gt;

&lt;project xmlns="http://maven.apache.org/POM/4.0.0"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;

  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;pl.jcommerce.example&lt;/groupId&gt;
  &lt;artifactId&gt;dwr-example&lt;/artifactId&gt;
  &lt;version&gt;0.1&lt;/version&gt;
  &lt;packaging&gt;war&lt;/packaging&gt;
  &lt;name&gt;j2ee.pl DWR example&lt;/name&gt;

  &lt;build&gt;
    &lt;defaultGoal&gt;package&lt;/defaultGoal&gt;
    &lt;finalName&gt;dwr-example&lt;/finalName&gt;
    &lt;resources&gt;
      &lt;resource&gt;
        &lt;directory&gt;src/main/webapp/WEB-INF&lt;/directory&gt;
      &lt;/resource&gt;
    &lt;/resources&gt;
    &lt;plugins&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
        &lt;configuration&gt;
          &lt;encoding&gt;utf8&lt;/encoding&gt;
          &lt;source&gt;1.6&lt;/source&gt;
          &lt;target&gt;1.6&lt;/target&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.mortbay.jetty&lt;/groupId&gt;
        &lt;artifactId&gt;maven-jetty-plugin&lt;/artifactId&gt;
        &lt;configuration&gt;
          &lt;connectors&gt;
            &lt;connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"&gt;
              &lt;port&gt;8080&lt;/port&gt;
              &lt;maxIdleTime&gt;60000&lt;/maxIdleTime&gt;
            &lt;/connector&gt;
          &lt;/connectors&gt;
          &lt;scanIntervalSeconds&gt;5&lt;/scanIntervalSeconds&gt;
          &lt;webAppConfig&gt;
            &lt;contextPath&gt;/dwr-example&lt;/contextPath&gt;
          &lt;/webAppConfig&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;

  &lt;pluginRepositories&gt;
    &lt;pluginRepository&gt;
      &lt;id&gt;mortbay-repo&lt;/id&gt;
      &lt;name&gt;mortbay-repo&lt;/name&gt;
      &lt;url&gt;http://jetty.mortbay.org/maven2/release&lt;/url&gt;
      &lt;snapshots&gt;
        &lt;enabled&gt;true&lt;/enabled&gt;
      &lt;/snapshots&gt;
    &lt;/pluginRepository&gt;
  &lt;/pluginRepositories&gt;

  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
      &lt;artifactId&gt;servlet-api&lt;/artifactId&gt;
      &lt;version&gt;2.5&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
      &lt;artifactId&gt;jstl&lt;/artifactId&gt;
      &lt;version&gt;1.2&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-core&lt;/artifactId&gt;
      &lt;version&gt;2.5.2&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-aop&lt;/artifactId&gt;
      &lt;version&gt;2.5.2&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-web&lt;/artifactId&gt;
      &lt;version&gt;2.5.2&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
      &lt;version&gt;2.5.2&lt;/version&gt;
    &lt;/dependency&gt;

  &lt;/dependencies&gt;

&lt;/project&gt;</pre>
<p style="text-align: justify">Element, który może być dla Ciebie nowy i być może powinieneś na niego zwrócić uwagę, to konfiguracja wtyczki <em>Jetty</em>. Jeżeli nie znałeś tego narzędzia do tej pory, to z czystym sumieniem mogę Ci je polecić.</p>
<p style="text-align: justify">Teraz utworzę standardową dla <em>mavena</em> strukturę katalogów i dodam kolejne ważne z punktu widzenia projektu pliki.</p>
<pre class="prettyprint">web.xml:
&lt;?xml version="1.0" encoding="UTF-8"?&gt;

&lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4"&gt;

  &lt;display-name&gt;j2ee.pl DWR example&lt;/display-name&gt;
  &lt;description&gt;&lt;/description&gt;

  &lt;listener&gt;
    &lt;display-name&gt;Spring context-loader&lt;/display-name&gt;
    &lt;listener-class&gt;
      org.springframework.web.context.ContextLoaderListener
    &lt;/listener-class&gt;
  &lt;/listener&gt;

  &lt;context-param&gt;
    &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
    &lt;param-value&gt;
      /WEB-INF/applicationContext.xml
    &lt;/param-value&gt;
  &lt;/context-param&gt;

  &lt;servlet&gt;
    &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;
    &lt;servlet-class&gt;
      org.springframework.web.servlet.DispatcherServlet
    &lt;/servlet-class&gt;
    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
  &lt;/servlet&gt;

  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;
    &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;

  &lt;filter&gt;
    &lt;filter-name&gt;CharacterEncodingFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;
      org.springframework.web.filter.CharacterEncodingFilter
    &lt;/filter-class&gt;
    &lt;init-param&gt;
      &lt;param-name&gt;encoding&lt;/param-name&gt;
      &lt;param-value&gt;UTF-8&lt;/param-value&gt;
    &lt;/init-param&gt;
  &lt;/filter&gt;

  &lt;filter-mapping&gt;
    &lt;filter-name&gt;CharacterEncodingFilter&lt;/filter-name&gt;
    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;

&lt;/web-app&gt;</pre>
<p style="text-align: justify">Następnie wykonam polecenie:</p>
<pre class="prettyprint">mvn eclipse:eclipse -DdownloadSources=true</pre>
<p style="text-align: justify">Po pomyślnym wykonaniu tego polecenia zostaną ściągnięte wszystkie wymagane pakiety wraz ze źródłami oraz zostaną utworzone pliki projektu <em>Eclipse</em>, co umożliwi nam pracę z poziomu <em>IDE</em>. Istnieje wiele innych sposobów integracji <em>Eclipse</em> z projektem <em>maven2</em>, ale żaden z nich nie działa do końca perfekcyjnie. W tym jednak wypadku wtyczka <em>eclipse</em> do <em>mavena</em> zdaje egzamin.</p>
<p style="text-align: justify">Teraz już z poziomu <em>IDE</em> uzupełnie konfigurację dodając pliki <em>applicationContext.xml</em> oraz <em>dispatcher-servlet.xml</em> nie zawierające na razie jednak żadnych definicji <em>beanów</em>.</p>
<h3>Pierwsze uruchomienie aplikacji</h3>
<p style="text-align: justify">Jeżeli wszystko poszło zgodnie z planem, to po wykonaniu polecenia</p>
<pre class="prettyprint">mvn jetty:run</pre>
<p>powinnienem być w stanie wywołać z przeglądarki adres <em>http://localhost:8080/dwr-example/</em>.</p>
<p style="text-align: justify">Warto zauważyć, że począwszy od tej chwili po każdej zmianie dokonanej przeze mnie w plikach projektu <em>Jetty</em> automatycznie dokona ponownego <em>deploymentu</em> aplikacji. Jeżeli zmiana plików projektu nie wywoła takiego działania najprawdopodobniej należy dodać dodatkowe wpisy do elementu konfiguracyjnego wtyczki <em>Jetty</em> o nazwie <em>scanTargets</em>.</p>
<p style="text-align: justify">Aplikacja owszem działa, ale trudno na razie być zachwyconym jej funkcjonalnością.</p>
<h3>Dodanie serwisu do aplikacji</h3>
<p style="text-align: justify">Dodam teraz 3 pliki <em>java</em>, które będą definiowały serwis, który będę chciał w przyszłości <em>wołać</em> z poziomu <em>JavaScriptu</em>. Posłużę się prostym serwisem, który będzie posiadał zaledwie jedną metodę. Do określonego przeze mnie celu będzie to zupełnie wystarczające.</p>
<pre class="prettyprint">
package pl.jcommerce.example.dwr.service;

import pl.jcommerce.example.dwr.model.Product;

/**
 * @author Michal Mally
 */
public interface ProductService {

  public Product getProductByCode(String code);

}</pre>
<pre class="prettyprint">
package pl.jcommerce.example.dwr.service;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import pl.jcommerce.example.dwr.model.Product;

/**
 * @author Michal Mally
 */
public class ProductServiceDummyImpl implements
    ProductService {

  private static final Set&lt;Product&gt; products;

  private static final Random random = new Random();

  static {
    products = new HashSet&lt;Product&gt;();
    products.add(new Product("CSS",
        "CSS: The Missing Manual", "O'Reilly Media", 3,
        BigDecimal.valueOf(2309, 2)));
    products.add(new Product("JQR", "jQuery in Action",
        "Manning Publications", 4, BigDecimal.valueOf(2639,
            2)));
    products.add(new Product("DWR",
        "Practical DWR 2 Projects", "Apress", 0, BigDecimal
            .valueOf(3101, 2)));
  }

  @Override
  public Product getProductByCode(String code) {
    for (final Product product : products) {
      if (product.getCode().equals(code.toUpperCase())) {
        return product;
      }
    }

    try {
      Thread.sleep(random.nextInt(1000));
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    return null;
  }

}</pre>
<pre class="prettyprint">
package pl.jcommerce.example.dwr.model;

import java.math.BigDecimal;

/**
 * @author Michal Mally
 */
public class Product {

  private String code;

  private String name;

  private String producer;

  private int itemsAvailable;

  private BigDecimal price;

  public Product() {
    // intentionally left blank
  }

  public Product(String code, String name, String producer,
      int itemsAvailable, BigDecimal price) {
    super();
    this.code = code;
    this.name = name;
    this.producer = producer;
    this.itemsAvailable = itemsAvailable;
    this.price = price;
  }

  // (...) getters/setters

}</pre>
<p style="text-align: justify">Ponieważ całość będę uruchamiał lokalnie w implementacji serwisu celowo zostało dodane losowe opóźnienie, aby móc symulować realne warunki, jakie mają miejsce w Internecie. Mianowicie często zdarza się sytuacja, że odpowiedzi na wysyłane żądanie nie przychodzą w tej samej kolejności w jakiej zostały wysłane żądania.</p>
<p style="text-align: justify">Dodam teraz odpowiedni wpis do pliku <em>applicationContext.xml</em>.</p>
<pre class="prettyprint">
  &lt;bean id="productService" class="pl.jcommerce.example.dwr.service.ProductServiceDummyImpl"&gt;
  &lt;/bean&gt;</pre>
<h3>A gdzie ten DWR?</h3>
<p style="text-align: justify">Będąc w tym miejscu dodanie wsparcia dla DWR zajmie mi już zaledwie kilka minut.</p>
<p style="text-align: justify">Do pliku <em>web.xml</em> dodaje definicję <em>servletu</em> DWR oraz odpowiednie do niego mapowanie.</p>
<pre class="prettyprint">
  &lt;servlet&gt;
    &lt;servlet-name&gt;dwr&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.directwebremoting.spring.DwrSpringServlet&lt;/servlet-class&gt;
    &lt;init-param&gt;
      &lt;param-name&gt;debug&lt;/param-name&gt;
      &lt;param-value&gt;true&lt;/param-value&gt;
    &lt;/init-param&gt;
  &lt;/servlet&gt;

  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;dwr&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/dwr/*&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;</pre>
<p style="text-align: justify">Servlet <em>DWR</em> skonfigurowałem w taki sposób, aby mieć możliwość <em>debugowania</em>.</p>
<p style="text-align: justify">Teraz ponownie modyfikuje plik <em>applicationContext.xml</em> doprowadzając go do finalnej postaci.</p>
<pre class="prettyprint">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
	xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
      http://www.directwebremoting.org/schema/spring-dwr
      http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd"&gt;

  &lt;dwr:configuration&gt;
    &lt;dwr:convert type="bean" class="pl.jcommerce.example.dwr.model.Product"/&gt;
  &lt;/dwr:configuration&gt;

  &lt;bean id="productService" class="pl.jcommerce.example.dwr.service.ProductServiceDummyImpl"&gt;
    &lt;dwr:remote javascript="ProductService"&gt;
      &lt;dwr:include method="getProductByCode"/&gt;
    &lt;/dwr:remote&gt;
  &lt;/bean&gt;

&lt;/beans&gt;</pre>
<p style="text-align: justify">Do zdefiniowanego już wcześniej <em>beana</em> <strong>productService</strong> dodaję tag <em>dwr:remote</em> określając, że <em>bean</em>, którego to dotyczy ma być dostępny z poziomu <em>JavaScriptu</em> pod nazwą <em>ProductService</em> oraz, że interesuje mnie wywoływanie metody <em>getProductByCode()</em>.</p>
<p style="text-align: justify">Nie można także zapomnieć o tagu <em>dwr:configuration</em>, który jest wymagany niezależnie od tego, czy zawiera jakieś dodatkowe elementy. W moim przypadku określam, że klasa <em>Product</em> będzie transformowana z/do obiektu <em>JavaScript</em> przy użyciu dostępnych w niej <em>getterów</em>/<em>setterów</em>.</p>
<p style="text-align: justify">Pamiętać należy również o dodaniu nowej zależności do pliku <em>pom.xml</em>. Po tej operacji należy także ponownie wywołać <em>mvn eclipse:eclipse -DdownloadSources=true</em>.</p>
<pre class="prettyprint">
    &lt;dependency&gt;
      &lt;groupId&gt;org.directwebremoting&lt;/groupId&gt;
      &lt;artifactId&gt;dwr&lt;/artifactId&gt;
      &lt;version&gt;2.0.2&lt;/version&gt;
    &lt;/dependency&gt;</pre>
<h3>Testowanie DWR przy pomocy dostarczonych wraz z frameworkiem narzędzi</h3>
<p style="text-align: justify">Przyszedł czas na sprawdzenie, czy wszystko się powiodło. Wpisuję w przeglądarce adres <em>http://localhost:8080/dwr-example/dwr/</em>. Moim oczom ukazuje się lista znanych klas dla <strong>DWR</strong>:</p>
<pre class="prettyprint">
ProductService (pl.jcommerce.example.dwr.service.ProductServiceDummyImpl)</pre>
<p style="text-align: justify">Klikam na <em>ProductService</em> i uzyskuję dzięki temu dostęp do bardzo przyjemnego narzędzie pozwalającego na przetestowanie wywołania serwisu. Odnajduję metodę <em>getProductByCode()</em>, wpisuje jako argument jej wywołania <em>&#8220;CSS&#8221;</em> i klikam <em>Execute</em>.</p>
<p style="text-align: justify">W wyskakującym okienku (<em>alert()</em>) uzyskuje dokładne informacje o produkcie o kodzie <em>CSS</em>. Zatem wywołanie się powiodło :). Warto zauważyć, że także na konsoli <em>Jetty</em> widać wpis o wykonanym zapytaniu.</p>
<h3>Tworzenie strony HTML korzystającej z DWR</h3>
<p style="text-align: justify">Ostatnim już elementem tego <em>tutoriala</em> będzie utworzenie strony <em>HTML</em> umożliwiającej wyszukiwanie produktów po ich kodach bez konieczności przeładowania strony. Przykład trywialny, ale w tym wypadku wystarczający.</p>
<p style="text-align: justify">Ponieważ zamierzam korzystać z <em>JavaScriptu</em> wspomogę się biblioteką <strong>jQuery</strong>, która znacznie to ułatwia. Bibliotekę umieszczam w folderze <em>/src/main/webapp/script/js/</em>. Polecam bliższe zapoznanie się z tą biblioteką <em>JS</em>.</p>
<p style="text-align: justify">A teraz już źródło samej strony JSP oraz krótki opis tego, co się wewnątrz jej źródła dzieje.</p>
<pre class="prettyprint">
&lt;%@ page pageEncoding="UTF-8" %&gt;&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"&gt;

&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&gt;
  &lt;head&gt;
    &lt;title&gt;Product search&lt;/title&gt;

    &lt;script type="text/javascript" src="${pageContext.request.contextPath}/script/js/jquery-1.2.3.min.js"&gt;&lt;/script&gt;

	&lt;script type='text/javascript' src='${pageContext.request.contextPath}/dwr/interface/ProductService.js'&gt;&lt;/script&gt;
	&lt;script type='text/javascript' src='${pageContext.request.contextPath}/dwr/engine.js'&gt;&lt;/script&gt;

    &lt;script type="text/javascript"&gt;
    	// &lt;![CDATA[
    	var lastRequestId = 0;

    	function onProductReceived(product) {
    		if (product != null) {
    			$("#productDescription").show();
    			$("#invalidCode").hide();

    			$("#productCode").html(product.code);
    			$("#productName").html(product.name);
    			$("#productProducer").html(product.producer);
    			$("#productItemsAvailable").html(product.itemsAvailable);
    			$("#productPrice").html(product.price);

    			return;
    		}

    		$("#invalidCode").show();
    		$("#productDescription").hide();
    	}

    	$(document).ready(
    		function(){
    			$("#productDescription").hide();
    			$("#invalidCode").hide();
    			$("#productCodeInput").keyup(
    				function() {
    					var requestId = ++lastRequestId;

    					ProductService.getProductByCode($(this).val(), {
	    						callback: function(product) {
	    							if (requestId != lastRequestId) {
	    								return;
	    							} 

			    					onProductReceived(product);
			    				}
		    				}
		    			)
    				}
    			);
    		}
    	);
    	// ]]&gt;
    &lt;/script&gt;

  &lt;/head&gt;
  &lt;body&gt;
	&lt;p&gt;Enter product code &lt;input id="productCodeInput" type="text"/&gt;&lt;/p&gt;
	&lt;div id="productDescription"&gt;
		&lt;p&gt;Product code: &lt;span id="productCode"&gt;&lt;/span&gt;&lt;/p&gt;
		&lt;p&gt;Product name: &lt;span id="productName"&gt;&lt;/span&gt;&lt;/p&gt;
		&lt;p&gt;Producer: &lt;span id="productProducer"&gt;&lt;/span&gt;&lt;/p&gt;
		&lt;p&gt;Items available: &lt;span id="productItemsAvailable"&gt;&lt;/span&gt;&lt;/p&gt;
		&lt;p&gt;Price: &lt;span id="productPrice"&gt;&lt;/span&gt;&lt;/p&gt;
	&lt;/div&gt;
	&lt;div id="invalidCode"&gt;
		&lt;p&gt;&lt;strong&gt;You have chosen invalid code! Please choose another one.&lt;/strong&gt;&lt;/p&gt;
	&lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>
<p style="text-align: justify">W bloku <em>head</em> załączam źródło biblioteki <em>jQuery</em> oraz kod wygenerowany przez <strong>DWR</strong> będący naszym punktem dostępu do serwisu <em>ProductService</em>. Trochę niżej definiujemy funkcję <em>onProductChange</em>, która będzie wywoływana w momencie uzyskania odpowiedzi z serwisu. Jej zadaniem będzie podmiana części informacji na stronie zgodnie z aktualnie wprowadzonym przez użytkownika kodem produktu.</p>
<p style="text-align: justify">Zapytanie do serwisu wysyłam każdorazowo po tym jak zajdzie zdarzenie zwolnienia przez użytkownika klawisza. W <em>prawdziwych</em> aplikacjach całkowicie odradzam tą technikę, jednak dla celów tego artykułu jest ona wystarczająca.</p>
<p style="text-align: justify">Ponieważ użytkownik może z dosyć dużą częstotliwością powodować wysłanie żądań do serwisu musimy się zabezpieczyć przed sytuacją w której  nieaktualna odpowiedź nadpisze aktualną wartość. Do tego posłuży nam zmienna <em>requestId</em>. Przy każdorazowym odebraniu odpowiedzi z serwisu będziemy sprawdzali, czy nie zostało przypadkiem wysłane nowsze żądanie. W takim przypadku starsza odpowiedź zostanie przeze mnie zignorowana.</p>
<p style="text-align: justify">Gdybym nie potrzebował stosować wyżej opisanej techniki wywołanie serwisu mogłoby wyglądać jak poniżej.</p>
<pre class="prettyprint">ProductService.getProductByCode($(this).val(), onProductChanged);</pre>
<p style="text-align: justify">Aby całość dostępna była poprzez adres <em>http://localhost:8080/dwr-example/product/search.html</em> uzupełnię jeszcze plik <em>dispatcher-servlet.xml</em>.</p>
<pre class="prettyprint">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"&gt;

  	&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
  	  &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /&gt;
  	  &lt;property name="prefix" value="/WEB-INF/jsp/" /&gt;
  	  &lt;property name="suffix" value=".jsp" /&gt;
  	&lt;/bean&gt;

  	&lt;bean name="/product/search.html" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" /&gt;

&lt;/beans&gt;</pre>
<h2>Podsumowanie</h2>
<h3>Nieprzekonany?</h3>
<p style="text-align: justify"><strong>DWR</strong> jest dojrzałym frameworkiem. W tym artykule główną uwagę skupiłem na jego prostocie wykorzystywania w kontekście aplikacji webowej budowanej na <em>Springu</em>. Pokazałem zaledwie od czego nasza <em>zabawa</em> z <strong>DWR</strong> może się rozpocząć. Dla projektantów i programistów bardzo ważnym aspektem natomiast jest elastyczność rozwiązań z których się korzysta oraz możliwość łatwego ich dostosowania do własnych potrzeb. Przeglądając oficjalną dokumentację szybko można się zorientować, że <strong>DWR</strong> w tej dziedzinie stara się spełniać stawiane mu oczekiwania.</p>
<p style="text-align: justify">Nie poruszyłem w tym artykule żadnego zaawansowanego aspektu <strong>DWR</strong>, ale wierzę, że jeżeli zdecydujesz się na korzystanie z tego frameworka, to dzięki dobrze napisanej dokumentacji nie będziesz miał problemu z jego dostosowaniem.</p>
<h3>Odnośniki</h3>
<ol>
<li><a href="http://getahead.org/dwr">DWR</a></li>
<li><a href="http://jquery.com/">jQuery</a></li>
<li><a href="http://springframework.org/">Spring Framework</a></li>
<li><a href="http://www.mortbay.org/">Jetty</a></li>
<li><a href="http://maven.apache.org/">Maven</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2008/03/16/dwr-direct-web-remoting/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Context Path za pomocą Expression Language</title>
		<link>http://j2ee.pl/2007/04/20/context-path-za-pomoca-expression-language/</link>
		<comments>http://j2ee.pl/2007/04/20/context-path-za-pomoca-expression-language/#comments</comments>
		<pubDate>Fri, 20 Apr 2007 12:55:45 +0000</pubDate>
		<dc:creator>Michał Porzożyński</dc:creator>
				<category><![CDATA[JSP]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2007/04/20/context-path-za-pomoca-expression-language/</guid>
		<description><![CDATA[Bardzo często w aplikacjach webowych wykorzystujemy context path. Jest to właściwie jedyne rozsądne rozwiązanie aby dołączyć do strony JSP jakiś CSS czy choćby obrazek. Bardzo często w kodzie strony JSP widać rozwiązanie polegające na umieszczeniu w niej wyrażenia:
&#60;%= request.getContextPath %&#62;
Jako, że bardzo.. bardzo nie lubię kodu Java w JSP zawsze zamieniam takie kwiatki na elegancki.. [...]]]></description>
			<content:encoded><![CDATA[<p>Bardzo często w aplikacjach webowych wykorzystujemy context path. Jest to właściwie jedyne rozsądne rozwiązanie aby dołączyć do strony JSP jakiś CSS czy choćby obrazek. Bardzo często w kodzie strony JSP widać rozwiązanie polegające na umieszczeniu w niej wyrażenia:</p>
<pre class="prettyprint">&lt;%= request.getContextPath %&gt;</pre>
<p>Jako, że bardzo.. bardzo nie lubię kodu Java w JSP zawsze zamieniam takie kwiatki na elegancki.. choć odrobinę dłuższy EL:</p>
<pre class="prettyprint">${pageContext.request.contextPath}</pre>
<p>Oczywiście nie jest to żadne odkrycie.. jednak nie ściemniając dalej muszę powiedzieć, że ten wpis powstał tylko dlatego, że nie mogę z jakiegoś dziwnego powodu zapamiętać składni tego EL i prawie zawsze jak muszę go użyć sięgam do googla ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2007/04/20/context-path-za-pomoca-expression-language/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
