Apache Struts: Porovnání verzí

Z FI WIKI
Přejít na: navigace, hledání
(Úvod)
m
Řádka 3: Řádka 3:
 
[[Kategorie:PA165]]
 
[[Kategorie:PA165]]
 
[[Kategorie:Webové aplikace]]
 
[[Kategorie:Webové aplikace]]
 
nice site, http://virb.com/sloan4acac Archive Cam Hidden Sex,  522726, http://virb.com/lyndellf3b33 African Music Queen Video,  olvxo, http://www.cleveland.com/forums/profile.ssf?nickname=granville467 Best Free Sex Position,  8[, http://www.videocodezone.com/users/casidy1dd80/ Anal Black Clip Free Movie Sex,  199, http://www.al.com/forums/profile.ssf?nickname=fredricdee32 Bald Free Pussy Video,  07365, http://www.videocodezone.com/users/justinae9353/ India Movie Sex,  8O, http://virb.com/orly714f5 Sexy Black Video,  >:((, http://virb.com/fawnia186d7 Amateur Video Of Couple Fucking,  =), http://www.videocodezone.com/users/devonnae76ce/ Amateur Anal Sample Video,  sjby,
 
  
 
== Struts Controller ==
 
== Struts Controller ==

Verze z 1. 10. 2008, 11:14


Struts Controller

Základem Struts je řídící servlet, který je obvykle v souboru /WEB-INF/web.xml nakonfigurován takto:

   <servlet>
     <servlet-name>action</servlet-name>
     <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
     <init-param>
       <param-name>config</param-name>
       <param-value>/WEB-INF/struts-config.xml</param-value>
     </init-param>
     <load-on-startup>2</load-on-startup>
   </servlet>
   <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>*.do</url-pattern>
   </servlet-mapping>

Tedy tento servlet je načten při spuštění aplikace, načte si konfigurační soubor struts-config.xml a následně obsluhuje všechny požadavky na URL končící příponou .do.

Struts.PNG

Principem funkce tohoto řídícího servletu je, že z URL získá text před .do (tzv. akci), podle konfiguračního souboru nalezne Java třídu provádějící akci (potomek org.apache.struts.action.Action) a zavolá její metodu execute(). Tato metoda by měla zpracovat data přicházející od prohlížeče, a jejím výsledkem je identifikátor (instance třídy org.apache.struts.action.ActionForward), podle kterého řídící servlet vybere, která stránka se zobrazí. Například mějme v souboru struts-config.xml tuto definici:

<struts-config>
 ...
 <action-mappings>
 ...
 <action path="/zbozinasklade" type="cz.nekde.ZboziNaSkladeAction">
     <forward name="zadneneni" path="prazdnysklad.jsp" />
     <forward name="zbozije" path="seznamzbozi.jsp" />
 </action>
 ...

pak zavolání URL /zbozinasklade.do způsobí vyvolání metody ZboziNaSkladeAction.execute(), která (předpokládejme) buď zjistí, že žádné zboží na skladě není, a vrátí identifikátor zadneneni, nebo vytáhne seznam zboží z databáze, nastaví jej jako proměnnou (atribut) do requestu, a vrátí identifikátor zbozije. Řídící servlet pak podle vráceného identifikátoru zavolá buď JSP stránku prazdnysklad.jsp nebo JSP stránku seznamzbozi.jsp.

Implementace akce ZboziNaSkladeAction pak může vypadat nějak takhle:

import cz.nekde.model.Sklad;
 import org.apache.struts.action.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 public class ZboziNaSkladeAction extends Action {
     public ActionForward execute(ActionMapping actionMapping,
                                  ActionForm actionForm, 
                                  HttpServletRequest request, 
                                  HttpServletResponse response) throws Exception {
 
         if(Sklad.mameNejakeZbozi()) {
             request.setAttribute("zbozi",Sklad.getZbozi());
             return actionMapping.findForward("zbozije");
         } else {
             return actionMapping.findForward("zadneneni");
         }
     } 
 }

