Apache Struts (2) - instalace, konfigurace, aplikace

Instalujeme JBoss, rozvržení nové aplikace, konfigurace pomocí souborů web.xml a struts.xml

25.2.2005 06:00 | Miroslav Holubec | přečteno 18896×

Instalujeme

Jelikož mi přišlo několik dotazů, jak správně nainstalovat aplikační server a ostatní potřebné komponenty, bude úvod článku věnován stručnému návodu. Nejprve si z internetu stáhněte J2EE server JBoss. Ten posléze někam rozbalte (zde do /usr/local/share), udělejte symbolické linky do adresáře usr/local/bin a nakonec nastavte proměnou JBOSS_HOME (je dobré ji definovat již někde v starovacích skriptech, nebo ji přidat přímo do run.sh).

tar -xvf jboss-4.0.1.tar.bz2 --use-compress-program bzip2 -C /usr/local/share/
ln -s /usr/local/share/jboss-4.0.1/bin/run.sh /usr/local/bin/jboss.sh
export JBOSS_HOME=/usr/local/share/jboss-4.0.1/

Pokud máte správně nainstalovaný Java Development Kit a správně nastavenou proměnou JAVA_HOME, tak již nic nebrání spuštění samotného serveru příkazem jboss.sh. Pokud se po chvíli čekání objeví podobné hlášení jako je níže, je vyhráno.

13:03:22,808 INFO  [Http11Protocol] Starting Coyote HTTP/1.1 on http-0.0.0.0-8080
13:03:23,013 INFO  [ChannelSocket] JK2: ajp13 listening on /0.0.0.0:8009
13:03:23,114 INFO  [JkMain] Jk running ID=0 time=0/131  config=null
13:03:23,148 INFO  [Server] JBoss (MX MicroKernel) [4.0.1 (build: CVSTag=JBoss_4_0_1
                   date=200412230944)] Started in 35s:959ms

O tom, že server doopravdy běží, se můžeme přesvědčit, pokud do prohlížeče zadáme adresu http://localhost:8080/.

Webové aplikace J2EE

Každá webová aplikace vyvíjená pod J2EE musí dodržovat určitá specifika, týkající se především adresářové struktury a konfiguračních souborů. Jejich primárním cílem je spuštění aplikace pod jakýmkoliv J2EE serverem bez nutnosti jeho speciální konfigurace. Aplikace je pak nezávislá nejen na cílové platformě (což je výsada javy), ale též na prostředí, ve kterém je spouštěna. Adresářová struktura typické webové aplikace vypadá takto:

Application
  ├ pages   - jsp stránky 
  ├ theme   - css styly
  ├ images  - obrázky
  ├ scripts - java scripty
  └ WEB-INF ┬ lib     - externí knihovny a soubory jar
            ├ classes - zkompilovaná aplikace  
            ├ web.xml - web deployment descriptor - hlavní konfigurační soubor
            └ další konfigurační soubory a knihovny tagů (značek)

Všimněte si především předepsaného adresáře WEB-INF, jenž skrývá konfiguraci a zkompilované soubory class. Aplikační server do něho zakazuje http klientům přístup, tudíž je to vhodné místo i pro jsp stránky. Pokud používáte externí knihovny (např. Struts), umístěte je do adresáře WEB-INF/lib a jejich konfiguraci (soubory xml a tld) přímo do WEB-INF. Aplikace se přenáší v balíku nazvaném web application archive (WAR), což je podoba archivu JAR, používaného u běžných aplikací. Aplikační kontejnery (servery) s těmito snadno přenositelnými soubory umí snadno pracovat, např. chcete-li spustit aplikaci pod JBOSSem, stačí dotyčný soubor WAR nakopírovat do adresáře $JBOSS_HOME/server/default/deploy/ a kontejner se o zbytek postará sám.

Rozdělení MVC v Apache Struts

Struts implementují části View a Controller. Aplikační logiku (alias Model) si samozřejmě musíte implementovat sami. V části View nabízejí především knihovnu uživatelských značek, jenž usnadňují tvorbu formulářů, zobrazování dat z kolekcí, atd. V části Controller poskytují vlastní servlet (org.apache.struts.action.ActionServlet), jenž jakmile přijde uživatelský request (požadavek), přesměruje ho na pomocnou třídu, která ví, jak vykonat aplikační logiku asociovanou s vyžádanou akcí. Tyto pomocné třídy (patří ještě do části controller aplikace) jsou potomky třídy org.apache.struts.Action a představují most mezi klientskou akcí a samotnou aplikační logikou. Servlet se dále stará o lokalizaci, správu session a inicializaci datových zdrojů.

