erweiterung einer bestehenden liferay-portal-anwendung … · prozessschnittstellen von dem ganzen...
TRANSCRIPT
Abschlussprüfung Winter 2017/2018
Erweiterung einer bestehenden Liferay-Portal-Anwendung
um 2 zusätzliche Portlets
Prüfungsteilnehmer:
Andrey Boivalenko
Fachinformatiker Anwendungsentwicklung
Projektverantwortlicher:
Herr Holger Werkhäuser
+49 (6151) 62912-0
Ausbildungsbetrieb:
e.i.s. Konzept AG Elektronische Informations-Systeme
Steubenpl. 17, 64293 Darmstadt
2
Inhaltsverzeichnis 1 Beschreibung der Ausgangssituation ........................................................................................ 3
1.1 Projektumfeld ......................................................................................................................... 3
1.2 Prozessschnittstellen ........................................................................................................... 3
1.3 Ansprechpartner ................................................................................................................... 3
1.4 IST-Zustand und Projektziele ............................................................................................. 4
1.5 Kundenwünsche ................................................................................................................... 4
1.6 Abgrenzung ........................................................................................................................... 5
1.7 Abweichungen vom Projektantrag ..................................................................................... 5
2 Ressourcen- und Ablaufplanung ................................................................................................ 5
2.1.1 Sachmittelplanung ........................................................................................................ 5
2.1.2 Personalplanung ........................................................................................................... 6
2.1.3 Terminplanung .............................................................................................................. 6
2.1.4 Kostenplanung .............................................................................................................. 6
2.1.5 Kosten-Nutzung-Analyse ............................................................................................. 7
2.2 Ablaufplanung ....................................................................................................................... 8
3 Durchführung und Auftragsbearbeitung .................................................................................... 9
3.1 Arbeitsumgebung Einrichten ............................................................................................... 9
3.1.1 Prozessbeschreibung ................................................................................................... 9
3.1.2 Arbeitsumgebungsbeschreibung .............................................................................. 11
3.1.3 Arbeitsumgebung einrichten ..................................................................................... 11
3.2 Einarbeitung in Spezifikation der Portlets ....................................................................... 12
3.3 Implementierung ................................................................................................................. 12
3.3.1 Backend der Portlets .................................................................................................. 13
3.3.2 Frontend der Portlets.................................................................................................. 14
4 Projektergebnisse ....................................................................................................................... 18
4.1 Soll-Ist-Vergleich ................................................................................................................. 22
4.2 Qualitätskontrolle ................................................................................................................ 22
4.3 Fazit ...................................................................................................................................... 22
5 Abkürzungsverzeichnis .............................................................................................................. 23
6 Literaturverzeichnis .................................................................................................................... 25
7 Anlage mit der Dokumentation des Quellcodes aus der Implementierungsphase ........... 25
7.1 Backend vom Portlet „Handlungsfelder“ .............................................................................. 25
7.2 Backend vom Portlet „Kennzahlen“ ...................................................................................... 31
7.3 Frontend vom Portlet „Handlungsfelder“ ............................................................................. 35
7.4 Frontend vom Portlet „Kennzahlen“ ..................................................................................... 45
3
1 Beschreibung der Ausgangssituation
1.1 Projektumfeld
Die e.i.s. Konzept AG ist ein mittelständiges Unternehmen mit Schwerpunkt auf der
Individualentwicklung von Software für die Automobilbranche. Die Firma hat sich auf die
Erstellung von Webanwendungen mit Java im Portalumfeld1 spezialisiert.
Die 20 Mitarbeiter, hauptsächlich Softwareentwickler, arbeiten im Firmensitz in Darmstadt.
Die Projektarbeit findet in der Firma e.i.s. Konzept AG statt.
1.2 Prozessschnittstellen
Das Produkt ADP ist eine firmeneigene Webanwendung mit offline Funktionalität zur
Berichterfassung, welches bei mehreren Kunden von der Firma im Einsatz ist.
Strategischer Geschäftsplan ist ein Modul von dem ADP. Die Erstellung des "strategischen
Geschäftsplanes" (SGP) erfolgt über eine händische Zusammenfassung von ca. 470
verschiedenen quantitativen und qualitativen Daten für insgesamt 600 Vollfunktionspartner.
Die aus dem Strategischen Geschäftsplan resultierenden Maßnahmen sollen weiter über ADP
verfolgt werden.
Prozessschnittstellen der entsprechenden Projektarbeit betreffen zwar die
Prozessschnittstellen von dem ganzen ADP, weil die Portlets, die zu implementieren sind,
sich mit Administration von Systemwerten des ganzen SGP Projekts befassen, sind aber mit
bekanntem Schema von den Tabellen in einer konkreten Datenbank
eingeschränkt.
1.3 Ansprechpartner
Der einzige Ansprechpartner für das Projekt ist der Herr Severin von der e.i.s Konzept AG, der
das komplette SGP Projekt von vielen Gesprächen und Meetings mit Kunden spezifiziert hat.
Wobei wurden über manche besondere technische Aspekte, die bei der richtigen
1 Ein Portal ist eine besondere Form der Webanwendung
4
Projektierung von Portlets2 zu beachten sind, von anderen Mitarbeiter des Liferay Portal3
Teams in der Firma beraten.
1.4 IST-Zustand und Projektziele
Bisher können die Systemwerte, die sich auf implementierende Portlets beziehen, nur über die
Datenbank direkt gepflegt werden. Dabei mussten Kunden beim Datenbank Administrator von
e.i.s Konzept AG einen Antrag stellen lassen um Systemwerte zu ändern, zu ergänzen oder
zu löschen. Danach teilte der Datenbank Administrator in einige Tagen den Kunden
geänderte Systemwerte und die werden Im Endeffekt in Excel Dokumentation von Kunden
eingetragen werden. Der Prozess war langsam, aufwendig und manchmal fehlerhaft.
Durch die Erweiterung erhalten die Kunden bzw. Anwendungsbenutzer die Möglichkeit,
Systemwerte über eine grafische Oberfläche innerhalb der bestehenden Anwendung zu
konfigurieren. Es gibt auch anderen Nutzen der Projekteinführung, die im Kapitel 2.1.5
„Kosten-Nutzung-Analyse“ genauer beschrieben werden.
Das Ziel des Projektes: Erweiterung der bestehenden Liferay-Portal-Anwendung „ADP –
Strategischer Geschäftsplan“ um 2 Portlets zur Administration von Systemwerten.
Diese sollen unter Verwendung des firmeninternen Frameworks umgesetzt werden, welches
wiederum verschiedene Open-Source-Frameworks für die Entwicklung von Portal-Projekten
einsetzt.
1.5 Kundenwünsche
Wie im Kapitel 1.3 schon erwähnt, wird die Projektarbeit auf Grund einer exakten
Spezifikation gemacht, die für das ganze SGP Projekt geeignet ist. In dieser Spezifikation ist
es deutlich beschrieben, welche Kundewünsche bezüglich des SGP Projekt und insbesondere
für den Abschlussprojektteil sind. Da gibt es ganze Information wie die entsprechenden
2 Portlets sind beliebig kombinierbare Komponenten einer Benutzeroberfläche, die von einem Portalserver angezeigt und verwaltet werden. 3 Liferay Portal - ist eine lizenzkostenfreie Open-Source-Software, die in Unternehmen als Mitarbeiter- und Geschäftsprozess-orientiertes Enterprise Portal eingesetzt wird. Mit Liferay können Informationen, Daten und Anwendungen unter einer einheitlichen Bedienungsoberfläche im Browser des Mitarbeiters vereint und personalisiert werden, um dadurch die Geschäftsprozesse im Unternehmen elektronisch zu unterstützen. Liferay Portal ist in Java entwickelt.
5
Portlets des Abschlussprojektes aussehen sollen und welche Funktionalität die Portlets haben
sollen. Anhand der Spezifikation wird im Teil „Projektergebnisse“ außerdem unter dem Punkt
„Soll-Ist-Vergleich“ vergleicht, wie genau das erstellende Projekt der Spezifikation entspricht.
1.6 Abgrenzung
Die Portlets, die zu implementieren sind, sind nur zu Administration von Systemwerten gedacht
und nicht zur Erfassung davon der Daten. Dafür gibt’s andere Portlets. Die Portlets enthalten
Listen von entsprechenden Werten, die angezeigt, zugefügt, bearbeitet und gelöscht werden
können. Die Änderungen von diesen Manipulationen werden schließlich in der Datenbank
gespeichert.
1.7 Abweichungen vom Projektantrag
Der Projektantrag wurde zwar von der IHK genehmigt. Es war aber vorgeschrieben, dass
eine Kosten-Nutzung-Analyse sowie organisatorischen Schnittstellen in der Projekt-
Dokumentation ergänzt werden soll. Dies wurde akzeptiert und entsprechend nachbearbeitet.
2 Ressourcen- und Ablaufplanung
In diesem Kapitel werden die zur Verfügung stehende Zeit sowie die Ressourcen des
Projektes geplant.
2.1.1 Sachmittelplanung
Zur Entwicklung des Front- und Backends des Projekts wird eine IDE benötigt. Dabei
wurde auf die bereits im Ausbildungsbetrieb verwendete, kostenlose Eclipse IDE
zurückgegriffen. Um die Webanwendung und das genutzte Backend bereit zu stellen,
wird ein Java Applicationserver benötigt. Da für die Portletsimplementierung besondere
Vorgaben gelten, wurde hierzu der kostenlose Liferay Portal Server verwendet. Die zu
Benutzung und Test der Anwendungen verwendeten Browser (Microsoft Internet
Explorer, Mozilla Firefox und Google Chrome) sind ebenso kostenlos erhältlich. Der nötige
Entwicklungsrechner und Arbeitsplatz wurde von der e.i.s. Konzept AG im Rahmen der
Ausbildung bereitgestellt.
6
Als Datenbank-Tool zum Zugriff zur Datenbank wurde Aqua Data Studio mit Trial Lizenz von
14 Tagen verwendet.
2.1.2 Personalplanung
Die für das Projekt nötigen Tätigkeiten werden vom Auszubildenden eigenständig erledigt.
2.1.3 Terminplanung
Das Projekt wird vom Auszubildenden in Teilabschnitten neben den üblichen Aufgaben des
Tagesgeschäfts durchgeführt. Als Bearbeitungszeitraum ist der 09.10.2017 bis zum
20.10.2017 geplant.
2.1.4 Kostenplanung
Da es sich hier um eine Erzeugung der Anwendungen handelt, werden die
Kostenplanung anhand der Stundensätze unseres Firmenstandards berechnet. Für einen
Entwickler betragen die Kosten pro Mannstunde 95 €, für einen Projektleiter 130 €.
Die Positionen sind nach ihrer Einordnung im Projektablauf gegliedert. Es ist zu beachten,
dass die unterstrichenen Positionen von mir durchgeführt wurden.
Nr. Position Mannstunden
Stundensatz (Euro)
Total (Euro)
1 Spezifikation Erstellen bezüglich der Portlets
16 130 Euro 2080 Euro
2 Einarbeitung in Spezifikation der Portlets
5 95 Euro 475 Euro
3 Erstellung von Backend der Portlets
10 95 Euro 950 Euro
4 Erweiterung von Frontend der Portlets
20 95 Euro 1900 Euro
5 Testphase 10 95 Euro 950 Euro
6 Testphase 4 130 Euro 520 Euro
7 Erstellung der Projekt Dokumentation und
Präsentation
22 95 Euro 2090 Euro
8 Kosten Gesamt 8965 Euro
Abbildung 1
Die Kosten sollen nur einmal investiert werden. Es gibt keine weiteren Kosten, die die
Projektumsetzung angehen.
7
2.1.5 Kosten-Nutzung-Analyse
Um eine Effizienz des Projektes bzw. der Projekteinführung beurteilen zu können, wird eine
Kosten-Nutzung-Analyse durchgeführt. Dabei werden präziser Kosten-Nutzung und Nutzen
allgemein betrachtet und dann schließlich die analysiert bzw. zusammengefasst.
2.1.5.1 Nutzen
Wie im Kapitel 1.4 „IST-Zustand und Projektziele“ erwähnt war, war der Prozess der
Änderung von Systemwerten ziemlich schwer und aufwendig. Dadurch, dass Systemwerte
nach der Umsetzung des Projektes direkt von Kunden gepflegt werden können, ist den
ganzen Geschäftsprozess klarer und effizienter aus Kundesicht geworden. Dabei sind
folgende neue Möglichkeiten erschienen:
1. Mit der Projektumsetzung kam die Möglichkeit, die Daten ordentlich zu strukturieren.
2. Dass die Daten ordentlich strukturiert sind, machen Kunden bei Steuerung der
Systemwerten weniger Fehler wie früher. Es geht sowohl um menschliche Fehler als auch
um Systemfehler, die den Kunden angezeigt werden können, falls sie unrichtige Daten ins
System eingeben würden.
3. Man kann ganze Änderungen von Systemwerten von vorherigen Jahren einfach und
komfortable nachvollziehen und vergleichen
4. Mit der Projektumsetzung kann nun nicht nur der Datenbank Administrator, sondern
auch der Anwender des Systems Systemwerte steuern. Es spart Geld, das dem Datenbank
Administrator für seine Arbeit bezahlt werden musste.
5. Der Anwender verbraucht weniger Zeit im Vergleich zum Datenbank Administrator,
um Systemwerte zu steuern.
2.1.5.2 Kosten-Nutzung
Im Kapitel 2.1.4 wurde berechnet welche Gesamt Kosten sind, um das Projekt umzusetzen.
Die Kosten werden nur einmal investiert. Es gibt keine weiteren Kosten die die
Projektumsetzung angehen.
Die Kosten von Dienstleistungen von einem Datenbank Administrator bezüglich der
8
Systemwerten (pro Jahr ca 30 Tage):
95 Euro * 2 Stunden/Tag * 30 Tage = 5700 Euro.
Die Kosten von Dienstleistungen von einem Anwender bezüglich der Systemwerten
(pro Jahr) nach der Einsetzung des Projektes:
95 Euro * 1 Stunden/Tag * 30 Tage = 2850 Euro.
Dass die Systemwerte mindestens 5 Jahren gepflegt werden müssen, wird nun eine
Effizienz der Umsetzung des Projektes berechnet:
Jahre Kosten vor Einsetzung
Kosten nach Einsetzung
Effizienz ( Euro )
1 5700 Euro 8965 Euro - 3265 Euro
2 5700 Euro 2850 Euro 2850 Euro
3 5700 Euro 2850 Euro 2850 Euro
4 5700 Euro 2850 Euro 2850 Euro
5 5700 Euro 2850 Euro 2850 Euro
Abbildung 2
Obwohl die Effizienz vom ersten Jahr unvorteilhaft ist, wird die in nächsten Jahren erfolgreich
kompensiert. Effizienz für 5 Jahre:
2850*4 – 3265= 8135 Euro.
Dadurch das Projekt eigesetzt wird, sparen Kunden 8135 Euro für 5 Jahre.
2.1.5.3 Kosten-Nutzung-Analyse
Von den Kapitel 2.1.5.1 und Kapitel 2.1.5.2 wird es sicher festgestellt, dass die
Vorteile von der Projektumsetzung ziemlich sinnvoll sind und das Projekt ist einzusetzen.
2.2 Ablaufplanung
Die Ablaufplanung des Projektes hat die folgende Struktur:
Phase Tätigkeit Dauer (h)
Einarbeitung
Arbeitsumgebung Einrichten
3
Einarbeitung in Spezifikation der Portlets
5
9
Implementierung
Erstellung von Backend der Portlets
10
Erweiterung von Frontend der Portlets
20
Testphase 10
Dokumentation
Erstellung der Projekt Dokumentation und
Präsentation
22
Abbildung 3
Gesamter Dauer von allen Phasen ist 70 Stunden. Das ist vorgegebene maximale Zeit, die für
eine Projektarbeit verbraucht werden darf.
3 Durchführung und Auftragsbearbeitung
Nachdem die Aufbauplanung des Projektes abgeschlossen ist, kann mit der
Einarbeitungsphase zur Ermittlung des Ist-Zustandes begonnen werden. Dabei muss vorher
die Arbeitsumgebung eingerichtet werden und die Spezifikation bezüglich der
Implementierung von Portlets durchgearbeitet werden.
3.1 Arbeitsumgebung Einrichten
3.1.1 Prozessbeschreibung
Um die Arbeitsumgebung für das Projekt eirichten zu können muss man vorher
Geschäftsprozesse verstehen, die dahinten laufen.
10
Abbildung 4
Von der Abbildung 4 wird es zusammenschließt:
1. Händler Netz Entwickler planen SGP vor. Es werden Kennzahlen und
Handlungsfelder erst mal eingestellt.
2. Gebietsleiter entscheiden ob die Zahlen stimmen
3. Händler selbst entscheidet ob die Zahlen stimmen
4. Alle Händler entscheiden im Gespräch miteinander ob die Zahlen stimmen
5. Falls die Händler die Zahlen zustimmen, kommen die Zahlen zu Regionalleiter und er
gibt im Endeffekt die Freigabe von Zahlen frei
6. In einiger Zeit werden Phasen wieder wiederholt.
Handlungsfelder sind von Kunden ausgedachte Felder, die definieren und messen können,
wie gut Autohäuser in bestimmten Bereichen etwas machen. Wenn man konkrete
Handlungsfelder anschaut, kann eine Bewertung anhand Soll-Ist-Vergleich vorgenommen
werden und eine Entschließung gemacht werden ob der Wert gut erfüllt oder nicht. Im Fall
wenn ein Wert negativ ausfällt gibt’s die Maßnahmen die mit dem Ziel erstellt werden, dass
das besser wird für das nächstes Jahr.
Kennzahlen sind Zahlen die verschiedene Parameter messen, z.B. Kundenzufriedenheit. Im
Fall wenn ein Wert niedrig ist werden genauso bestimmten Maßnahmen wie bei
Handlungsfelder erstellt die dafür da sind um die entsprechenden Kennzahlen besser zu
machen.
11
3.1.2 Arbeitsumgebungsbeschreibung
Bei den Anwendungen handelt es sich um 2 neue Portlets innerhalb einer
bestehenden Liferay-Portal-Anwendung. Diese werden mit folgenden Technologien
umgesetzt:
Java EE (Enterprise Edition)
HTML
Javascript
CSS
SQL
Für die Entwicklung werden folgenden Frameworks verwendet:
Firmeninternes Portal-Framework
Spring (Core + MVC)
MyBatis (Datenbankzugriffe)
DOJO (Javascript Frontend)
Für die Entwicklung wird folgende Software benötigt:
Liferay IDE (Eclipsebasierte Entwicklungsumgebung für Liferay Portal)
Liferay Portal Server 6.2.0 (Portalserver mit Tomcat)
AquaDataStudio (Datenbank-Tool)
Diverse Browser (Internet Explorer, Chrome, Firefox)
Optional: JRebel
Alle diese obenstehenden Begriffe werden im Abkürzungsverzeichnis erklärt.
3.1.3 Arbeitsumgebung einrichten
Um die Arbeitsumgebung einrichten zu können muss:
1. das Java Development Kit (JDK) heruntergeladen und auf dem Rechner installiert
werden
2. ein Liferay IDE und einen Liferay Portal Server aus dem Fileserver von der Firma
herunterladen werden.
3. das Liferay IDE gestartet werden und eine neue Liferay IDE Arbeitsumgebung
eingestellt werden
4. eine Kopie des SGP Projektes aus SVN in die entsprechenden Liferay IDE
Arbeitsumgebung ausgecheckt werden
5. das Aqua Data Studio gestartet werden
6. einen Liferay Portal Server in arbeitsfähiger Liferay IDE mit dem SGP Projekt
gestartet werden, um zu testen, ob der Liferay Portal Server lauffähig ist.
12
3.2 Einarbeitung in Spezifikation der Portlets
Einarbeitung in Spezifikation der Portlets bestand aus:
1. Die ganze Spezifikation wurde von mir durchgelesen (mehr als 80 Seiten)
2. Die Spezifikation bezüglich der implementieren Portlets wurde von mir noch mal
durchgelesen und analysiert.
3. Gespräche mit Kollegen bezüglich der implementierenden Portlets wurden
durchgeführt.
4. Vorbereitung zur Implementierungsphase des Portlets wurde durchgeführt dadurch,
dass technische Aspekte mit anderen Portlets in Projekten wie SGP, GKSA usw.
verglichen wurden. Dabei wurde zusammengefasst welche DOJO Web Komponenten
zu verwenden sind.
3.3 Implementierung
Das Projekt teilt sich in backend und webapp (Frontend). Diese sind Subprojekte des
Hauptprojektes. Nachdem die Arbeitsumgebung eigerichtet ist, soll Im Root-Ordner des
Hauptprojektes die Struktur folgendermaßen aussehen:
Abbildung 5
Inhalte des Hauptprojektes:
pom.xml: Maven Konfiguration des Hauptprojektes. Hier werden Informationen zum
Projekt selbst, wie Name, Organisation oder Version angegeben, sowie Abhängigkeiten
(=Java-Bibliotheken, welche zum Bau des Projektes automatisch runtergeladen und
beigefügt werden), Erstellungsprofile, Plugins, usw.
build-<Plattform>-<Zielsystem>.cmd: Dies sind Build-Commands, mit denen die
Webanwendung für bestimmte Plattformen und Zielsysteme über die Windowskonsole
(CMD) oder Powershell-Konsole erstellt werden kann. Der Build der verschiedenen
Versionen erfolgt über Profile.
clean-package.cmd: Hier wird die Webanwendung mit den Standardprofilen erstellt.
13
concat-sql.cmd: Sind Views in der Anwendung definiert, so sammelt dieses Skript alle
SQL-Dateien (.sql) aus einem bestimmten Verzeichnis (wird später noch erwähnt) und
erzeugt daraus eine große SQL-Datei, mit der die Views bei der Installation auf einmal
installiert werden können. Die Datei muss von Hand erweitert werden, wenn neue SQL-
Dateien einbezogen werden sollen.
3.3.1 Backend der Portlets
3.3.1.1 Inhalte des Backendprojektes
Im Subprojekt Backend wird alles entwickelt, das für die Datenverarbeitung zuständig ist.
Abbildung 6
Inhalte des Backendprojektes:
pom.xml: Maven Konfiguration des Backendprojektes. Hier werden Informationen zum
Projekt selbst, wie Name, Organisation oder Version angegeben, sowie Abhängigkeiten
(=Java-Bibliotheken, welche zum Bau des Projektes automatisch runtergeladen und
beigefügt werden), Erstellungsprofile, Plugins, usw.
src/main/java: Hier findet die Implementierung der oben genannten
Datenverarbeitungsobjekte statt.
src/main/resources/i18n: Hier können Property-Dateien abgelegt werden, die im
Backend verfügbar sein müssen (z.B. wenn eine Übersetzung im Services stattfindet).
Dies ist insbesondere dann wichtig, wenn das Backend von mehreren Webanwendungen
verwendet werden soll.
src/main/resources/jasperreports: Hier werden die Templates für Jasperreports
abgelegt.
src/main/resources/mybatis: Hier werden die XML-Konfigurationen für die MyBatis-
Mapper abgelegt. In diesen sind die Statements für die im Mapper definierten Methoden
hinterlegt.
14
src/main/resources/setup/database: Hier werden die SQL-Dateien mit View-Definition
abgelegt.4
3.3.1.2 Erstellung von Backend der Portlets
Erstellung von Backend betrifft Im Wesentlichen dies:
POJO-Java-Beans für MyBatis (Java-Beans, die von den Repositories und Mappern
befüllt werden; die Datenobjekte)
MyBatis-Mapper (früher DAOs genannt; stellen Methoden für den Datenbankzugriff
bereit)
Services (die die Daten aufbereiten und die Schnittstelle zwischen Datenbank und
Frontend (Webapp) bilden)
3.3.2 Frontend der Portlets
3.3.2.1 Inhalte des Webappprojektes
Im Subprojekt webapp wird das komplette Frontend entwickelt. Dies beinhaltet alles, das der
Benutzer sehen und mit dem der Anwender interagieren kann. Zusätzlich dazu muss hier die
Schnittstelle zwischen Backend und GUI entstehen.
4 Interne Quelle
16
Inhalte des Webappprojektes:
pom.xml: Maven Konfiguration des Webappprojektes. Hier werden Informationen zum
Projekt selbst, wie Name, Organisation oder Version angegeben, sowie Abhängigkeiten
(=Java-Bibliotheken, welche zum Bau des Projektes automatisch runtergeladen und
beigefügt werden), Erstellungsprofile, Plugins, usw.
src/main/java: Hier findet die Implementierung der Schnittstellen von GUI und Backend
statt. Dies erfolgt in EPF2 mittels Spring-Controllern.
src/main/resources/config/spring: Hier werden unter anderem die Spring-
Konfigurationen der Portlets abgelegt, sowie eine Anwendungskonfiguration.
src/main/resources/config/spring/applicationContext.xml: Dies ist die Spring-
Hauptkonfiguration der Anwendung. In dieser Datei werden die anderen XML-Dateien
des Verzeichnisses zusammengeführt und die zu ladenden Übersetzungsdateien
definiert
src/main/resources/config/spring/datasource.xml: Hier werden die Datasources für
den Datenbankzugriff über MyBatis definiert. Für die lokale Entwicklung befindet sich
diese Datei unter src/main/enf/development/config/spring.
src/main/resources/config/spring/db.xml: Erweiterte MyBatis Konfiguration
src/main/resources/config/spring/fileshare.xml: Hier wird der Zugriff auf den Fileshare
konfiguriert.
src/main/resources/config/spring/mybatis.xml: Die Basis-Mybatis-Konfiguration.
src/main/resources/config/spring/user-role-mapping: Die Konfiguration für die
Sicherheitsabfragen.
src/main/resources/config/env.properties: Hier werden sämtliche
Konfigurationsparameter wie Datenbank-URL / Benutzer / Passwort usw. hinterlegt.
src/main/resources/config/roles.csv: In dieser Datei können Anwendungsfunktionen
definiert werden und diese dann Anwendungsrollen zugewiesen werden.
src/main/resources/i18n: Hier können Property-Dateien abgelegt werden, die im
Frontend verfügbar sein müssen (z.B. für Tabellenüberschriften).
src/main/resources/logback.xml: Hier wird das Logging der Anwendung konfiguriert.
src/main/env/<System>: Hier werden die Parameter für unterschiedliche Systeme
(siehe Build des Hauptprojektes) konfiguriert.
src/main/webapp/css: Alles was mit der Gestaltung des Frontends mit CSS zu tun hat
ist hier richtig.
src/main/webapp/images: Hier werden Bilder hinterlegt.
src/main/webapp/js: Alle Javascript-Dateien werden hier abgelegt.
src/main/webapp/WEB-INF/jsp: Hier werden die JSPs für die Anzeige der Daten
entwickelt.
17
src/main/webapp/WEB-INF/liferay-display.xml: In dieser Datei werden die
Informationen für das Hinzufügen eines Portlets auf eine Seite im Liferay hinterlegt. Die
Portlets können hier gruppiert werden.
src/main/webapp/WEB-INF/liferay-portlet.xml: In dieser Datei werden die Portlets für
den Liferay konfiguriert. Hier kann auch eingestellt werden, welche Rollen Zugriff auf das
Portlet haben sollen und welche Javascript-/CSS-Ressourcen von Portlet automatisch
mitgeladen werden sollen, dies erspart einen separaten Import der entsprechenden
Dateien in den jeweiligen JSPs
src/main/webapp/WEB-INF/portlet.xml: In dieser Datei werden die Portlets für die
Portlet-Applikation laut JSR286 konfiguriert.
src/main/webapp/WEB-INF/web.xml: Konfiguration der Web-Anwendung. Dies
umschließt die Seiten-Struktur, Aufruf-Filter, Kontext-Parameter (/Resources), Sicherheit
(z.B. Nutzer-Anmeldung), Start- & Fehler-Seite, uvm.5
3.3.2.2 Erstellung von Frontend der Portlets
Erstellung von Frontend betrifft Im Wesentlichen dies:
Java-Controllers.
Sie sind für Verbindung zwischen Services und GUI geeignet. Im Controller wird definiert,
welche jsp Seite die erste Aufruf Seite ist. Außerdem wird da Business Logik organisiert.
Java-Beans und Search-Beans
Beans, die von den Controller benutzt werden, um dann sich mit Beans von Backend in
Verbindung zu setzen.
JavaServer Pages.
JavaServer Pages, abgekürzt JSP, ist auf JHTML basierende Web-Programmiersprache
zur einfachen dynamischen Erzeugung von HTML- und XML-Ausgaben eines
Webservers.
Sie erlaubt, Java-Code und spezielle JSP-Aktionen in HTML- oder XML-Seiten
einzubetten. Dabei ermöglicht es die JSP-Syntax, mittels spezieller XML-Tags (JSP-
Aktionen) vordefinierte Funktionalität einzubinden.
5 Interne Quelle
18
4 Projektergebnisse
Die Portlets „Handlungsfelder“ und „Kennzahlen“ wurden von mir implementiert.
Das Portlet „Handlungsfelder“ (Analyse Markt):
Abbildung 8
21
Das Portlet „Kennzahlen“ (Kennzahlen Service):
Abbildung 11
Auf den Abbildungen 8-11 wird präsentiert, welche Portlets implementiert wurden.
22
4.1 Soll-Ist-Vergleich
Bisher können die Systemwerte nur über die Datenbank direkt gepflegt werden. Durch die
Erweiterung erhalten die Anwendungsbenutzer die Möglichkeit, diese über eine grafische
Oberfläche innerhalb der bestehenden Anwendung zu konfigurieren.
Wie im 1.3 Kapitel erwähnt, gab’s eine Spezifikation zu Portlets. Die Portlets wurden nach
Spezifikation implementiert. Dabei werden beachtet, dass Portlets ganze Funktionalität
verfügen wie in der Spezifikation beschrieben ist.
4.2 Qualitätskontrolle
Es wurde eine Projektabnahme durch den Projektleiter durchgeführt. Dabei werden ein paar
Hinweisen vom Projektleiter gesagt, z.B. welche GUI-Elemente am besten benutzt werden
sollen und wie die Methoden von Controllers umprogrammiert werden sollen, dass weniger
Code gibt.
4.3 Fazit
Innerhalb der Implementierungsphase der Projektarbeit wurden von mir verschiedene
Probleme erkannt, die behoben werden mussten. Am häufigsten sind Probleme mit GUI
Elementen von dem DOJO Framework aufgetreten. Das Lesen von der offiziellen
Dokumentation dieses Frameworks hat zur Lösungsfindung beigetragen. Es entstanden
zusätzlich immer kleine Probleme entweder in Controller oder in JSP Seiten, die im DEBUG-
Modus behoben wurden.
23
5 Abkürzungsverzeichnis
Aqua Data Studio (Databank-Tool) - visuelles Datenbank-Abfrage- und
Verwaltungswerkzeug, das in der Programmiersprache Java entwickelt wird. Es ist für die
Plattformen Windows, Linux sowie Mac OS X verfügbar.
Applikation Server - ein Server in einem Computernetzwerk, der Anwendungsprogramme
ausführt. Im engeren Sinne bezeichnet der Begriff eine Software, die spezielle Dienste zur
Verfügung stellt, wie beispielsweise Transaktionen, Authentifizierung oder den Zugriff auf
Verzeichnisdienste, Webservices und Datenbanken über definierte Schnittstellen.
CSS - Cascading Style Sheets für gestufte Gestaltungsbögen), kurz CSS genannt, ist eine
Stylesheet-Sprache für elektronische Dokumente und zusammen mit HTML und DOM eine
der Kernsprachen des World Wide Webs
DOJO (JavaScript Frontend) - eine freie, modulare JavaScript-Bibliothek, die zur raschen
Entwicklung von JavaScript- oder Ajax-basierenden Anwendungen und Websites dient.
EPF2 Framework – ein Portal Framework von E.I.S. Konzept
HTML - Die Hypertext Markup Language, abgekürzt HTML, ist eine textbasierte
Auszeichnungssprache zur Strukturierung digitaler Dokumente wie Texte mit Hyperlinks,
Bildern und anderen Inhalten.
JRebel – ein Werkzeug, welches das dynamische Deployen von Java Web-Applikationen in
einem Applikations-Server unterstützt
Java EE (Enterprise Edition) - abgekürzt Java EE oder früher J2EE, ist die Spezifikation
einer Softwarearchitektur für die transaktionsbasierte Ausführung von in Java
programmierten Anwendungen und insbesondere Web-Anwendungen. Sie ist eine der
großen Plattformen, die um den Middleware-Markt kämpfen. Größter Konkurrent ist dabei die
.NET-Plattform von Microsoft.
JavaBeans - sind Software-Komponenten für die Programmiersprache Java. JavaBeans
werden auch als Container zur Datenübertragung verwendet. Daher zeichnen sich alle
24
JavaBeans durch folgende Eigenschaften aus:Öffentlicher parameterloser Konstruktor,
Serialisierbarkeit (Serializable), Öffentliche Zugriffsmethoden (Public Getters/Setters)
Javascript - ist eine Skriptsprache, die für dynamisches HTML in Webbrowsern entwickelt
wurde, um Benutzerinteraktionen auszuwerten, Inhalte zu verändern, nachzuladen oder zu
generieren und so die Möglichkeiten von HTML und CSS zu erweitern. Heute findet
JavaScript auch außerhalb von Browsern Anwendung, so etwa auf Servern und in
Microcontrollern
Liferay IDE - Eclipsebasierte Entwicklungsumgebung für Liferay Portal
Liferay-Portal (Server) - lizenzkostenfreie Open-Source-Software, die in Unternehmen als
Mitarbeiter- und Geschäftsprozess-orientiertes Enterprise Portal eingesetzt wird. Mit Liferay
können Informationen, Daten und Anwendungen unter einer einheitlichen
Bedienungsoberfläche im Browser des Mitarbeiters vereint und personalisiert werden, um
dadurch die Geschäftsprozesse im Unternehmen elektronisch zu unterstützen. Liferay Portal
ist in Java entwickelt.
Maven - ein Build-Management-Tool der Apache Software Foundation und basiert auf Java.
Mit ihm kann man insbesondere Java-Programme standardisiert erstellen und verwalten.
MyBatis - ein Open-Source-Persistenz-Framework für Java und .NET
Portlets - beliebig kombinierbare Komponenten einer Benutzeroberfläche, die von einem
Portalserver angezeigt und verwaltet werden. Sie erzeugen Fragmente von HTML-Code und
fügen sich in einer Portalseite ein. Typischerweise besteht eine Portalseite aus vielen, nicht-
überlappenden Portlet-Fenstern („Kacheln“), in denen jeweils ein Portlet ausgeführt wird.
Spring - ist ein Framework für die Java-Plattform. Ziel des Spring Frameworks ist es, die
Entwicklung mit Java/Java EE zu vereinfachen und gute Programmierpraktiken zu fördern.
25
6 Literaturverzeichnis
1. Interne Spezifikation für das Projekt
2. Interne Quellen (interne Unterlagen)
3. DOJO Dokumentation https://dojotoolkit.org/documentation/
7 Anlage mit der Dokumentation des Quellcodes aus der Implementierungsphase
7.1 Backend vom Portlet „Handlungsfelder“
package com.eiskonzept.portal.prm2.mapper.handlungsfeld;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import com.eiskonzept.portal.prm2.domain.handlungsfeld.Handlungsfeld;
import com.eiskonzept.portal.prm2.domain.handlungsfeld.Handlungsfeld2SGP;
@Component
public interface HandlungsfeldMapper {
public List<Handlungsfeld> listHandlungsfelderByFilter(@Param("typ") Integer typ,
@Param("datum") Date datum);
public List<Handlungsfeld> listChildHandlungsfelder(@Param("parentId") Integer parentId);
public void insertHandlungsfeld(@Param("bean") Handlungsfeld feld, @Param("typ") Integer
typ,
@Param("userId") Integer userId);
public void updateHandlungsfeld(@Param("bean") Handlungsfeld feld, @Param("typ")
Integer typ,
26
@Param("userId") Integer userId);
public Handlungsfeld getHandlungsfeld(final @Param("id") Integer id);
public Handlungsfeld2SGP getHandlungsfeld2SGP(final @Param("id") Integer id);
public void insertHandlungsfeld2SGP(@Param("bean") Handlungsfeld2SGP bean);
public void updateHandlungsfeld2SGP(@Param("bean") Handlungsfeld2SGP bean);
}
//
package com.eiskonzept.portal.prm2.service.handlungsfeld;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.eiskonzept.portal.prm2.domain.handlungsfeld.Handlungsfeld;
import com.eiskonzept.portal.prm2.domain.user.User;
import com.eiskonzept.portal.prm2.mapper.handlungsfeld.HandlungsfeldMapper;
import com.eiskonzept.portal.prm2.mapper.user.UserMapper;
@Component
public class HandlungsfeldService {
27
@Autowired
private HandlungsfeldMapper handlungsfeldMapper;
@Autowired
private UserMapper userMapper;
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.NEVER)
public List<Handlungsfeld> listHandlungsfelderByFilter(final Integer typ, final Date datum) {
return handlungsfeldMapper.listHandlungsfelderByFilter(typ, datum);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void insertlistHandlungsfelderByFilter(final Handlungsfeld feld, final Integer typ, final Integer
userId) {
handlungsfeldMapper.insertHandlungsfeld(feld, typ, userId);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void storelistHandlungsfelderByFilter(final Handlungsfeld feld, final Integer typ, final Integer
userId) {
handlungsfeldMapper.updateHandlungsfeld(feld, typ, userId);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void storeHandlungsfelder(List<Handlungsfeld> list, Integer typ, String userLogin) {
//Collections.sort(list);
User user = userMapper.getUserByLogin(userLogin);
//int sort = 1;
for (Handlungsfeld f : list) {
28
//f.setSort(sort);
if (f.getId() == null || f.getId() < 0) {
handlungsfeldMapper.insertHandlungsfeld(f, typ, user.getId());
} else {
handlungsfeldMapper.updateHandlungsfeld(f, typ, user.getId());
}
//sort++;
}
}
// Children
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.NEVER)
public List<Handlungsfeld> listChildHandlungsfelder(final Integer id) {
return handlungsfeldMapper.listChildHandlungsfelder(id);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void storeChildHandungsfelder(List<Handlungsfeld> list, Integer typ, Integer parentId, String
userLogin) {
User user = userMapper.getUserByLogin(userLogin);
// int sort = 1;
for (Handlungsfeld f : list) {
// f.setSort(sort);
if (f.getId() == null || f.getId() < 0) {
f.setParent(parentId);
handlungsfeldMapper.insertHandlungsfeld(f, typ, user.getId());
} else {
handlungsfeldMapper.updateHandlungsfeld(f, typ, user.getId());
}
// sort++;
}
29
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.NEVER)
public Handlungsfeld getHandlungsfeld(final int id){
return handlungsfeldMapper.getHandlungsfeld(id);
}
}
//
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.eiskonzept.portal.prm2.mapper.handlungsfeld.HandlungsfeldMap
per">
<select id="listHandlungsfelderByFilter" resultType="handlungsfeld">
select
HDF_ID as "id",
HDF_BEZEICHNUNG as "bezeichnung",
HDF_PARENT as "parent",
HDF_GRUPPE as "gruppe",
HDF_SORT as "sort",
HDF_HINWEIS as "hinweis",
HDF_GUELTIG_VON as "gueltigVon",
HDF_GUELTIG_BIS as "gueltigBis",
HDF_DELETED as "deleted",
HDF_PARTNER as "partner",
HDF_UCR as "ucr",
HDF_ULC as "ulc",
(SELECT COUNT(*) FROM PRM2.SGP_HANDLUNGSFELD F0 WHERE F0.HDF_PARENT =
F.HDF_ID and HDF_DELETED ='N') AS "childCount"
from PRM2.SGP_HANDLUNGSFELD F
where HDF_GRUPPE = #{typ}
and HDF_PARENT IS NULL
and HDF_PARTNER IS NULL
and HDF_DELETED ='N'
<if test="datum != null">
and (HDF_GUELTIG_VON IS NULL OR HDF_GUELTIG_VON <= #{datum})
and (HDF_GUELTIG_BIS IS NULL OR HDF_GUELTIG_BIS >= #{datum})
</if>
order by
HDF_SORT asc
</select>
<select id="listChildHandlungsfelder" resultType="handlungsfeld">
select
HDF_ID as "id",
HDF_BEZEICHNUNG as "bezeichnung",
HDF_PARENT as "parent",
HDF_GRUPPE as "gruppe",
HDF_SORT as "sort",
HDF_HINWEIS as "hinweis",
30
HDF_GUELTIG_VON as "gueltigVon",
HDF_GUELTIG_BIS as "gueltigBis",
HDF_DELETED as "deleted",
HDF_PARTNER as "partner",
HDF_UCR as "ucr",
HDF_ULC as "ulc"
from PRM2.SGP_HANDLUNGSFELD
where HDF_PARENT = #{parentId}
and HDF_PARTNER IS NULL
and HDF_DELETED ='N'
order by
HDF_SORT asc
</select>
<insert id="insertHandlungsfeld" flushCache="true"
statementType="PREPARED" timeout="20" keyProperty="bean.id"
keyColumn="HDF_ID" useGeneratedKeys="true">
INSERT INTO PRM2.SGP_HANDLUNGSFELD (HDF_BEZEICHNUNG, HDF_PARENT,
HDF_GRUPPE, HDF_SORT, HDF_HINWEIS, HDF_GUELTIG_VON, HDF_GUELTIG_BIS,
HDF_DELETED, HDF_UCR, HDF_ULC, HDF_PARTNER)
VALUES(#{bean.bezeichnung}, #{bean.parent}, #{typ}, #{bean.sort},
#{bean.hinweis}, #{bean.gueltigVon}, #{bean.gueltigBis}, #{bean.deleted},
#{userId}, #{userId}, #{bean.partner})
</insert>
<update id="updateHandlungsfeld" flushCache="true"
statementType="PREPARED" timeout="20">
UPDATE PRM2.SGP_HANDLUNGSFELD
SET
HDF_BEZEICHNUNG = #{bean.bezeichnung},
HDF_PARENT = #{bean.parent},
HDF_GRUPPE = #{typ},
HDF_SORT = #{bean.sort},
HDF_HINWEIS = #{bean.hinweis},
HDF_GUELTIG_VON = #{bean.gueltigVon},
HDF_GUELTIG_BIS = #{bean.gueltigBis},
HDF_DELETED = #{bean.deleted},
HDF_ULC = #{userId},
HDF_PARTNER = #{bean.partner}
WHERE HDF_ID = #{bean.id}
</update>
<select id="getHandlungsfeld" resultType="handlungsfeld">
select
HDF_ID as "id",
HDF_BEZEICHNUNG as "bezeichnung",
HDF_PARENT as "parent",
HDF_GRUPPE as "gruppe",
HDF_SORT as "sort",
HDF_HINWEIS as "hinweis",
HDF_GUELTIG_VON as "gueltigVon",
HDF_GUELTIG_BIS as "gueltigBis",
HDF_DELETED as "deleted",
HDF_PARTNER as "partner",
HDF_UCR as "ucr",
HDF_ULC as "ulc",
(SELECT COUNT(*) FROM PRM2.SGP_HANDLUNGSFELD F0 WHERE F0.HDF_PARENT =
F.HDF_ID) AS "childCount"
from PRM2.SGP_HANDLUNGSFELD F
where HDF_ID = #{id}
</select>
31
<select id="getHandlungsfeld2SGP" resultType="handlungsfeld2SGP">
SELECT
HDF2SGP_ID AS "id",
HDF2SGP_SGPID AS "sgpId",
HDF2SGP_HDF AS "hdf",
HDF2SGP_SORT AS "sort",
HDF2SGP_DELETED AS "deleted",
HDF2SGP_UCR AS "ucr",
HDF2SGP_ULC AS "ulc"
FROM PRM2.SGP_HANDLUNGSFELD2SGP
WHERE HDF2SGP_ID = #{id}
</select>
<insert id="insertHandlungsfeld2SGP" flushCache="true"
statementType="PREPARED" timeout="20" keyProperty="bean.id"
keyColumn="HDF2SGP_ID" useGeneratedKeys="true">
INSERT INTO PRM2.SGP_HANDLUNGSFELD2SGP (HDF2SGP_SGPID, HDF2SGP_HDF,
HDF2SGP_SORT, HDF2SGP_DELETED, HDF2SGP_UCR, HDF2SGP_ULC)
VALUES(#{bean.sgpId}, #{bean.hdf}, #{bean.sort}, #{bean.deleted},
#{bean.ucr}, #{bean.ulc})
</insert>
<update id="updateHandlungsfeld2SGP" flushCache="true"
statementType="PREPARED" timeout="20">
UPDATE PRM2.SGP_HANDLUNGSFELD2SGP
SET
HDF2SGP_SORT = #{bean.sort},
HDF2SGP_DELETED = #{bean.deleted},
HDF2SGP_ULC = #{bean.ulc}
WHERE HDF2SGP_ID = #{bean.id}
</update>
</mapper>
7.2 Backend vom Portlet „Kennzahlen“
package com.eiskonzept.portal.prm2.mapper.kennzahlen;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import com.eiskonzept.portal.prm2.domain.kennzahlen.KennzahlenAdmin;
@Component
public interface KennzahlenAdminMapper {
32
public List<KennzahlenAdmin> listKennzahlenAdminByFilter(@Param("kennz_bereich")
String kennz_bereich, @Param("datum") Integer datum);
public void insertKennzahlenAdmin(@Param("bean") KennzahlenAdmin bean,
@Param("typ") String typ, @Param("userId") Integer userId);
public void updateKennzahlenAdmin(@Param("bean") KennzahlenAdmin bean,
@Param("typ") String typ, @Param("userId") Integer userId);
}
//
package com.eiskonzept.portal.prm2.service.kennzahlen;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.eiskonzept.portal.prm2.domain.kennzahlen.KennzahlenAdmin;
import com.eiskonzept.portal.prm2.domain.kennzahlen.KennzahlenGruppe;
import com.eiskonzept.portal.prm2.domain.user.User;
import com.eiskonzept.portal.prm2.mapper.kennzahlen.KennzahlenAdminMapper;
import com.eiskonzept.portal.prm2.mapper.kennzahlen.KennzahlenGruppeAdminMapper;
import com.eiskonzept.portal.prm2.mapper.user.UserMapper;
@Component
public class KennzahlenAdminService {
@Autowired
33
private KennzahlenAdminMapper kennzahlenAdminMapper;
@Autowired
private KennzahlenGruppeAdminMapper kennzahlenGruppeAdminMapper;
@Autowired
private UserMapper userMapper;
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.NEVER)
public List<KennzahlenAdmin> listKennzahlenAdminByFilter(final String kennz_bereich,
final Integer datum) {
return kennzahlenAdminMapper.listKennzahlenAdminByFilter(kennz_bereich, datum);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void insertlistKennzahlenAdminByFilter(final KennzahlenAdmin feld, final String typ,
final Integer userId) {
kennzahlenAdminMapper.insertKennzahlenAdmin(feld,typ, userId);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void updateKennzahlenAdmin(final KennzahlenAdmin feld, final String typ, final
Integer userId) {
kennzahlenAdminMapper.updateKennzahlenAdmin(feld,typ, userId);
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.REQUIRES_NEW)
public void storeKennzahlenAdmin(List<KennzahlenAdmin> list, String typ, String
userLogin) {
User user = userMapper.getUserByLogin(userLogin);
34
// int sort = 1;
for (KennzahlenAdmin f : list) {
// f.setSort(sort);
if (f.getId() == null || f.getId() < 0) {
kennzahlenAdminMapper.insertKennzahlenAdmin(f, typ, user.getId());
} else {
kennzahlenAdminMapper.updateKennzahlenAdmin(f, typ, user.getId());
}
// sort++;
}
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation =
Propagation.NEVER)
public List<KennzahlenGruppe> listKennzahlenGruppe() {
return kennzahlenGruppeAdminMapper.listKennzahlenGruppe();
}
}
//
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.eiskonzept.portal.prm2.mapper.kennzahlen.KennzahlenAdminMapp
er">
<select id="listKennzahlenAdminByFilter"
resultType="kennzahlenAdmin">
SELECT
KENNZ_ID as "id",
KENNZ_BEZEICHNUNG as "bezeichnung",
KENNZ_BEREICH as "kennz_bereich",
KENNZ_SORT as "sort",
KENNZ_NACHKOMMA as "nachkoma",
KENNZ_EINHEIT_INFO as "kennz_einheit_info",
KENNZ_GRUPPE as "kennz_gruppe",
KENNZ_DELETED as "deleted",
KENNZ_GUELTIG_VON as "gueltigVon",
KENNZ_GUELTIG_BIS as "gueltigBis",
KENNZ_KEY_MART as "kennz_key_mart",
KENNZ_HINWEIS as "hinweis",
KENNZ_UCR as "ucr",
KENNZ_ULC as "ulc"
35
FROM PRM2.SGP_KENNZAHL
WHERE KENNZ_BEREICH = #{kennz_bereich}
and KENNZ_DELETED ='N'
<if test="datum != null">
and (KENNZ_GUELTIG_VON IS NULL OR KENNZ_GUELTIG_VON <= #{datum})
and (KENNZ_GUELTIG_BIS IS NULL OR KENNZ_GUELTIG_BIS >= #{datum})
</if>
order by
KENNZ_SORT asc
</select>
<insert id="insertKennzahlenAdmin" flushCache="true"
statementType="PREPARED" timeout="20" keyProperty="bean.id"
keyColumn="KENNZ_ID" useGeneratedKeys="true">
INSERT INTO prm2.sgp_kennzahl (KENNZ_BEZEICHNUNG, KENNZ_BEREICH,
KENNZ_SORT, KENNZ_NACHKOMMA, KENNZ_EINHEIT_INFO, KENNZ_GRUPPE,
KENNZ_DELETED, KENNZ_GUELTIG_VON, KENNZ_GUELTIG_BIS, KENNZ_KEY_MART,
KENNZ_HINWEIS, KENNZ_UCR, KENNZ_ULC)
VALUES(#{bean.bezeichnung}, #{typ}, #{bean.sort}, #{bean.nachkoma},
#{bean.kennz_einheit_info},#{bean.kennz_gruppe}, #{bean.deleted},
#{bean.gueltigVon},
#{bean.gueltigBis},#{bean.kennz_key_mart},#{bean.hinweis}, #{userId},
#{userId})
</insert>
<update id="updateKennzahlenAdmin" flushCache="true"
statementType="PREPARED" timeout="20">
UPDATE PRM2.sgp_kennzahl
SET
KENNZ_BEZEICHNUNG = #{bean.bezeichnung},
KENNZ_BEREICH = #{typ},
KENNZ_SORT = #{bean.sort},
KENNZ_NACHKOMMA = #{bean.nachkoma},
KENNZ_EINHEIT_INFO = #{bean.kennz_einheit_info},
KENNZ_GRUPPE = #{bean.kennz_gruppe},
KENNZ_DELETED = #{bean.deleted},
KENNZ_GUELTIG_VON = #{bean.gueltigVon},
KENNZ_GUELTIG_BIS = #{bean.gueltigBis},
KENNZ_KEY_MART = #{bean.kennz_key_mart},
KENNZ_HINWEIS = #{bean.hinweis},
KENNZ_ULC = #{userId}
WHERE KENNZ_ID = #{bean.id}
</update>
</mapper>
//
7.3 Frontend vom Portlet „Handlungsfelder“
private List<HandlungsfelderBean> createList(List<Handlungsfeld>
listHandlungsfelderByFilter) {
List<HandlungsfelderBean> list = new ArrayList<HandlungsfelderBean>();
for (Handlungsfeld p : listHandlungsfelderByFilter) {
list.add(new HandlungsfelderBean(p));
36
}
return list;
}
}
//
package com.eiskonzept.portal.prm2_sgp.controller.administration.handlungsfelder;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class SearchBean implements Serializable {
private static final long serialVersionUID = -330664870279031977L;
private Integer typ;
private Integer id;
Integer parentId;
private Date gueltig;
private List<HandlungsfelderBean> list;
public Integer getTyp() {
return typ;
}
public void setTyp(Integer typ) {
37
this.typ = typ;
}
public Date getGueltig() {
return gueltig;
}
public void setGueltig(Date gueltig) {
this.gueltig = gueltig;
}
public List<HandlungsfelderBean> getList() {
return list;
}
public void setList(List<HandlungsfelderBean> list) {
this.list = list;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "SearchBean [typ=" + typ + ", id=" + id + ", partnerId=" + parentId + ", gueltig="
+ gueltig + ", list="
+ list + "]";
38
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
}
//
<%@ page import="de.eis.portlet.framework.util.SPRWindowState"%>
<%@ page trimDirectiveWhitespaces="true" %>
<%@ include file="/WEB-INF/jsp/epf2/include.jsp"%>
<%@ taglib prefix="spr" uri="http://eiskonzept.com/eis-spr"%>
<%@ taglib prefix="epf2" uri="http://eiskonzept.com/ns/epf2" %>
<%@ taglib prefix="eis" uri="http://eiskonzept.com/ns/epf2-nav"%>
<div id="${ns}content" class="claro prm Collage">
<%@ include file="/WEB-INF/jsp/epf2/inc-header.jsp"%>
<spr:actionURL var="urlStore"
windowState="<%=SPRWindowState.EXCLUSIVE.toString()%>">
<portlet:param name="action" value="storeHandlungsfelder" />
</spr:actionURL>
<spr:actionURL var="urlSearch"
windowState="<%=SPRWindowState.EXCLUSIVE.toString()%>">
<portlet:param name="action" value="searchHandlungsfelder" />
</spr:actionURL>
<spr:actionURL var="childSearch"
windowState="<%=SPRWindowState.EXCLUSIVE.toString()%>">
<portlet:param name="action" value="searchChildHandlungsfelder" />
</spr:actionURL>
<eis:nav label="Zurück zur Übersicht" key="analyse.handlungsfeldliste"
spr="true"
windowState="<%=SPRWindowState.EXCLUSIVE.toString()%>"
root="true">
<eis:nav-param name="action"
value="searchHandlungsfelder" />
<eis:nav-param name="typ" value="${searchBean.typ}"
postParam="true"/>
39
<eis:nav-param name="id" value="${searchBean.id}"
postParam="true"/>
<eis:nav-param name="gueltig"
value="${searchBean.gueltig}" postParam="true"/>
</eis:nav>
<div id="${ns}tabcontainer">
<div id="${ns}tab">
<form:form id="${ns}filterForm" modelAttribute="searchBean"
data-dojo-type="eisdojo/EisForm" method="POST">
<div class="searchbar">
<div class="styled-select searchbarItem">
<div class="searchbarItem">
<label for="${ns}gueltig">
<spring:message
code="txt.sgp.portlet.sgphandlungsfelder.label.gueltig" />
</label>
<form:input
path="gueltig"
id="${ns}gueltig"
data-dojo-type="eisdojo/EisDateTextBox"
onkeyup="return eventOnEnter(event,
function(){${ns}search();});"
/>
</div>
<div class="searchbarItem">
<button type="button" class="btn-sekundaer icon-
search" onclick="${ns}search();">
<span>
<spring:message
code="txt.sgp.portlet.sgphandlungsfelder.label.suchen" />
</span>
</button>
</div>
</div>
</div>
<%@ include file="table.jsp"%>
</form:form>
</div>
</div>
<script type="text/javascript">
var ${ns}qedit = null;
require(["eisdojo/EisQuickEditUtil", 'eisdojo/EisDateTextBox',
'dojo/domReady!'],function(QuickEditUtil){
${ns}qedit = new QuickEditUtil({tableId:
'handlungsfeldertable${ns}', ns:'${ns}', hiddenRow:true});
${ns}qedit.initSortButtons();
40
});
function moveRowUp${ns}(item){
${ns}qedit.moveRowUp(item);
}
function moveRowDown${ns}(item){
${ns}qedit.moveRowDown(item);
}
function removeRow${ns}(item){
if (confirm("Wollen Sie das Handlungsfeld wirklch löschen?
Klicken Sie auf OK, um das Handlungsfeld zu löschen"))
{
${ns}qedit.removeRow(item);
${ns}qedit.initSortButtons();
}
}
function childListOpen${ns}(id){
//alert('jo');
${ns}qedit.removeNewRow();
loadFormAsync('${ns}','${childSearch}',
'${ns}content','${ns}filterForm', {'parentId': id});
}
function ${ns}search() {
${ns}qedit.removeNewRow();
loadFormAsync('${ns}','${urlSearch}',
'${ns}content','${ns}filterForm');
};
function save${ns}() {
require(["dijit/registry"],function(registry) {
if (registry.byId('${ns}filterForm').validate()){
${ns}qedit.removeNewRow();
loadFormAsync('${ns}','${urlStore}',
'${ns}content','${ns}filterForm');
}
});
};
/*
function updateOptionen${ns}() {
loadFormAsync('${ns}','${urlSearch}',
'${ns}content','${ns}filterForm');
}
*/
function newHandlungsfeld${ns}(){
${ns}qedit.addNewRow();
// loadFormAsync('${ns}','${urlAdd}',
'${ns}content','${ns}filterForm');
}
// Search-Bar initialisieren
registerListForInstantiation(
[
41
'${ns}filterForm'
//, '${ns}selectedAktiv'
//, '${ns}selectedGruppe'*/
],
{
portlet: '${ns}',
init: true
}
);
// Tabelle initialisieren
//registerGroupForInstantiation('handlungsfeldertable${ns}',
{portlet:'${ns}', init: true});
//registerForInstantiation({portlet: '${ns}', id: '${ns}gueltig',
init: true});
function ${ns}disableDates(checked){
require(['dijit/registry'],function(registry) {
registry.byId('${ns}gueltig').set('disabled', !checked);
});
${ns}search();
}
<%@ include file="tabs.jsp"%>
</script>
<%@ include file="/WEB-INF/jsp/epf2/inc-footer.jsp"%>
</div> <!-- content -->
//
<table class="etable eistable" style="width: 100%; margin-top: 10px;
margin-bottom: 10px; vertical-align: top;" id="handlungsfeldertable${ns}">
<tr class="head eistablerow eistablerowheader">
<td class="eistablecell
eistablecellheader">Position</td>
<td class="eistablecell
eistablecellheader">Handlungsfeld*</td>
<td class="eistablecell eistablecellheader">Hinweis
für GL/Händler</td>
<td class="eistablecell eistablecellheader">Gültig
von</td>
<td class="eistablecell eistablecellheader">Gültig
bis</td>
<td class="eistablecell eistablecellheader"></td>
</tr>
<c:set var="listEmpty" value="${empty searchBean.list}"/>
42
<c:if test="${!listEmpty}">
<c:forEach items="${searchBean.list}" var="handlungsfeld"
varStatus="handlungsfeldStatus">
<c:if test="${!handlungsfeld.deleted}">
<tr class="qedit_sortable_row">
<td class="eistable_hidden">
<form:hidden
path="list[${handlungsfeldStatus.index}].id"
value="${handlungsfeld.id}" />
<form:hidden
class="qedit_sort_indicator"
path="list[${handlungsfeldStatus.index}].sort"
value="${handlungsfeld.sort}" />
<form:hidden
class="qedit_delete_indicator"
path="list[${handlungsfeldStatus.index}].deleted" value="false" />
<form:hidden
path="list[${handlungsfeldStatus.index}].ucr"
value="${handlungsfeld.ucr}" />
<form:hidden
path="list[${handlungsfeldStatus.index}].ulc"
value="${handlungsfeld.ulc}" />
</td>
<td style="width: 50px; text-align:
center; vertical-align: top;" align="center" >
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_up" onclick="moveRowUp${ns}(this)" ><span
class="icon-button-up"></span></button>
</div>
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_down"
onclick="moveRowDown${ns}(this)"><span class="icon-button-
down"></span></button>
</div>
</td>
<td style="width: 300px; vertical-align:
top;"><form:input id="${ns}bezeichnung.${handlungsfeldStatus.index}"
type="text"
path="list[${handlungsfeldStatus.index}].bezeichnung"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-props ="required:true"
style="width:100%" /></td>
<td style="width:200px; vertical-align:
top;"><form:textarea id="${ns}hinweis.${handlungsfeldStatus.index}"
path="list[${handlungsfeldStatus.index}].hinweis"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-
props="value:'${handlungsfeld.hinweis}'"
43
style="width:100%" /></td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<form:input
id="${ns}gueltigVon.${handlungsfeldStatus.index}"
path="list[${handlungsfeldStatus.index}].gueltigVon"
data-dojo-
type="eisdojo/EisDateTextBox" />
</td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<form:input
id="${ns}gueltigBis.${handlungsfeldStatus.index}"
path="list[${handlungsfeldStatus.index}].gueltigBis"
data-dojo-
type="eisdojo/EisDateTextBox" />
</td>
<td>
<button type="button"
style="background-color: #a9a2a7;"
onclick="childListOpen${ns}(${handlungsfeld.id})">
Unterpunkte
(${handlungsfeld.childCount})
</button>
</td>
<td style="text-align: center; width:
60px; vertical-align: top; border-right: none;">
<button type="button"
class="btn-no-button qedit_remove" onclick="removeRow${ns}(this)">
<div style="display:
table-cell; text-align: center; vertical-align: middle;" class="icon-minus-
circle">
</div>
<div style="display:
table-cell; text-align: center; vertical-align: middle;" >
<span
class="underlineBtn">Löschen</span>
</div>
</button>
</td>
</tr>
</c:if>
</c:forEach>
</c:if>
<tr class="qedit_hiddenrow qedit_sortable_row">
<td class="eistable_hidden">
<input type="hidden" name="list[].id"
value="-1" />
<input type="hidden" name="list[].sort"
value="-1" class="qedit_sort_indicator"/>
44
<input type="hidden"
name="list[].deleted" value="false" class="qedit_delete_indicator"/>
</td>
<td style="width: 50px">
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_up" onclick="moveRowUp${ns}(this)"><span
class="icon-button-up"></span></button>
</div>
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_down"
onclick="moveRowDown${ns}(this)"><span class="icon-button-
down"></span></button>
</div>
</td>
<td style="width: 300px; vertical-align:
top;">
<input
type="text"
name="list[].bezeichnung" value=""
data-dojo-
type0="dijit/form/ValidationTextBox" data-dojo-props="required:true"
style="width:100%" />
</td>
<td style="width:200px; vertical-align: top;">
<input
type="text"
name="list[].hinweis" value=""
data-dojo-
type0="dijit/form/ValidationTextBox" data-dojo-prop=""
style="width:100%" />
</td>
<td align="center" style="vertical-align: top;
text-align: center; width: 80px; ">
<input type="text"
name="list[].gueltigVon"
value=""
data-dojo-
type0="eisdojo/EisDateTextBox" />
</td>
<td align="center" style="vertical-align: top;
text-align: center; width: 80px; ">
<input type="text"
name="list[].gueltigBis"
value=""
data-dojo-
type0="eisdojo/EisDateTextBox" />
</td>
<td>
</td>
45
<td style="text-align: center; vertical-align:
middle; border-right: none;">
<button type="button" class="btn-
no-button qedit_remove" onclick="removeRow${ns}(this)">
<div style="display: table-
cell; text-align: center; vertical-align: middle;" class="icon-minus-
circle">
</div>
<div style="display: table-
cell; text-align: center; vertical-align: middle;"><span>Löschen</span>
</div>
</button>
</td>
</tr>
</table>
<button type="button" class="btn-sekundaer icon-plus"
onclick="newHandlungsfeld${ns}()">Neues Handlungsfeld
hinzufügen</button>
<button type="button" class="btn-primaer icon-save"
style="float: right; margin-right: 50px;"
onclick="save${ns}()">Speichern</button>
7.4 Frontend vom Portlet „Kennzahlen“
<table class="etable eistable" style="width: 100%; margin-top: 10px;
margin-bottom: 10px; vertical-align: top;" id="kennzahlAdmintable${ns}">
<tr class="head eistablerow eistablerowheader">
<td class="eistablecell
eistablecellheader">Position</td>
<td class="eistablecell
eistablecellheader">Kennzahl*</td>
<td class="eistablecell
eistablecellheader">Nachkoma</td>
<td class="eistablecell eistablecellheader">KPI-
Schlüssel</td>
<td class="eistablecell eistablecellheader">Hinweis
für GL/Händler</td>
<td class="eistablecell
eistablecellheader">Kennzahlen Einheit Information</td>
<td class="eistablecell
eistablecellheader">Kennzahlen Gruppe</td>
<td class="eistablecell eistablecellheader">Gültig
von [Jahr]</td>
<td class="eistablecell eistablecellheader">Gültig
bis [Jahr]</td>
<td class="eistablecell eistablecellheader"></td>
</tr>
<c:set var="listEmpty" value="${empty searchBean.list}"/>
<c:if test="${!listEmpty}">
46
<c:forEach items="${searchBean.list}" var="kennzahlAdmin"
varStatus="kennzahladminStatus">
<c:if test="${!kennzahlAdmin.deleted}">
<tr class="qedit_sortable_row">
<td class="eistable_hidden">
<form:hidden
path="list[${kennzahladminStatus.index}].id"
value="${kennzahlAdmin.id}" />
<form:hidden
class="qedit_sort_indicator"
path="list[${kennzahladminStatus.index}].sort"
value="${kennzahlAdmin.sort}" />
<form:hidden
class="qedit_delete_indicator"
path="list[${kennzahladminStatus.index}].deleted" value="false" />
<form:hidden
path="list[${kennzahladminStatus.index}].ucr"
value="${kennzahlAdmin.ucr}" />
<form:hidden
path="list[${kennzahladminStatus.index}].ulc"
value="${kennzahlAdmin.ulc}" />
</td>
<td style="width: 50px; text-align:
center; vertical-align: top;" align="center" >
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_up" onclick="moveRowUp${ns}(this)" ><span
class="icon-button-up"></span></button>
</div>
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_down"
onclick="moveRowDown${ns}(this)"><span class="icon-button-
down"></span></button>
</div>
</td>
<td style="width: 300px; vertical-align:
top;"><form:input id="${ns}bezeichnung.${kennzahladminStatus.index}"
type="text"
path="list[${kennzahladminStatus.index}].bezeichnung"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-props ="required:true"
style="width:100%" /></td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px;"><form:input
id="${ns}nachkoma.${kennzahladminStatus.index}"
type="text"
path="list[${kennzahladminStatus.index}].nachkoma"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-props ="required:true"
style="width:100%" /></td>
47
<td style="width: 300px; vertical-align:
top;"><form:input id="${ns}kennz_key_mart.${kennzahladminStatus.index}"
type="text"
path="list[${kennzahladminStatus.index}].kennz_key_mart"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-
props="value:'${kennzahlAdmin.kennz_key_mart}'"
style="width:100%" /></td>
<td style="width:200px; vertical-align:
top;"><form:textarea id="${ns}hinweis.${kennzahladminStatus.index}"
path="list[${kennzahladminStatus.index}].hinweis"
data-dojo-
type="eisdojo/EisValidationTextArea" data-dojo-
props="value:'${kennzahlAdmin.hinweis}'"
style="width:100%" /></td>
<td style="width:200px; vertical-align:
top;"><form:textarea
id="${ns}kennz_einheit_info.${kennzahladminStatus.index}"
path="list[${kennzahladminStatus.index}].kennz_einheit_info"
data-dojo-
type="eisdojo/EisValidationTextArea" data-dojo-
props="value:'${kennzahlAdmin.kennz_einheit_info}'"
style="width:100%" /></td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<form:select
path="list[${kennzahladminStatus.index}].kennz_gruppe"
id="${ns}kennz_gruppe.${kennzahladminStatus.index}"
data-dojo-
type="dijit/form/Select" data-dojo-props ="required:true,
value:'${kennzahlAdmin.kennz_gruppe}'" cssStyle="width:280px;">
<form:options
items="${kennzahlenGruppeListe}"
itemValue="id"
itemLabel="bezeichnung" />
</form:select>
</td>
<%--
<td
<select name="select1" data-dojo-
type="dijit/form/Select">
<option
value="1">Kennzahlen</option>
<option value="2"
selected="selected">Simply Grow</option>
<option
value="3">Kundenzufriedenheit</option>
</select>
48
</td>
--%>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<form:input
id="${ns}gueltigVon.${kennzahladminStatus.index}"
path="list[${kennzahladminStatus.index}].gueltigVon"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-props="maxLength: 4, regExp:
'[0-9]{4}'"
style="width:100%" /></td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<form:input
id="${ns}gueltigBis.${kennzahladminStatus.index}"
path="list[${kennzahladminStatus.index}].gueltigBis"
data-dojo-
type="dijit/form/ValidationTextBox" data-dojo-props="maxLength: 4, regExp:
'[0-9]{4}'"
style="width:100%" /></td>
<td style="text-align: center; width:
60px; vertical-align: top; border-right: none;">
<button type="button"
class="btn-no-button qedit_remove" onclick="removeRow${ns}(this)">
<div style="display:
table-cell; text-align: center; vertical-align: middle;" class="icon-minus-
circle">
</div>
<div style="display:
table-cell; text-align: center; vertical-align: middle;" >
<span
class="underlineBtn">Löschen</span>
</div>
</button>
</td>
</tr>
</c:if>
</c:forEach>
</c:if>
<tr class="qedit_hiddenrow qedit_sortable_row">
<td class="eistable_hidden">
<input type="hidden" name="list[].id"
value="-1" />
<input type="hidden" name="list[].sort"
value="-1" class="qedit_sort_indicator"/>
<input type="hidden"
name="list[].deleted" value="false" class="qedit_delete_indicator"/>
</td>
49
<td style="width: 50px; text-align: center;
vertical-align: top;" align="center" >
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_up" onclick="moveRowUp${ns}(this)"><span
class="icon-button-up"></span></button>
</div>
<div
style="display:table-cell; width:30px;">
<button type="button"
class="btn-icon-only qedit_sort_down"
onclick="moveRowDown${ns}(this)"><span class="icon-button-
down"></span></button>
</div>
</td>
<td style="width: 300px; vertical-align:
top;">
<input
type="text"
name="list[].bezeichnung" value=""
data-dojo-
type0="dijit/form/ValidationTextBox" data-dojo-props="required:true"
style="width:100%" />
</td>
<td align="center" style="vertical-align: top;
text-align: center; width: 80px;">
<input
type="text"
name="list[].nachkoma" value=""
data-dojo-
type0="dijit/form/ValidationTextBox" data-dojo-props="required:true"
style="width:100%" />
</td>
<td style="width: 300px; vertical-align:
top;">
<input
type="text"
name="list[].kennz_key_mart" value=""
data-dojo-
type0="dijit/form/ValidationTextBox"
style="width:100%" />
</td>
<td style="width:200px; vertical-align:
top;">
<textarea
name="list[].hinweis"
value=""
data-dojo-
type0="eisdojo/EisValidationTextArea" data-dojo-props=""
style="width:100%"
></textarea>
</td>
<td style="width:200px; vertical-align:
top;">
50
<textarea
name="list[].kennz_einheit_info" value=""
data-dojo-
type0="eisdojo/EisValidationTextArea" data-dojo-props=""
style="width:100%"
></textarea>
</td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<select name="list[].kennz_gruppe"
data-dojo-type0="dijit/form/Select"
data-dojo-props ="required:true"
style="width:280px;">
<c:forEach var="kat"
items="${kennzahlenGruppeListe}">
<option
value="${kat.id}" >${kat.bezeichnung}</option>
</c:forEach>
</select>
</td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<input type="text"
name="list[].gueltigVon"
value="" data-dojo-props="maxLength:,4, regExp: '[0-9]{4}'"
data-dojo-
type0="dijit/form/ValidationTextBox" />
</td>
<td align="center" style="vertical-
align: top; text-align: center; width: 80px; ">
<input type="text"
name="list[].gueltigBis"
value="" data-dojo-props="maxLength: 4, regExp: '[0-9]{4}'"
data-dojo-
type0="dijit/form/ValidationTextBox" />
</td>
<td style="text-align: center; width: 60px;
vertical-align: top; border-right: none;">
<button type="button" class="btn-
no-button qedit_remove" onclick="removeRow${ns}(this)">
<div style="display: table-
cell; text-align: center; vertical-align: middle;" class="icon-minus-
circle">
</div>
<div style="display: table-
cell; text-align: center; vertical-align: middle;"><span>Löschen</span>
</div>
</button>
</td>
</tr>
</table>
<button type="button" class="btn-sekundaer icon-plus"
onclick="newAdminKennzahlenFeld${ns}()">Neue Kennzahl
hinzufügen</button>
51
<button type="button" class="btn-primaer icon-save"
style="float: right; margin-right: 50px;"
onclick="save${ns}()">Speichern</button>
//
<%@ page import="de.eis.portlet.framework.util.SPRWindowState"%>
<%@ page trimDirectiveWhitespaces="true" %>
<%@ include file="/WEB-INF/jsp/epf2/include.jsp"%>
<%@ taglib prefix="spr" uri="http://eiskonzept.com/eis-spr"%>
<%@ taglib prefix="epf2" uri="http://eiskonzept.com/ns/epf2" %>
<%@ taglib prefix="eis" uri="http://eiskonzept.com/ns/epf2-nav"%>
<div id="${ns}content" class="claro prm Collage">
<%@ include file="/WEB-INF/jsp/epf2/inc-header.jsp"%>
<spr:actionURL var="urlStore"
windowState="<%=SPRWindowState.EXCLUSIVE.toString()%>">
<portlet:param name="action" value="storeKennzahlenAdmin" />
</spr:actionURL>
<spr:actionURL var="urlSearch"
windowState="<%=SPRWindowState.EXCLUSIVE.toString()%>">
<portlet:param name="action" value="searchKennzahlenAdmin" />
</spr:actionURL>
<div id="${ns}tabcontainer">
<div id="${ns}tab">
<form:form id="${ns}filterForm" modelAttribute="searchBean"
data-dojo-type="eisdojo/EisForm" method="POST">
<div class="searchbar">
<div class="styled-select searchbarItem">
<div class="searchbarItem">
<label for="${ns}gueltig">
<spring:message
code="txt.sgp.portlet.sgphandlungsfelder.label.gueltig" />
</label>
<form:input
path="gueltig"
id="${ns}gueltig"
data-dojo-type="eisdojo/EisDateTextBox"
onkeyup="return eventOnEnter(event,
function(){${ns}search();});"
/>
</div>
<div class="searchbarItem">
<button type="button" class="btn-sekundaer icon-
search" onclick="${ns}search();">
<span>
52
<spring:message
code="txt.sgp.portlet.sgphandlungsfelder.label.suchen" />
</span>
</button>
</div>
</div>
</div>
<%@ include file="table.jsp"%>
</form:form>
</div>
</div>
<script type="text/javascript">
var ${ns}qedit = null;
require(["eisdojo/EisQuickEditUtil", 'eisdojo/EisDateTextBox',
"dojo/parser", "dijit/form/Select",
'dojo/domReady!'],function(QuickEditUtil){
${ns}qedit = new QuickEditUtil({tableId:
'kennzahlAdmintable${ns}', ns:'${ns}', hiddenRow:true});
${ns}qedit.initSortButtons();
});
function moveRowUp${ns}(item){
${ns}qedit.moveRowUp(item);
}
function moveRowDown${ns}(item){
${ns}qedit.moveRowDown(item);
}
function removeRow${ns}(item){
if (confirm("Wollen Sie die Kennzahl wirklch löschen? Klicken
Sie auf OK, um die Kennzahl zu löschen"))
{
${ns}qedit.removeRow(item);
${ns}qedit.initSortButtons();
}
}
function ${ns}search() {
${ns}qedit.removeNewRow();
loadFormAsync('${ns}','${urlSearch}',
'${ns}content','${ns}filterForm');
};
function save${ns}() {
require(["dijit/registry"],function(registry) {
if (registry.byId('${ns}filterForm').validate()){
${ns}qedit.removeNewRow();
53
loadFormAsync('${ns}','${urlStore}',
'${ns}content','${ns}filterForm');
}
});
};
function newAdminKennzahlenFeld${ns}(){
${ns}qedit.addNewRow();
}
// Search-Bar initialisieren
registerListForInstantiation(
[
'${ns}filterForm'
//, '${ns}selectedAktiv'
//, '${ns}selectedGruppe'*/
],
{
portlet: '${ns}',
init: true
}
);
// Tabelle initialisieren
//registerGroupForInstantiation('handlungsfeldertable${ns}',
{portlet:'${ns}', init: true});
//registerForInstantiation({portlet: '${ns}', id: '${ns}gueltig',
init: true});
function ${ns}disableDates(checked){
require(['dijit/registry'],function(registry) {
registry.byId('${ns}gueltig').set('disabled', !checked);
});
${ns}search();
}
<%@ include file="tabs.jsp"%>
</script>
<%@ include file="/WEB-INF/jsp/epf2/inc-footer.jsp"%>
</div> <!-- content -->