Články z kategorie 'Java'
Před nějakým časem se v Avedyi rozjížděl nový projekt. Jednalo
se o klasický webový chat. Vytvořil jsem tehdy jednoduchý prototyp.
Použil jsem DWR a technologii reverse ajax.
Pro tento článek jsem původní prototyp trochu rozšířil a zapojil jsem
Spring Framework a jako DAO vrstvu jsem vybral iBatis.
Krátce o iBatisu
I když iBatis není plnotučné ORM s klidem bych ho nasadil na
většinu projektů, na které jsem v minulosti použil Hibernate.
Stručný přehled vlastností a featur iBatisu:
- Konfigurace v XML podobně jako Hibernate.
- Veškeré SQL příkazy (insert, update, select) jsou nadefinovány přímo
v XML konfigurácích. V nich definujete placeholdery, které jsou
při vykonávání nahrazeny skutečnými hodnotami.
- Umí relace (1:1, 1:n, m:n)
- má vlastní kešování (kongurace opět v xml)
iBatis mě nadchnul a původně jsem o něm chtěl napsat krátký
článek. Ale když jsem viděl kolik zdrojů na (i českém) internetu je
rozmyslel jsem si to. Seznam zdrojů o iBatisu uvádím na konci
článku.
Krátce o DWR
O DWR jsem z na blogu již psal.
V tomto článku bych se blížeji podíval pouze na typy reverse ajaxu,
které nabízí.
Full Streaming Mode
Nejrychlejší způsob reverse ajaxu. Spojení zůstává otevřeno po dobu
60 sekund. Poté je vytvořeno nové (což se nemusí podařit pokud
browser již není otevřený např). Má dvě nevýhody:
- velká zátěž serveru (při velkém počtu klientů)
- proxy, antivirové program a různé moduly webserveru mohou držet data do
doby než se spojení ukončí (k zobrazování dat by pak docházelo pouze
jednou za 60 sekund)
Early Closing Mode (Long Polling)
Funguje tak, že server zavře spojení s klientem a vyžádá si
spojení nové v případě, že klientovi posíláme nějaká data.
Jestliže data neposíláme je chování stejné jako u Full Streaming
modu. Spojení s klientem není uzavřeno ihned, ale lze jej konfigurovat
pomocí parametru maxWaitAfterWrite
. Typicky napstaveno na
500 ms. Server v tomto případě pošle klientovi zprávu, počtu
500 ms a poté ukončí a znovu otevře spojení s klientem.
Výhodou je odolnost vůči držení dat na straně proxy atd. Nevýhodou je
opět velká zátěž serveru.
Polling Mode
Polling Mode bych pravým reverse ajaxem ani nenazýval. Spočívá
v periodickém dotazování serveru klientem. Směr volání je klient
→ server, což je opakem předchozích dvou možností.
Full Streaming Mode je představitelem technologie
Comet – tzv. spojení mezi serverem a klientem
s dlouhou délkou života.
Příklad
Příkladem je jednochuchý chat. Základní usecasy jsou:
- nalogování uživatele
- zjištění aktuálního uživatele ze session
- odlogování
- poslání nového vzkazu (buď všem v chatu nebo jednomu
adresátovi)
Klient
Klientem je statická html stránka (index.html), která dělá dotazy na
server pomocí js souboru. V něm je volán DWR servlet. Pro komfort při
práci se stránou je použita i knihovna jQuery.
Server
Serverovou částí je javovská webové aplikace běžící
v libovolném servlet kontajneru. Jediným endpointem je DWR servlet. Jako
IOC kontajner je použit Spring Framework. Obsahuje jednu remotnutou servisní
beanu – chatService. Jsou zde dva doménové objekty
– User
a Message
.
Soubor dwr.xml
obsahující konfiguraci remotnuté servisy a
bean convertor pro doménové objekty:
<dwr>
<allow>
<!-- configure service -->
<create creator="spring" javascript="ChatService" scope="application">
<param name="beanName" value="chatService"/>
</create>
<!-- configuje bean converter -->
<convert converter="bean" match="cz.vavru.test.dwr.domain.*"/>
</allow>
</dwr>
Soubor Message.xml
s iBatis mapováním:
<sqlMap namespace="Message">
<typeAlias alias="message" type="cz.vavru.test.dwr.domain.Message"/>
<resultMap id="result" class="message">
<result property="messageId" column="messageId"/>
<result property="date" column="date" />
<result property="message" column="message"/>
<result property="sender.userId" column="senderId"/>
<result property="sender.nick" column="senderNick"/>
<result property="recipient.userId" column="recipientId"/>
<result property="recipient.nick" column="recipientNick"/>
</resultMap>
<select id="getMessages" resultMap="result">
select * from Message where recipientId is null or senderId = #userId# or recipientId = #userId#
</select>
<insert id="insertMessage">
insert into Message set date = #date#, senderId = #sender.userId#, senderNick = #sender.nick#, recipientId = #recipient.userId#, recipientNick = #recipient.nick#, message = #message#
<selectKey resultClass="int" keyProperty="messageId">
select last_insert_id() as messageId
</selectKey>
</insert>
</sqlMap>
Metoda getScriptSessionsToNotifyAboutNewMessage
z třídy
cz.vavru.test.dwr.util.DwrWebContextUtil
. Úkolem
metody je vrátit kolekci objektů ScriptSession
, které mají být
notifikovány o nově příchozí zprávě. Jak je z kódu vidět
v případě, že je vybraný adresář je notifikace poslána jenom
odesílateli nebo adresátovi. Proměnná webCtx
je interface
org.directwebremoting.WebContext
obsahují např odkaz
na aktuální ScriptSession
(obdoba HttpSession). Na rozdíl od
HttpSession
vzniká nová ScriptSession
s každým obnovením stránky (F5 v prohlížeči). Ohromnou výhodou
tohoto objektu je možnost uložit si do něj libovolný atribut. Já do něj
při zalogování ukládám informace o uživateli. A tak později
přesně vím, které scriptsešný mám zavolat:
@SuppressWarnings("unchecked")
public Collection<ScriptSession> getScriptSessionsToNotifyAboutNewMessage(Message message) {
Collection<ScriptSession> pageScriptSessions = (Collection<ScriptSession>) webCtx
.getScriptSessionsByPage(currentPage);
Collection<ScriptSession> scriptSessions = new ArrayList<ScriptSession>();
if (message.getRecipient() != null) {
for (Iterator<ScriptSession> it = pageScriptSessions.iterator(); it.hasNext();) {
ScriptSession scriptSession = it.next();
User user = (User) scriptSession.getAttribute(ChatServiceImpl.SCRIPT_CHAT_USER_SES_ATTR);
if(user == null) continue;
if (message.getSender().getUserId() == user.getUserId()
|| message.getRecipient().getUserId() == user.getUserId()) {
scriptSessions.add(scriptSession);
}
}
} else {
scriptSessions = pageScriptSessions;
}
return scriptSessions;
}
Posledním fragmentem kódu je metoda addMessage
z třídy
cz.vavru.test.dwr.service.ChatServiceImpl
.
@Transactional
public void addMessage(Message message) throws ChatServiceException {
WebContext webCtx = WebContextFactory.get();
User currentUser = (User) webCtx.getHttpServletRequest().getSession(true).getAttribute(
CHAT_USER_SES_ATTR);
message.setSender(currentUser);
message.setDate(new Date());
messageDao.insertMessage(message);
DwrWebContextUtil dwrUtil = new DwrWebContextUtil(WebContextFactory.get());
Collection<ScriptSession> scriptSessions = dwrUtil
.getScriptSessionsToNotifyAboutNewMessage(message);
logger.info("Sending info about new message to " + scriptSessions.size() + " users");
Util util = new Util(scriptSessions);
util.addFunctionCall("addMessage", message);
}
Celý příklad lze stáhnout zde – dwr-ajax.zip (zip, 9.9 MB). Archiv
obsahuje:
- zdrojové soubory (celý Eclipse projekt)
- dwr-ajax.sql s DDL
- war archiv
Závěr
Věřím, že se mi povedlo ukázat jak je spojení všech použitých
knihoven naprosto bezbolestné a jednoduché. Při testech na mém notebooku,
kdy jsem si v každém prohlížeči (IE, Opera, Mozilla) otevřel chat a
vstoupil pod jiným uživatelem, byl celý chat pekelně rychlý. Zpráva byla
zobrazena takřka okamžitě.
Odkazy
Celý článek 6. July 2008
S křížkem po funusu ale přece! V tomto článku bych chtěl
několika větami okomentovat :lednovou přednášku":http://www.java.cz/detail.do?…
Jakuba Podlešáka Java API
pro RESTful web services. Po obyčejném blogování se mi už pekelně
stýskalo. Od půlky prosince totiž nedělám nic jiného než že se snažím
přivést k životu naše kontaktní
čočky.
REST
REST chápu jako soubor pravidel pro manipulaci s daty po síti
(zpravidla pomocí HTTP protokolu). V RESTu se pracuje se resourci –
zdroji. Každý zdroj má svoji unikátní adresu. Pomocí volání adresy
zdroje s ním lze provádět operace. Od prostého načtení po
vytvoření, modifikaci až po smazání. Kromě zavolání zdroje pomocí
adresy (URL) lze do těla požadavku zabalit další data – například
pro vytvoření nového zdroje. Data mohou být v různé formě –
např XML, JSON, plain text…
REST naopak nedefinuje autentizaci a autorizaci uživatelů. REST je
bezstavový.
Jak je to s tou stavovostí RESTu?
A právě o stavovosti RESTu bych se chtěl zamyslet. Na
přednášce proběhla vášnivá debata na téma stavovost RESTu. Padly zde
názory, že když pracuju s webovou aplikací používající REST a
uložím nový zdroj, tak se přece musí jednat o stavové chování.
Vždyť se přece změnil stav aplikace.
Výše uvedený názor je nesmysl. Se stavovostí RESTu je to stejně
jako se stavostí HTTP protokolu – je nestavový. Uvedu na
jednoduchém příkladu. Tím příkladem jsou sessions.
Příklad se sessions
Sessions fungují tak, že server přibalí do odpovědi klienta unikátní
idenfikátor, který označuje session id. Toto cookies se pak přenáší při
další komunikaci mezi serverem a klientem. Klient session id přibaluje buď
do:
A naprosto stejně to funguje i s RESTem. Když budeme mít
resource na adrese http://vavru.cz/eshop/vytvorit-kosik/
,
může odpověď vypada například takto –
http://vavru.cz/eshop/kosik/wsdei9012309a/
. Dostali
jsme zpět adresu na nově vytvořený košík. Když pak klient chce
s tím to košíkem (každý klient má svůj košík) musí uvést celou
adresu košíku. Takže pro přidání nové položky bychom mohli použít
například takovýhle odkaz –
http://vavru.cz/eshop/kosik/wsdei9012309a/pridat-produkt/
a v těle požadavku specifikovat o jaký produkt se jedná a
například počet kusů.
Zdá se vám to jednoduché?
Mně taky. Proto nechápu tolik případů nepochopení ze strany
posluchačů. Možná jsem to celé jenom špatně pochopil a chyba je na mé
straně. V tom případě prosím nějakého zkušeného RESTovače, aby
mě například pomocí komentáře přivedl na správnou cestu.
Celý článek 28. February 2008
Pomocí DWR můžete volat Javovský kód přímo z Javascriptu
z prostředí internetového prohlížeče na klientském počítači. DWR
se samo postará o vykonání asynchronního požadavku na server a převod
objektů z javovského světa do javascriptového.
Kromě toho má DWR sadu Utilit, které pomáhají
v manipulaci s odesíláním a zpracováním příjímaných dat
– plnění selektu daty, přidávání řádků do tabulky atd.
Celý článek 7. September 2007
V dnešním článku přiblížím tvorbu dymických PDF dokumentů
pomocí JasperReports, iReport a Spring frameworku. V článku uvedu
základy JasperReports. Následovat bude seznámení s návrhářem
iReport a nakonec ukážu integraci se Spring Frameworkem.
Celý článek 12. June 2007
Tak jsem dnes úspěšně složil sunovský certifikát – jsem Sun
Certified Programmer for the Java 2 Platform, Standard Edition 5.0.
Jelikož jsem zkoušku skládal v Gopasu, kde pracuji, stačilo se pouze přesunout
z naší kanceláře o pár metrů dál do testovací místnosti.
Na zkoušku jsem se připravoval poslední dva týdny. Větší část
v nemocnici a
minulý víkend. Moje Kačenka mě neustále obletovala (rozuměj nosila
lahodné nápoje a potraviny) a často opakovala, že se jí líbí, když se
učím, protože jsem u toho hodnej:).
No jak je vidět příprava na zkoušku prospěla všem – Kačenka si
užila pár příjemných večerů ve společnosti hodného Vlasty.
A Vlasta si díky výsledku zkoušky, který zněl pass,
ověřil, že jeho samostudiem nabité znalosti Javy nejsou úplně
k zahození.
Někomu by při přípravě na tuto zkoušku mohla pomoci literatura a
další zdroje, které jsem používal:
Celý článek 6. June 2007
Tak to vypadá, že je AJAXu odzvoněno. Alespoň takhle to prezentuje Sun.
Na konferenci JavaOne Sun oznámil zrození nové RIA technologie –
JavaFX.
Pár střípků o JavaFX
- stačí doinstalova malou knihovnu a JavaFX aplikace poběží na všech
přístrojích (počítačích, mobilních telefonech), kde je nainstalována
Java SE nebo Java ME. V případě mobilních přístrojů je to
kompletní operační systém, který zahrnuje linuxový kernel a nativní
servisy.
- není vidět zdrojový kód aplikace tak jak je tomu v případě
AJAXu, který je realizován klientským javasriptem
- JavaFX aplikaci lze používat i v offline módu
- používá vlastní skriptovací jazyk – JavaFX Script
- odpadá problém s kompatilitou javascriptového kódu pro různé
prohlížeče jak je to mu u AJAXu
- JavaFX aplikace splňují heslo write once and run anywhere
(napiš jednou a spušť kdekoliv). Stejný skript bude tedy možné spouštět
na PC, digitální TV a mobilních telefonech.
- JavaFX Script (původní jméno F3)) je staticky
typovaný. Má compile-time kontrolu kódu. Lze v něm používat java
kód – importovat třídy, vytvářet objekty…
- součástí prvního releasu JavaFX bude interaktivní GUI builder
(v současnosti již hotov)
- co se týče deploymentu JavaFX na klienty chystá Sun nový model –
základní balík knihoven bude velmi malý a další potřebné části se
budou doinstalovávat „lazy“.
Konkurenti JavaFX
- AJAX
- rodina technologií, které mají společní název AJAX (Asynchronous
JavaScript and XML) a umožňují asynchronní volání zdrojů na serveru na
pozadí klasické HTML stránky.
- Apollo
- projekt Apollo
pochází z dílny Adobe.
Apollo is the code name for a cross-operating system runtime being developed
by Adobe that allows developers to leverage their existing web development
skills (Flash, Flex, HTML, JavaScript, Ajax) to build and deploy rich Internet
applications (RIAs) to the desktop.
- Macromedia Flash
- Macromedia Flash není
přímým konkurentem JavaFX. Flash byl zpočátku používán na vytváření
animací. Později dostal dobrou podporu pro práci s daty. Ovšem co se
robustnosti nelze jej s Javou srovnávat.
- SilverLight
- Projekt SilverLight pochází
z dílny Microsoftu.
Microsoft® Silverlight™ is a cross-browser, cross-platform plug-in for
delivering the next generation of .NET based media experiences and rich
interactive applications for the Web. Silverlight offers a flexible programming
model that supports AJAX, VB, C#, Python, and Ruby, and integrates with existing
Web applications. Silverlight supports fast, cost-effective delivery of
high-quality video to all major browsers running on the Mac OS or Windows.
Odkazy
Celý článek 15. May 2007
Známe to všichni – přijdete ráno do práce a máte za úkol
naimplementovat nějaký webový formulář v aplikaci, která používá
Spring Framework a Hibernate.
Už v sample aplikaci Petclinic, která
je součástí distribuce Spring Frameworku je vidět jak na to:
public class EditOwnerForm extends AbstractClinicForm {
...
protected Object formBackingObject(HttpServletRequest request) throws ServletException {
return getClinic().loadOwner(RequestUtils.getRequiredIntParameter(request, "ownerId"));
}
protected ModelAndView onSubmit(Object command) throws ServletException {
Owner owner = (Owner) command;
getClinic().storeOwner(owner);
return new ModelAndView(getSuccessView(), "ownerId", owner.getId());
}
}
Zjednodušeně slovy:
Nechť je formBacking
objekt naloadován z fasády pomocí
metody loadOwner
(a tady vzniká detached objekt). Po odeslání
(a případně validaci) nechť je editovaný (stále mluvíme o našem
detached objektu) uložen do databáze pomocí metody
storeOwner
.
Vše funguje skvěle až do chvíle, kdy nastane tento scénář:
- V session A naloadujete objekt A s ID např 1 (vznikne tak
vzpomínaný detached objekt)
- V session B (vzniká při odeslání formuláře) dojde
k inicializaci objektu A s ID 1 (tedy toho samého objektu jež
právě editujete).
Hibernate vyhodí nepěknou NonUniqueObjectException
.
A dobře dělá – který z dvou objektů typu A, oba s ID
1 je ten pravý.
K tomuto scénáři může dojít zcela jednoduše a hlavně na první
pohled z nevysvětlitelných důvodů. Například díky řetězci
několika many-to-one asociací. V mém případě k tomu došlo při
zavolání metody setAsText(String text)
v jednom z property
editorů. A k tomu dochází ještě před validací a uložením
editovaném objektu.
Nejdřívě mě napadlo vyřešit to lazy loadingem many-to-one asociací.
Při bližším prostudování dokumentace Hibernatu zjistíme, že
asociace many-to-one nejsou defaultně lazy. Ani pomocí
atributu outer-join to nezměníte. Pouze řeknete, zda se má
použít join (outer-join=„true“), samostatný sql dotaz
(outer-join=„false“) a nebo zda se objekt fetchne v rámci
joinu nebo lazy (outer-join=„auto“ – defaultní hodnota).
K lazy loadu může dojít pouze když má objekt definovanou proxy.
Ovšem tohle řešení je hodně ugly…krom toho to řeše problém pouze
u vazech many-to-one.
Použité řešení bylo nakonec jiné – při ukládání objektu do
databáze udělat něco takového:
protected ModelAndView onSubmit(Object command) throws ServletException {
Owner owner = (Owner) command;
Owner detachedOwner = getClinic().loadOwner(owner.getId().intValue());
BeanUtils.copyProperties(detachedOwner, owner);
getClinic().storeOwner(owner);
return new ModelAndView(getSuccessView(), "ownerId", owner.getId());
}
Provedli jsme nové naloadování editovaného objektu. Pokud již Hibernate
v této session má tento objekt fetchnutý zafunguje first level cache a
dojde pouze k vrácení odkazu na daný objekt bez jeho druhého
loadování z db. Poté zkopírujeme vlastnosti ze změněného objektu do
čertvě fetchnutého. Nakonec jej uložíme.
Závěr
Článkem jsem chtěl poukázat na to, že i když nám Hibernate život
hodně zjednodušuje, je pořád dost věcí, na které je potřeba dávat
pozor, a které dokážou pěkně potrápit (v tomto případě
2 hodiny).
Celý článek 30. April 2007
Při čtení článku Schéma
databáze – používáme hibernate mě napadlo, abych napsal
o jednom problému, který souvisí s generováním POJOs
z mapovacích souborů pomocí Hibernate
Synchronizeru v případě používání vlastních typů
(UserTypes).
Hibernate umožňuje psaní vlastních typů – takzvaných
UserTypes.Mohou být buď jednoduché (skalární –
s jednou vlastností) – typ UserType nebo kompozitní
– CompositeUserType (více vlastností).
Ukažme si na příkladu použití kompozitního UserTypu:
package cz.vavru.sample.hibernate;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Currency;
import net.sf.hibernate.CompositeUserType;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.engine.SessionImplementor;
import net.sf.hibernate.type.Type;
import cz.vavru.sample.hibernate.MonetaryAmount;
public class MonetaryAmountType implements CompositeUserType {
public Class returnedClass() {
return MonetaryAmount.class;
}
...
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session,
Object owner) throws SQLException {
double value = resultSet.getDouble(names[0]);
if (resultSet.wasNull())
return null;
Currency currency = Currency.getInstance(resultSet.getString(names[1]));
return new MonetaryAmount(new Double(value), currency);
}
public void nullSafeSet(PreparedStatement statement, Object value, int index,
SessionImplementor session) throws SQLException {
if (value == null) {
statement.setNull(index, Hibernate.BIG_DECIMAL.sqlType());
statement.setNull(index + 1, Hibernate.CURRENCY.sqlType());
} else {
MonetaryAmount amount = (MonetaryAmount) value;
String currencyCode = amount.getCurrency().getCurrencyCode();
statement.setDouble(index, amount.getValue().doubleValue());
statement.setString(index + 1, currencyCode);
}
}
...
}
Příslušný doménový objekt MonetaryAmount
vypadá
následovně:
package cz.vavru.sample.hibernate;
import java.io.Serializable;
import java.util.Currency;
import java.util.Iterator;
public class MonetaryAmount implements Serializable {
private static final long serialVersionUID = Long.MIN_VALUE * 34;
private Double value;
private final Currency currency;
public MonetaryAmount(Currency currency) {
value = new Double(0d);
this.currency = currency;
}
public MonetaryAmount(BigDecimal bigDecimal, Currency currency) {
this.value = new Double(bigDecimal.doubleValue());
this.currency = currency;
}
public MonetaryAmount(Double value, Currency currency) {
this.value = value;
this.currency = currency;
}
public Currency getCurrency() {
return currency;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof MonetaryAmount))
return false;
final MonetaryAmount monetaryAmount = (MonetaryAmount) o;
if (!currency.equals(monetaryAmount.currency))
return false;
if (value != monetaryAmount.value)
return false;
return true;
}
public int hashCode() {
int result;
result = 29 * value.intValue() + currency.hashCode();
return result;
}
public String toString() {
return "Value: '" + getValue() + "', " + "Currency: '" + getCurrency() + "'";
}
}
A ukázka využití v mapovacím souboru jiného doménového
objektu, který MonetaryAmount
používá:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<hibernate-mapping>
<class name="cz.vavru.sample.hibernate.MyEntity"
table="ccg_pg_yearly_settings" >
<id name="id" type="java.lang.Integer" column="id">
<generator class="increment" />
</id>
...
<property name="budget" not-null="false"
type="cz.vavru.sample.hibernate.MonetaryAmountType">
<column name="budget_amount" />
<column name="budget_currency" />
</property>
</class>
</hibernate-mapping>
Kód, který Hibernate Synchronizer vygeneruje nesprávně používá pro
vlastnost budget
typ MonetaryAmountUserType
místo správného MonetaryAmount
.
package cz.vavru.sample.hibernate;
public class MyEntity implements Serializable {
...
private cz.vavru.sample.hibernate.MonetaryAmountType budget;
public cz.vavru.sample.hibernate.MonetaryAmountType getBudget () {
return budget;
}
public void setBudget (cz.vavru.sample.hibernate.MonetaryAmountType budget) {
this.budget = budget;
}
...
}
Správný kód je tedy:
package cz.vavru.sample.hibernate;
public class MyEntity implements Serializable {
...
private cz.vavru.sample.hibernate.MonetaryAmount budget;
public cz.vavru.sample.hibernate.MonetaryAmount getBudget () {
return budget;
}
public void setBudget (cz.vavru.sample.hibernate.MonetaryAmount budget) {
this.budget = budget;
}
...
}
Přiznám se, že mi odhlaní tohoto problému zabralo asi hodinu.
Odkazy
Celý článek 23. April 2007
Dnes existuje spousta MVC frameworků, které vám dovedou zařídit skvělé
(rozuměj flexibilní) routování. Světem webu dnes vládnou nice URL`s,
přístupnost atd…V některých případech však požadujete něco
zcela jiného. Například taková registrace uživatelů nebo odesílání
objednávky. Takovéto procesy bývají rozděleny do několika kroků a bývá
zcela klíčové zajistit, aby se uživatel do každého kroku procesu mohl
dostat pouze námi definovanými cestami. Při odesílání objednáky
z e-shopu je jeden z možných scénářů takovýto:
- klepnutí na tlačítko objednat
- ověření zda je uživatel přihlášený
- pokud je uživatel přihlášen jdeme dále
- pokud není přihlášen nabídneme přihlašovací fomulář (a zde opět
mohou nastat dva stavy – uživatel již je nebo není
zaregistrován)
- potvrzení objednávky
- objednávka je odeslána
Během tohoto procesu je nutné nějak ošetřit, že jsou nastaveny všechny
potřebné údaje a jednoduše řešeno – systém je v takovém stavu
v jakém ho potřebujeme mít. Můžeme zvolit svoje proprietární
řešení a vše si ošetřovat například pomocí session nebo použít
SWF. Pomocí SWF můžeme
nadefinovat business procesy pomocí toků (flows), ve kterých můžeme
nadefinovat jednotlivé stavy procesů, možné přechody z jednoho stavu
do druhého a akce a podmínky, které tento přechod provází. Pomocí SWF
vlastně provádíme abstrakci našich business procesů a zvyšujeme tím
jejich přenositelnost. Veškerá logika pro řízení toku je soustředěna na
jednom místě a ne rozeseta na x místech kódu.
Celý článek 6. April 2007
Dnešní článek bych chtěl věnovat property
editorům a zvláště jejich používání ve Spring Frameworku.
K čemu slouží property editory
Představte si následující případ – máte doménový objekt
cz.vavru.spring.sample.business.vo.Company
,
který je deninován:
package cz.vavru.sample.spring.business.vo;
public class Company {
private int id;
private Country country;
private java.util.Currency currency;
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
public java.util.Currency getCurrency() {
return currency;
}
public void setCurrency(java.util.Currency currency) {
this.currency = currency;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Vidíme, že se jedná o klasickou JavaBeanu. Referencování
třída cz.vavru.sample.spring.business.vo.Country
vypadá následovně:
Celý článek 22. March 2007
Starší články