Struts MVC
Obrázek 1: Rozdělení MVC ve Struts

Web Deployment Descriptor

Důležitou součástí každé J2EE aplikace je soubor web.xml (web deployment descriptor). Z něho si server přečte prvotní konfiguraci aplikace, především inicializační parametry, deklarace servletů a jejich mapování, cesty ke knihovnám značek (soubory tld) a odkazy na JNDI (databázové zdroje). Myslím, že další popis není třeba, soubor je čitelný sám o sobě.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app
  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
  <display-name>LinuxSoft Shop</display-name>
  
  <!-- standartní Servlet Struts -->
  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
      <!-- cesta ke konfiguračnímu souboru Struts -->
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <!-- automatické spuštění -->
    <load-on-startup>1</load-on-startup>
  </servlet>


  <!-- mapování akcí -->
  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>/do/*</url-pattern>
  </servlet-mapping>


  <!-- pokud nezadáme cestu k souboru, servlet pošle index.jsp -->
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>


  <!-- knihovny značek Struts -->
  <taglib>
    <taglib-uri>/tags/struts-bean</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>/tags/struts-html</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>/tags/struts-logic</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>/tags/struts-nested</taglib-uri>
    <taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>/tags/struts-tiles</taglib-uri>
    <taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
  </taglib>

</web-app>

Konfigurace Struts

Konfigurace Apache Struts obstarává jediný konfigurační soubor struts-config.xml. Ten se skládá z několika částí:

Pro snadnější editaci konfigurace Struts je vhodné si stáhnout software Struts Console, který ze zadaných parametrů automaticky vytvoří xml. Jelikož se budu k tomuto souboru ještě často vracet, nechám prozatím jeho stručnější popis plavat a popíši jej při bližším zkoumání jednotlivých komponent rámce.

Popojedem - Aplikační logika

Nyní již můžeme začít budovat naší první virtuální aplikaci - eshop serveru linuxsoft.cz. Zatím implementujeme pouze jednoduchou logiku přihlašování uživatelů. Ta je reprezentována třídou Service v balíku cz.linuxsoft.web.authentification.

package cz.linuxsoft.web.authentification;

import cz.linuxsoft.web.exceptions.InvalidUserException;
import cz.linuxsoft.web.struts.shop.dto.User;

public class Service {
    
    public User validate(User user) throws InvalidUserException {
        //zde bude v reálu ověření proti databázi nebo proti LDAP serveru
        //databázové opera přijdou ovšem do jiné třídy (v rámci znovupoužitelnosti)
        if (user.getUsername().equalsIgnoreCase("franta") 
	    && user.getPassword().equals("franta")) 
	{
            user.setRealName("Franta Jedlička");
            user.setUserId(5);
            return user;
        }
        throw new InvalidUserException();
    }
}

Třída Service obsahuje jedinou metodu validate(),které se předává DTO objekt User. DTO je zkratka pro Data Transfer Object a jedná se o jednoduchou třídu JavaBean, která má pouze metody get a set pro své členy. Třídy DTO NESMĚJÍ provádět žádnou logiku, jsou určené jenom k přenosu mezi dat jednotlivými vrstvami. Jak vidíte, zatím máme autorizaci tvrdě zakódovanou v aplikaci, v reálu se použije ověření proti databázi nebo proti LDAP serveru. Pokud je uživatel nalezen, tak se mu nastaví parametry realName a id a DTO se pošle zpátky, pokud není nalezen, vyhodí se vyjímka. Následuje výpis DTO třídy User:

package cz.linuxsoft.web.dto;

public class User {
    
    private int userId;
    private String username;
    private String password;
    private String realName;
    
    public User() {
    }
    
    public int getUserId() {
        return this.userId;
    }

    public String getUsername() {
        return this.username;
    }
    
    public void setUserId(int userId) {
        this.userId=userId;
    }
    
    public void setUsername(String username) {
        this.username=username;
    }
    
    // apod pro všechny členy...
}

Akce

Nejsnazší cestou k vytvoření aplikace pod Struts, je rozbalení archivu struts-blank.war někam na disk. Tento archiv obsahuje jednoduchou aplikaci, která pouze zobrazuje uvítání. Z aplikace smažte adresáře META-INF, pages, soubor index.jsp a pod adresář WEB-INF\src\java nakopírujte zdrojové kódy aplikace. Nyní si vytvoříme pomocné třídy o kterých jsem již psal výše, v hantýrce Struts se jim říká "akce". Podíváte-li se na kód třídy LoginAction, měli byste si všimnout především dvou věcí. Že akce je potomkem objektu Action, a že přetěžuje metodu execute(). Tato metoda provádí vlastní kód akce, zde zkopíruje data z formuláře do DTO objektu, provede business logiku a uloží data do session, kterou předá dále do prezentační vrstvy (View). Veškerá data z formuláře se kopírují do DTO pomocí prostředníka BeanUtils, nemusíte tedy specifikovat žádné parametry (co a jak kopírovat), BeanUtils sám zavolá odpovídající metody get u vstupní třídy a set u výstupní, přičemž zároveň automaticky provádí konverzi typů. Předávání toku provádíme vrácením objektu ActionForward, který nám poskytuje člen mapping metodou findForward(String). Forwards.SUCCESS je obyčejná konstanta String s hodnotou "success".

package cz.linuxsoft.web.struts.shop.actions;

//import ...

public class LoginAction extends Action {
    
    public ActionForward execute(ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws Exception {
        //vytvořím novou instanci User DTO
        User user=new User();
        //přetypování formu na DynaActionForm
        DynaActionForm inputForm=(DynaActionForm) form;
        //zkopírování hodnot formu do DTO objektu
        BeanUtils.copyProperties(user, inputForm);
        //provedení samotné business logiky
        Service service=new Service();
        //validace proběhne úspěšně pokud služba nehodí exception
        user=service.validate(user);
        //vytvoř novou session
        HttpSession session = request.getSession(false);
        if (session!=null)
            session.invalidate();
        session=request.getSession(true);
        //ulož uživatelská data do session
        session.setAttribute("user", user);
        return(mapping.findForward(Forwards.SUCCESS));
    }
}

Druhou akcí, kterou vytvoříme je LogoutAction. Jejím jediným cílem je zrušit sezení uživatele a přesměrovat ho na výchozí stránku.

package cz.linuxsoft.web.struts.shop.actions;

//import ...

public class LogoutAction extends Action {
    public ActionForward execute(ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws Exception {
        //zruš session
        HttpSession session = request.getSession(false);
        if (session!=null)
            session.invalidate();
        //přesměruj na login.jsp
        return(mapping.findForward(Forwards.SUCCESS));
    }
}

Akce Struts a jejich mapování je součástí konfigurace v souboru struts-config.xml. Pro naše dvě třídy bude vypadat takto:

    <action-mappings>
        
	<action path="/default"
                forward="/pages/login.jsp"/>
        
	<action path="/login"
                type="cz.linuxsoft.web.struts.shop.actions.LoginAction"
                name="loginForm"
                parameter="/pages/login.jsp">
            <forward name="success"
                     path="/pages/welcome.jsp"/>
        </action>

        <action path="/logout"
                type="cz.linuxsoft.web.struts.shop.actions.LogoutAction">
            <forward name="success"
                     path="/pages/login.jsp"
                     redirect="false"/>
        </action>

    </action-mappings>

Provádíme zde přepis url na jejich absolutní lokaci, ať už v podobě třídy nebo jsp stránky. Zároveň určujeme tok aplikace značkou forward. Atribut name u značky action je odkaz na definici formuláře spjatého s akcí. Formulář musí být potomkem třídy org.apache.struts.action.ActionForm, podrobněji se na něj podíváme později. Struts v1.1. nabízejí možnost vytvářet třídy formulářů dynamicky pomocí objektu DynaActionForm, kterému jeho členy přiřadíme přímo v konfiguračním souboru.

    <form-beans>
        <form-bean name="loginForm"
                   type="org.apache.struts.action.DynaActionForm">
            <form-property name="username"
                           type="java.lang.String"/>
            <form-property name="password"
                           type="java.lang.String"/>
        </form-bean>
    </form-beans>

Příště

Pro dnešek už toho bylo dost, v dalším díle dotáhneme aplikaci do první funkční verze. Probereme obraz formulářů v prezenční vrstvě, JSP stránky, i18n ve Struts, nastavíme Ant, který aplikaci zkompiluje, a provedeme první spuštění na aplikačním serveru.

Ke stažení

Současná podoba aplikace

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=703