a JSP stránka seznamzbozi.jsp může vypadat nějak takto:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 ...
 <table>
 <c:forEach var="z" items="${zbozi}">
   <tr>
     <td><c:out value="${z.nazev}"/></td>
     <td><c:out value="${z.mnozstvi}"/></td>
   </tr>
 </c:forEach>
 </table>
 

Struts je možné používat i jen na této základní úrovni, a již přináší do projektů přehlednost, protože přehled o celé aplikaci je možné získat pohledem do souboru struts-config.xml. Ve spojení s JSTL a EL,zejména Core a Formatting knihovnami, poskytuje Struts MVC silný nástroj pro tvorbu vícejazyčných webových aplikací.


Kromě základního MVC rámce ale Struts poskytují spoustu dalších užitečných vlastností, proto čtěte dále.

Obsluha formulářů

Struts obsahují podporu pro pohodlnou obsluhu HTML formulářů. Typická úloha s formulářem je, že uživateli se zobrazí formulář, případně s předvyplněnými některými poli. Uživatel zadá údaje a odešle formulář. Pokud zadaná data obsahují chybu, je třeba formulář zobrazit znovu s vyplněnými údaji, a označit nějak zřetelně chybné údaje a zobrazit hlášení s důvodem, proč jsou chybně. Pokud jsou data v pořádku, jsou přijmuta, a je zobrazena následující stránka.

Všimněte si, že to, jestli bude znovu zobrazen formulář s upozorněním na chybná data, nebo následující stránka, není známo v okamžiku generování stránky s formulářem, a tedy se nemůže projevit v URL na které je formulář odesílán. V tomto bodě velmi pomáhá Struts MVC.

Obtíž se znovuzobrazením formuláře je, že musíme data převzít od prohlížeče, zjistit zda jsou chybná, a pokud ano, nastavit je jako hodnoty do nově zobrazeného formuláře.

Struts pro tyto účely poskytuje dva propojené nástroje:

  • knihovnu JSP značek pro tvorbu formulářů
  • rámec pro obsluhu dat zaslaných z formuláře

Začněme druhým nástrojem. Akce může mít přiřazen tzv. form bean, což je Java třída odvozená z org.apache.struts.action.ActionForm. Je to JavaBean, který má pro každou položku formuláře vytvořenou property, tedy dvojici setXXX() a getXXX() metod. V souboru struts-config.xml je tato třída označena identifikátorem a přiřazena akci takto:

<struts-config>
   <form-beans>
       <form-bean name="udaje" type="cz.nekde.ZboziForm"></form-bean>
    ...
   </form-beans>
   <action-mappings>
   ...
      <action path="/editzbozi" type="cz.nekde.EditZboziAction"
           name="udaje" validate="false" scope="request" >
           <forward name="vporadku" path="formular.jsp" />
      </action>
      <action path="/ulozzbozi" type="cz.nekde.UlozZboziAction"
           name="udaje" validate="true" scope="request" input="formular.jsp">
           <forward name="vporadku" path="zbozidetail.jsp" />
      </action>

Obě akce používají ten stejný form bean. První akce ho nevaliduje, pouze nechá Struts, aby form bean vytvořily, a nastaví do něj data, získáná z databáze. Druhá akce již má nastaveno, že má proběhnout validace, a pokud validace proběhne bez chyb, akce může data z form beanu uložit do databáze.

V JSP stránce s formulářem formular.jsp je formulář vytvořen pomocí JSP značek, které se na form bean odvolávají:

 <%@ taglib prefix="h" uri="http://jakarta.apache.org/struts/tags-html" %>
  <h:form action="/ulozzbozi.do" method="post">
      Název zboží: <h:text property="nazev" size="40"/>
      Počet kusů:  <h:text property="pocet" size="10"/>
      ...
  </h:form>
  

