Články z kategorie 'Java'

Reverse Ajax s DWR, Spring, iBatis

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 maxWaitAfterWri­te. 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 getScriptSessi­onsToNotifyAbou­tNewMessage z třídy cz.vavru.test­.dwr.util.DwrWeb­ContextUtil. Ú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.directwebre­moting.WebCon­text 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.Chat­ServiceImpl.

@Transactional
public void addMessage(Message message) throws ChatServiceException {
        WebContext webCtx = WebContextFactory.get();
        // zjisteni aktualniho usera ze session
        User currentUser = (User) webCtx.getHttpServletRequest().getSession(true).getAttribute(
                        CHAT_USER_SES_ATTR);

        // nastaveni odesilatele a data
        message.setSender(currentUser);
        message.setDate(new Date());

        // vlozeni message do databaze
        messageDao.insertMessage(message);

        DwrWebContextUtil dwrUtil = new DwrWebContextUtil(WebContextFactory.get());
        // zjisteni vsech scriptsession, ktere mame notifikovat o nove zprave
        Collection<ScriptSession> scriptSessions = dwrUtil
                        .getScriptSessionsToNotifyAboutNewMessage(message);

        logger.info("Sending info about new message to " + scriptSessions.size() + " users");

        Util util = new Util(scriptSessions);
        // timto zpusobem se vola primo kod na strane klienta
        // nasledujici radek tedy zavola javascriptovou funkci addMessage (viz soubor js/chat.js) s parametrem message
        // objekt message, ze samozrejme preveden do javascriptoveho sveta
        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 Přidat komentář 6. July 2008

Jak jsem (ne)pochopil REST

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/deta­il.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:

  • URL
  • POST dat
  • cookies

A naprosto stejně to funguje i s RESTem. Když budeme mít resource na adrese http://vavru.cz/eshop/vyt­vorit-kosik/, může odpověď vypada například takto – http://vavru.cz/eshop/ko­sik/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/ko­sik/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 12 komentářů 28. February 2008

DWR - AJAX knihovna pro remotování Java objektů

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 13 komentářů 7. September 2007

Dynamické PDF pomocí JasperReports, iReport a Spring Frameworku

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 5 komentářů 12. June 2007

Jsem certifikovaný

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 4 komentářů 6. June 2007

Pár střípků o JavaFX

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 3 komentářů 15. May 2007

Jak mě potrápil jeden detached objekt

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 {
        ...
        /** Method forms a copy of an existing Owner for editing */
        protected Object formBackingObject(HttpServletRequest request) throws ServletException {
                // get the Owner referred to by id in the request
                return getClinic().loadOwner(RequestUtils.getRequiredIntParameter(request, "ownerId"));
        }
        /** Method updates an existing Owner. */
        protected ModelAndView onSubmit(Object command) throws ServletException {
                Owner owner = (Owner) command;
                // delegate the update to the Business layer
                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ář:

  1. V session A naloadujete objekt A s ID např 1 (vznikne tak vzpomínaný detached objekt)
  2. 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 NonUniqueObjec­tException. 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 1 komentář 30. April 2007

Hibernate Synchronizer - pozor na UserType

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 MonetaryAmountU­serType 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 2 komentářů 23. April 2007

Spring web flow - framework pro management toku web aplikace

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:

  1. klepnutí na tlačítko objednat
  2. ověření zda je uživatel přihlášený
    1. pokud je uživatel přihlášen jdeme dále
    2. 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)
  3. potvrzení objednávky
  4. 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 4 komentářů 6. April 2007

Property Editory ve Spring Frameworku

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.sprin­g.sample.busi­ness.vo.Compa­ny, 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.busines­s.vo.Country vypadá následovně:

Celý článek 1 komentář 22. March 2007

Starší články


Kalendář

March 2024
M T W T F S S
« Jan    
 123
45678910
11121314151617
18192021222324
25262728293031

Články podle měsíců

Kategorie

Locations of visitors to this page