Table of Contents
Nun wird es Zeit einen
decorator
für den
screen
der Anwendung anzulegen. Legen Sie die Datei
CommonScreens.xml
im Verzeichnis
widget
an. Diese Datei enthält die allgemeinen
screens
welche durchweg in der Anwendung verwendet werden. Ein
allgemeiner
screen
könnte ein Kopf- und ein Fußteil haben. Jeder andere Screen
welches diesen als
decorator
hat dann ebenfalls Kopf- und Fußteil.
<?xml version="1.0" encoding="UTF-8"?> <screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-screen.xsd"> <screen name="main-decorator"> <!-- The main-decorator screen 'wraps' or 'decorates' all of the screens in the practice component. It is also decorated - by the GlobalDecorator screen. --> <section> <actions> <!-- base/top/most specific map first, then more common map added for shared labels. Setting things up this way enables a component to redefine the more common UI labels. --> <property-map resource="CommonUiLabels" map-name="uiLabelMap" global="true"/> <property-map resource="PracticeUiLabels" map-name="uiLabelMap" global="true"/> <!-- The layoutSettings field is a Map that is used to pass variables and layout information to the GlobalDecorator and any templates that it uses. --> <set field="layoutSettings.companyName" from-field="uiLabelMap.PracticeCompanyName" global="true"/> <set field="activeApp" value="practice" global="true"/> <!-- Default (main) javascript files --> <set field="layoutSettings.javaScripts[+0]" value="/images/prototypejs/validation.js" global="true"/> <set field="layoutSettings.javaScripts[]" value="/images/prototypejs/prototype.js" global="true"/> <set field="applicationMenuName" value="PracticeAppBar" global="true"/> <set field="applicationMenuLocation" value="component://practice/widget/PracticeMenus.xml" global="true"/> </actions> <widgets> <include-screen name="GlobalDecorator" location="component://common/widget/CommonScreens.xml"/> </widgets> </section> </screen> <screen name="CommonPracticeDecorator"> <section> <widgets> <decorator-screen name="main-decorator"> <decorator-section name="body"> <decorator-section-include name="body"/> </decorator-section> </decorator-screen> </widgets> </section> </screen> </screens>
Wie immer können Sie Bezug
auf die
CommonScreens.xml
Datei aus dem Beispielen nehmen und Beispiele zur Verwendung von
main-decorator
einsehen. Zu diesem Thema finden Sie wichtige Informationen
unter
den beiden Links:
Understanding the OFBiz Widget Toolkit
und den Abschnitt
"The Decorator"
in den
FAQ
.
Legen Sie ein Menü für die Anwendung an. Dafür legen Sie eine
Datei Namens
PracticeMenus.xml
im Verzeichnis
widget
der Komponente an. Ziehen Sie in die Datei
ExampleMenus.xml
des Beispielprojektes als Referenz heran.
<?xml version="1.0" encoding="UTF-8"?> <menus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-menu.xsd"> <menu name="PracticeAppBar" title="PracticeApplication" extends="CommonAppBarMenu" extends-resource="component://common/widget/CommonMenus.xml"> <menu-item name="main" title="Main"><link target="main"/></menu-item> </menu> </menus>
Binden Sie dieses Menüdatei in ihren
CommonPracticeDecorator
wie folgt ein.
<screen name="CommonPracticeDecorator"> <section> <widgets> <include-menu location="component://practice/widget/PracticeMenus.xml" name="PracticeAppBar"/> <decorator-section-include name="body"/> </widgets> </section> </screen>
Legen Sie das Verzeichnis
actions
im Verzeichnis
WEB-INF
an. In dieses Verzeichnis werden wir Skripte ablegen. Über
Skipte
werden Daten zur Laufzeit bereitgestellt. Die Skripte
sind
Groovy-Skripte (in früheren Versionen wurden
beanshell-Skripte
verwendet). Unser Skript wird Daten aus der
Datenbank lesen und zur
Laufzeit für das UI aufbereiten.
Referenzen: Tips & Tricks while working with Groovy und http://groovy.codehaus.org/ .
Achten Sie bei Groovy-Skripten immer auf die verwendeten
Imports.
Importieren Sie immer nur das was auch Verwendung
findet. Um
Log-Meldungen zu schreiben verwenden Sie bitte von
Anfang an die
Debug
-Klasse.
Legen Sie eine Datei mit dem Namen
person.groovy
im Verzeichnis
actions
an. Dieses Skript wird alle Werte für die Entität
Person
aus der Datenbank lesen. Für den Moment ist der Code mit einer
Zeile wirklich winzig.
context.persons = delegator.findList("Person", null, null, null, null, false);
Der obige Code zieht alle Werte von der Entität
Person
und legt sie in den Context der entsprechenden Person. In der
ftl
Datei wird über die
Liste der Personen iteriert.
Wichtige Informationen dazu finden Sie unter: Which variables are available in screen context?
Im Verzeichnis
practice/webapp/practice/
legen sie nun die Datei
person.ftl
an. Diese Datei ist für die Anzeige der Werte, welche über das
Groovy-Skript gelesen wurden, verantwortlich.
Siehe dazu auch: http://freemarker.sourceforge.net/docs/ .
Im Moment brauchen Sie nur über die Liste der Personen aus dem Context zu iterieren. Dazu sind die wenigen folgenden Zeilen Code notwendig.
<#if persons?has_content> <h2>Some of the people who visited our site are:</h2> <br> <ul> <#list persons as person> <li>${person.firstName?if_exists} ${person.lastName?if_exists}</li> </#list> </ul> </#if>
Nun legen Sie einen
screen
mit dem Namen
person
über die Datei
PracticeScreens.xml
an. Gleichzeitig erzeugen Sie einen neuen Menüeintrag über die
PracticeMenus.xml
Datei.
Der neue Menüeintrag in der
PracticeScreens.xml
sieht folgender Maßen aus:
<screen name="person"> <section> <actions> <script location="component://practice/webapp/practice/WEB-INF/actions/person.groovy"/> </actions> <widgets> <decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}"> <decorator-section name="body"> <platform-specific> <html> <html-template location="component://practice/webapp/practice/person.ftl"/> </html> </platform-specific> </decorator-section> </decorator-screen> </widgets> </section> </screen>
Nun ändern Sie die
controller.xml
Datei so, dass auf den neuen
screen
verwiesen wird.
<?xml version="1.0" encoding="UTF-8"?> <site-conf xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/site-conf.xsd"> <include location="component://common/webcommon/WEB-INF/common-controller.xml" /> <description>Practice Component Site Configuration File</description> <owner>Copyright 2001-2009 The Apache Software Foundation</owner> <handler name="screen" type="view" class="org.ofbiz.widget.screen.ScreenWidgetViewHandler" /> <!-- Request Mappings --> <request-map uri="main"> <security https="false" auth="false" /> <response name="success" type="view" value="main" /> </request-map> <request-map uri="person"> <security https="false" auth="true" /> <response name="success" type="view" value="person" /> </request-map> <!-- end of request mappings --> <!-- View Mappings --> <view-map name="main" type="screen" page="component://practice/widget/PracticeScreens.xml#main" /> <view-map name="person" type="screen" page="component://practice/widget/PracticeScreens.xml#person" /> <!-- end of view mappings --> </site-conf>
Nun starten Sie die Anwendung und prüfen das Ergebnis http://localhost:8080/practice/control/person .
Das Beispiel kann ohne Anmeldung aufgerufen werden. Wegen besser Sichtbarkeit wurde für das Bildschirmfoto eine anderes Thema (Theme) gewählt. Dazu ist allerdings eine Anmeldung notwendig.
Falls also ihr
screen
kein Menü enthält, aktivieren Sie die Authentifizierung. Sobald
auth="false"
in der
controller.xml
Datei auf
auth="true"
für die URI
person
gestellt wurde wird eine Anmeldung benötigt und dann erscheint
auch das Menü.
Es ist alles soweit erledigt, die ersten Anfragen an OFBiz werden gestartet und dann das: irgend etwas geht schief. Mögliche Fehler und ihre Ursachen für dies Abschnitt:
Der Aufruf http://localhost:8080/practice/control/person liefert folgende Fehlermeldung:
Message: Unknown request [person]; this request does not
exist or cannot be called directly.
Lösung: Überprüfen Sie die Groß-/Kleinschreibung und Pfade zu den Dateien (besonders person.groovy, person.ftl und actions). Die originale, englische Anleitung ist an ein paar Stellen diesbezüglich Fehlerhaft.
Dies betrifft auch die Groß-/Kleinschreibung in den Dateien:
PracticeScreens.xml
und
controller.xml
.
Der Aufruf http://localhost:8080/practice/control/person liefert folgende Fehlermeldung:
org.ofbiz.widget.screen.ScreenRenderException: Error
rendering screen
[component://common/widget/CommonScreens.xml#login]:
java.lang.IllegalArgumentException: Could not find screen with
name [main-decorator] in class resource
[component://practice/widget/CommonScreens.xml] (Could not find
screen with name [main-decorator] in class resource
[component://practice/widget/CommonScreens.xml])
Lösung: Prüfen Sie den Aufbau der
CommonScreens.xml
Datei.
Fügen Sie einen weiteren Punkt zum Menü in der
PracticeMenus.xml
hinzu.
Legen Sie ein Datei namens
PracticeForms.xml
im Verzeichnis
widget
an. Erzeugen Sie ein Formular für eine Liste um die Datensätze der
Entität
Person
anzuzeigen. (Nehmen Sie Bezug
ExampleScreens.xml
und
ExampleForms.xml
)
<?xml version="1.0" encoding="UTF-8"?> <forms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-form.xsd"> <form name="ListPersons" type="list" list-name="persons" list-entry-name="person" target="updatePracticePerson"> <auto-fields-service service-name="updatePracticePerson" default-field-type="edit" map-name="person"/> <field name="partyId"><hidden/></field> <field name="deleteLink" title="" widget-style="buttontext"> <hyperlink target="deletePracticePerson" description="${uiLabelMap.CommonDelete}" also-hidden="false"> <parameter param-name="partyId" from-field="person.partyId"/> </hyperlink> </field> <field name="submitButton" title="${uiLabelMap.CommonUpdate}"><submit button-type="button"/></field> </form> </forms>
Erzeugen Sie in der
CommonScreens.xml
Datei einen weiteren
screen
mit den Namen
personForm
und fügen Sie folgendes Formular für Listen ein.
<screen name="PersonForm"> <section> <actions> <set field="headerItem" value="personForm"/> <set field="titleProperty" value="PageTitlePracticePersonForm"/> <entity-condition entity-name="Person" list="persons"/> </actions> <widgets> <decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}"> <decorator-section name="body"> <label text="Person List" style="h2"/> <include-form name="ListPersons" location="component://practice/widget/PracticeForms.xml"></include-form> </decorator-section> </decorator-screen> </widgets> </section> </screen>
Jetzt muss noch
controller.xml
angepasst werden um den screen anzuzeigen.
Fügen Sie dazu bitte folgende Abschnitte an die entsprechenden
stellen der
controller.xml
Datei ein.
<request-map uri="PersonForm"> <security https="false" auth="true"/> <response name="success" type="view" value="PersonForm"/> </request-map> <request-map uri="updatePracticePerson"> <security https="true" auth="true"/> <event type="service" invoke="updatePracticePerson"/> <response name="success" type="view" value="PersonForm"/> <response name="error" type="view" value="PersonForm"/> </request-map>
und
<view-map name="PersonForm" type="screen" page="component://practice/widget/PracticeScreens.xml#PersonForm"/>
Im Unterschied zur Liste der Personen erfordert das Formular nun
die Authentifizierung (
auth="true"
).
Es muss die Datei
PracticeScreens.xml
angepasst werden. Ergänzen Sie die Datei an passender Stelle um
folgende Zeilen.
<screen name="PersonForm"> <section> <actions> <set field="headerItem" value="personForm"/> <set field="titleProperty" value="PageTitlePracticePersonForm"/> <entity-condition entity-name="Person" list="persons"/> </actions> <widgets> <decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}"> <decorator-section name="body"> <label text="Person List" style="h2"/> <include-form name="ListPersons" location="component://practice/widget/PracticeForms.xml"/> </decorator-section> </decorator-screen> </widgets> </section> </screen>
Es muss noch ein Service definiert werden. Erzeugen Sie die Datei
/practice/servicedef/services.xml
an.
<?xml version="1.0" encoding="UTF-8"?> <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/services.xsd"> <description>Practice Services</description> <!-- Party related Services --> <service name="updatePracticePerson" default-entity-name="Person" engine="simple" location="component://practice/script/org/hotwax/practice/PracticeServices.xml" invoke="updatePracticePerson" auth="true"> <description>Update a person</description> <auto-attributes include="pk" mode="IN" optional="false" /> <attribute name="firstName" mode="IN" type="String" optional="false" /> <attribute name="middleName" mode="IN" type="String" optional="true" /> <attribute name="lastName" mode="IN" type="String" optional="false" /> </service> </services>
Die Service-Definition muss in der
ofbiz-component.xml
eingebunden werden. Dazu fügen sie folgende Zeile an passender
Stelle ein.
<service-resource type="model" loader="main" location="servicedef/services.xml"/>
Nun starten Sie die Anwendung und rufen http://localhost:8080/practice/control/PersonForm auf. Nach der Anmeldung sehen sie folgendes:
Das erste Formular ist erstellt auch wenn noch nicht alle Funktionen implementiert sind. Wir werden dies im weiteren noch nachholen.
Kleine Rekapitulation, bis jetzt haben Sie an folgendem gearbeitet: controller requests mappings, Screen widget, form widget, Decorator, Menus, groovy, ftl.
Mögliche Fehler und ihre Ursachen für dies Abschnitt:
Aufruf von alhost:8080/practice/control/PersonForm liefert folgendes:
org.ofbiz.widget.screen.ScreenRenderException: Error
rendering screen
[component://common/widget/CommonScreens.xml#GlobalDecorator]:
java.lang.RuntimeException: Error rendering included form named
[ListPersons] at location
[component://practice/widget/PracticeForms.xml]:
java.lang.IllegalArgumentException: Error finding Service with
name updatePracticePerson for auto-fields-service in a form
widget (Error rendering included form named [ListPersons] at
location [component://practice/widget/PracticeForms.xml]:
java.lang.IllegalArgumentException: Error finding Service with
name updatePracticePerson for auto-fields-service in a form
widget)
Lösung: Die Einträge für
updatePracticePerson
in der
controller.xml
könnten fehlerhaft sein. Oder die service definition (
servicedef/services.xml
) sind fehlerhaft oder nicht in der
ofbiz-component.xml
Datei eingebunden.
Die Anwendung benötigt noch einen
main Decorator
über den die Auszeichnung erfolgt.
Legen Sie einen
screen
mit dem Namen
main-decorator
in der
CommonScreens.xml
. (Nehmen Sie
CommonScreens.xml
aus dem Beispielen als Referenz.)
<screen name="main-decorator"> <section> <actions> <property-map resource="CommonUiLabels" map-name="uiLabelMap" global="true"/> <set field="layoutSettings.companyName" from-field="uiLabelMap.PracticeCompanyName" global="true"/> <set field="activeApp" value="practice" global="true"/> <set field="applicationMenuName" value="PracticeAppBar" global="true"/> <set field="applicationMenuLocation" value="component://practice/widget/PracticeMenus.xml" global="true"/> </actions> <widgets> <include-screen name="GlobalDecorator" location="component://common/widget/CommonScreens.xml"/> </widgets> </section> </screen>
Den
Decorator
haben Sie bereits in den
CommonPracticeDecorator
screen (
PracticeScreens.xml
) eingefügt.