Značka h:form podle atributu action najde form bean, a vnořené značky h:text generují <input type="text"> značky s hodnotami nastavenými z form beanu. Při odeslání formuláře jsou parametry HTTP requestu nastaveny podle jména do příslušných properties ve form beanu, a pokud je ve struts-config.xml nastaven atribut validate="true", je zavolána metoda validate(). Pokud neuspěje, je předáno řízení na JSP stránku určenou atributem input="formular.jsp", tedy formulář je znovu zobrazen. Pokud metoda validate() uspěje, je zavolána metoda execute() příslušné akce a form bean je jí předán jako parametr.

Uživatel může do textových polí formuláře uvádět libovolné hodnoty, například po políčka určeného pro číslo může napsat řetězec obsahující písmena. Proto je dobré mít všechny properties typu String, aby mohly obsahovat přesně to, co uživatel zadal.

Je dobré vědět, že knihovna standardních JSP značek JSTL vznikla standardizací osvědčených značek ze Struts knihoven značek.


Validace hodnot

Třída s form beanem pak obsahuje kromě definic properties i implementaci validate():

public class ZboziForm extends ActionForm {
 
     private String nazev;
     ... setNazev() a getNazev() ...
     private String pocet;
     .... setPocet() a getPocet() ...
 
     public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
         ActionErrors errors = new ActionErrors();
         if ((nazev == null) || (nazev.length() == 0)) {
              errors.add("nazev", new ActionMessage("error.nazev.nutny"));
         }
         return errors;
     }
 }

Zde je na místě podat vysvětlení ohledně třídy ActionErrors. Slouží pro nastavení seznamu chybových hlášení, ty však nejsou zadána přímo, ale podle zásad internacionalizace jako klíče k textům v různých jazycích. Chybová hlášení je ve stránce s formulářem možné vypsat buď všechny najednou, nebo každý v místě formuláře, ke kterému se vztahuje. Pro vypsání všech najednou je možné použít třeba tuto konstrukci:

 <%@ taglib prefix="l" uri="http://jakarta.apache.org/struts/tags-logic" %>
 <%@ taglib prefix="h" uri="http://jakarta.apache.org/struts/tags-html" %>
 <l:messagesPresent>
    <div class="chyba"><h:messages id="msg"><c:out value="${msg}"/><br/></h:messages></div>
 </l:messagesPresent>

Validaci je možné provádět fromě form beanů i v akcích, pak je třeba vytvořit instanci ActionErrors a uložit ji pomocí metody saveErrors(errors), která ji nastaví pod dohodnutým klíčem jako proměnnou (atribut) requestu tak, aby ji značka l:messagesPresent našla.

Formulářem je možno odesílat i soubory, pak je zpracování téměř stejné, jen příslušná property ve form beanu musí mít typ org.apache.struts.upload.FormFile.

Dynamické JavaBeans pro formuláře

Aby nebylo nutné pro každý formulář vytvářet novou Java třídu reprezentující form bean, existuje možnost použít univerzální třídu DynaActionForm, jejíž properties lze specifikovat ve struts-config.xml.

<form-bean name="userForm" type="org.apache.struts.action.DynaActionForm">
   <form-property name="givenName" type="java.lang.String" initial="John"/>
   <form-property name="familyName" type="java.lang.String" initial="Smith"/>
</form-bean>

Ve značkách ze Struts, tj. zejména <h:text>, lze používat DynaActionForm stejně jako normální form beany, v JSTL značkách se pak přistupuje k properties přes mapu:

 ${userForm.map.givenName}

V Action pak lze k properties přistupovat takto:

actionForm.get("givenName");

Indexované, mapované a vnořované properties JavaBeanů

