Die Webschicht
Eine Anwendung ohne Weboberfläche ist heutzutage natürlich keine echte Anwendung. Bei Roo wird hier auf Spring MVC zurückgegriffen, welches in der Version 3 ein sehr flexibles und ausgereiftes Webframework zur Verfügung stellt, mit dem sich auch Webanwendungen im REST-Stil einfach erstellen lassen. Um einen Spring MVC Controller mit den üblichen CRUD-Operationen und die JSP-Seiten dazu zu erstellen, bedarf es nur eines Befehls:
roo> controller scaffold --name ~.web.AdminRequestController
Wie bei den Eigenschaften vorher, muss auch hier die Domänenklasse nicht angegeben werden. Es wird automatisch die zuletzt erstellte verwendet. Die Klasse kann ansonsten auch mit dem Argument --entity angeben werden.
Die Funktionalitäten der Webschicht entstehen durch die in den Entitäten definierten Daten und Geschäftslogik. Abstrakter gesprochen definieren die Entitäten das Datenmodell der Anwendung und zwar durch Java-Code. Dieser wird nun untersucht, um dazu eine Webschicht zu generieren.
Jetzt wird es Zeit, Roo zu beenden und unsere Webanwendung mal anzusehen. Dazu sind folgende Befehle notwendig:
roo> quitmvn tomcat:run
Unter http://localhost:8080/hra sollte nun die Anwendung verfügbar sein (Abbildung 1).
Mehr als nur CRUD
Die Anwendung ist noch nicht fertig, denn außer dem Admin sollte kein Benutzer diese CRUD-Operationen direkt verwenden können. Folgende Anforderungen müssen noch umgesetzt werden:
- Anmeldemaske mit Benutzername (E-Mail Adresse) und Kennwort
- Benutzer darf nur seine Urlaubsanträge sehen
- Benutzer darf nur für sich selbst Urlaubsanträge stellen
- Eine Bestätigungs-Email soll nach dem Erstellen des Urlaubsantrags verschickt werden
- Der Administrator soll die volle CRUD-Funktionalität zur Verfügung haben.
Für die Anmeldemaske verwenden wir Spring Security und lassen uns mit Roo eine Grundkonfiguration erstellen.
roo> security setup
Mittels dieses einfachen Befehls werden die notwendigen Änderungen in der Spring-Konfiguration, in der Konfiguration der Web-Anwendung und in den Abhängigkeiten des Projekts vorgenommen. Man sieht also, dass es eine wesentliche Vereinfachung darstellt.
Jetzt muss die Konfiguration noch an unsere Anforderungen angepasst werden. Dazu wollen wir Eclipse verwenden. Wie eingangs erwähnt, ist das am einfachsten mit der STS möglich. STS enthält bereits eine Version von Roo, die aber eventuell nicht zu der selbst verwendeten passt. Daher sollte man STS so konfigurieren, das es die eigene Roo-Installation verwendet. Dies geschieht in den Workspace Preferences (Window/Preferences...) unter dem Eintrag "Spring/Roo Support". Anschließend über "Import/Maven Projects" das erstellte Projekt auswählen und ein Rechtsklick auf das Projekt und "Spring Tools/Add Roo Project Nature" auswählen. Die Roo Shell lässt sich jetzt auch in STS starten, indem man einen Rechtsklick auf das Projekt ausführt, und dann "Spring Tools/Open Roo Shell" auswählt. Die Vervollständigung erfolgt hier dem Eclipse-Standard entsprechend nicht mit der Tabulator-Taste, sondern mit Strg+Leertaste. Man muss jedoch darauf achten, dass nur eine Shell läuft, entweder in STS oder in der Konsole.
Aber zurück zur Spring Security Konfiguration. Zum Anpassen öffnen wir die Datei „applicationContext-security.xml“ . Hier stellen wir ein, dass nur der Administrator unseren CRUD-Controller verwenden darf, und richten die Benutzer samt Kennwörter ein. Die fertige Konfiguration sollte wie in Listing 2 aussehen. Wenn wir jetzt die Anwendung starten, erscheint eine Anmeldemaske und nur noch der Administrator darf unseren automatischen Controller verwenden.
<http auto-config="true"><form-login login-processing-url="/static/j_spring_security_check"login-page="/login.jsp"authentication-failure-url="/login.jsp?login_error=t"/><logout logout-url="/static/j_spring_security_logout"/><intercept-url pattern="/holidayrequest/**" access="ROLE_ADMIN"/><intercept-url pattern="/resources/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/><intercept-url pattern="/static/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/><intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY"/><intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/></http><authentication-provider><user-service><user name="admin@example.com" password="admin" authorities="ROLE_ADMIN"/><user name="user1@example.com" password="user1" authorities="ROLE_USER"/><user name="user2@example.com" password="user2" authorities="ROLE_USER"/></user-service></authentication-provider>
Für die nächsten Anforderungen erstellen wir einen eigenen Spring MVC Controller. Da wir hier auch eine E-Mail bei der Erstellung von Urlaubsanträgen versenden müssen, lassen wir uns auch gleich das Spring Mail Template erzeugen:
roo> controller class --name ~.web.EmployeeRequestControllerroo> email sender setup --hostServer 127.0.0.1roo> field email template --class ~.web.EmployeeRequestController
Um unseren Controller jetzt implementieren zu können, benötigen wir eine Methode in der Klasse HolidayRequest, die nur die Urlaubsanträge für einen speziellen Benutzer zurück gibt. Grails stellt dafür dynamische Finder-Methoden zur Laufzeit zur Verfügung wie findHolidayRequestByEmployee(). Mit Roo kann man sich solche Methoden auch über die Konsole erstellen lassen. Mit dem Befehl "finder list --class hra.HolidayRequest " bekommen wir eine Liste von möglichen Methodennamen, durch Angabe von --filter können wir diese weiter einschränken:
roo> finder list --class hra.HolidayRequest --filter employee,eqroo> finder add --finderName findHolidayRequestsByEmployeeEquals
Wenn wir die Anwendung nun erneut starten, werden wir feststellen, dass Roo automatisch eine Suchabfrage für diesen Finder in die Webanwendung eingefügt hat. Ab jetzt geht es weiter mit normaler Spring MVC Programmierung. Wir müssen den von Roo erzeugten Controller ausimplementieren und die JSP-Seiten sowie die Apache Tiles Definitionen dazu erstellen. Bei den JSP-Seiten können die von Roo erzeugten Seiten als Vorlage genommen werden. In Listing 3 sehen wir dann den fertigen Controller, mit Ausnahme der sendMessage()-Methode, da diese von Roo bereits erzeugt wurde. Auf die Details gehen wir hier jetzt nicht ein, da dies nichts mehr mit Roo zu tun hat, sondern normaler Spring MVC Code ist.
@Controller@SessionAttributes("holidayrequest")public class EmployeeRequestController {@Autowiredprivate transient MailSender mailTemplate;@InitBinderpublic void initBinder(org.springframework.web.bind.WebDataBinder binder) {binder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("dd.MM.yyyy"), false));binder.setAllowedFields(new String[] {"fromDate","toDate","comment"});}@RequestMapping("/employeerequest/form")public String form(ModelMap modelMap, HttpServletRequest request) {HolidayRequest hra = new HolidayRequest();hra.setEmployee(request.getRemoteUser());modelMap.addAttribute("holidayrequest",hra);return "employeerequest/create";}@RequestMapping(value="/employeerequest", method = RequestMethod.POST)public String create(@ModelAttribute("holidayrequest") HolidayRequest hra) {hra.persist();sendMessage("hra@example.com", "New Holiday Request",hra.getEmployee(), hra.toString());return "redirect:/employeerequest/" + hra.getId();}@RequestMapping(value="/employeerequest/list")public String list(ModelMap modelMap, HttpServletRequest req) {List holidayrequests = HolidayRequest.findHolidayRequestsByEmployeeEquals(req.getRemoteUser()).getResultList();modelMap.put("holidayrequests", holidayrequests);return "employeerequest/list";}@RequestMapping("/employeerequest/{id}")public String show(@PathVariable("id") long id, ModelMap modelMap) {modelMap.put("holidayrequest",HolidayRequest.findHolidayRequest(id));return "employeerequest/show";}}
Aus Platzgründen werden die JSP-Seiten hier nicht gezeigt, die lauffähige Anwendung steht hier zum Download bereit. Wenn kein Mailserver zur Verfügung steht, muss die betreffende Zeile auskommentiert werden, da ansonsten eine Exception geworfen wird.