Struts používají pro práci s JavaBeans knihovnu Jakarta Commons Beanutils. Ta podporuje vylepšení oproti normálním JavaBeans. Kromě normálních properties lze používat

  • indexované properties, kdy property se jeví jako pole, k jehož prvkům lze přistupovat pomocí indexu v hranatých závorkách
  • mapované properties, kdy property se jeví jako mapa, k prvkům lze přistupovat přes klíč v kulatých závorkách
  • vnořované properties, kdy hodnotou property je opět JavaBean

Tyto vlastnosti lze využívat nejen pro zobrazení dat, ale i pro jejich nastavení při odeslání formulářů. Všechny tři druhy lze používat dohromady. Např. pokud ve formuláři budeme mít pole

<h:text property="rocnik[1].trida("A").pocetZaku" />

tak se při zobrazení formuláře na příslušném JavaBeanu zavolá

 
  formbean.getRocnik(1).getTrida("A").getPocetZaku()

a po odeslání formuláře dojde efektivně k

 
  formbean.getRocnik(1).getTrida("A").setPocetZaku( request.getParameter("rocnik[1].trida(\"A\").pocetZaku") )

Tiles

Součástí Struts je plugin Tiles, který řeší obvyklý problém jak zajistit všem stránkám jednotný vzhled. Řešení tohoto problému bez použití Tiles obvykle spočívá v tom, že do každé JSP stránky se přidá vložení hlavičky a patičky:

<jsp:include page="hlavicka.jsp">
...
<jsp:include page="paticka.jsp">

Pokud se později zjistí, že by bylo třeba do všech stránek přidat něco dalšího, co nejde umístit ani do hlavičky, ani do patičky, je nutné všechny stránky ručně upravit. Tiles jdou na tento problém z druhé strany.

Tiles se nainicializují v souboru struts-config.xml takto:

<plug-in className="org.apache.struts.tiles.TilesPlugin">
   <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
 </plug-in>

V souboru tiles-defs.xml jsou soustředěny na jednom místě popisy, z jakých částí se stránky skládají, dohromady s definicí šablony pro jejich složení dohromady:

<tiles-definitions>
   <definition name="zaklad" path="/rozlozeni.jsp">
       <put name="titulklic" value=""/>
       <put name="menu" value="/menu.jsp"/>
       <put name="telo" value=""/>
   </definition>
   <definition name="stranka.home" extends="zaklad">
       <put name="titulklic" value="home.titul"/>
       <put name="telo" value="home.jsp"/>
   </definition>
   ...

První definice zavádí jako základní rozvržení stránky JSP stránku určenou atributem path, v tomto případě /rozlozeni.jsp, která na různých místech předpokládá vložení dalších částí specifikovaných značkami <put>. Rozložení může vypadat třeba takto:

<%-- rozlozeni.jsp --%>
 <%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
 <%@ taglib prefix="tiles" uri="http://jakarta.apache.org/struts/tags-tiles" %>
 <tiles:useAttribute id="titulklic" name="titulklic" scope="request"/>
 <html>
  <head>
   <title><f:message key="${titulklic}" /></title>
  </head>
  <body>
  <tiles:insert attribute="menu"/>
  <h1><f:message key="${titulklic}" /></h1>
  <tiles:insert attribute="telo"/>
 </body>
</html>

Značky tiles:insert vkládají na svoje místo soubor určený v definici stránky. Definice stranka.home v tiles-defs.xml dědí nastavení z definice zaklad, a doplňuje že telo je home.jsp.

Názvy definic Tiles je možné používat v souboru struts-config.xml místo jmen JSP stránek. Pokud tedy nějaké akce způsobí zobrazení stranka.home, vyvolá se JSP stránka /rozlozeni.jsp, která na příslušných místech zavolá stránky menu.jsp a home.jsp.

Při potřebě změnit vzhled všech stránek najednou tak stačí změnit jen stránku rozlozeni.jsp, případně upravit definici zaklad, aby obsahovala další klíč. Všechny stránky s definicemi poděděnými z definice zaklad tak změní svůj vzhled.