Spring Celem ćwiczenia jest przygotowanie prostej aplikacji internetowej wykorzystującej architekturę Spring. Do wykonania ćwiczenia potrzebne jest zintegrowane środowisko programistyczne NetBeans IDE w wersji 6.9 lub nowszej (do pobrania z http://www.netbeans.org). Wćwiczeniu wykorzystywany jest serwer bazy danych Oracle, ale można zastąpić go innym pod warunkiem utworzenia w bazie danych tabeli PRACOWNICY zawierającej kolumny NAZWISKO i ETAT lub zastąpienia zapytania innym. 1. Uruchom narzędzie NetBeans IDE. 2. Z menu głównego wybierz File New Project. Wybierz kategorię Java Web i typ projektu Web Application. Kliknij przycisk Next >. Podaj nazwę projektu, np. SpringLab. Kliknij przycisk Next >. Jako serwer na którym będzie testowana aplikacja wybierz najnowszą wersję serwera GlassFish, a jako wersję Java EE: Java EE 6 Web. Nie zaznaczaj pola Enable Contexts and Dependency Injection. Kliknij przycisk Next >. W ostatnim kroku kreatora na liście dostępnych frameworków zaznacz Spring Web MVC. Obejrzyj zaproponowaną konfigurację dyspozytora (ang. dispatcher). Kliknij przycisk Finish. 3. Sprawdź jakie biblioteki kreator automatycznie dodał do projektu. 4. Uruchom projekt. Przeczytaj tekst wyświetlany na stronie startowej aplikacji utworzonej przez kreator i spróbuj go zrozumieć. Prześledź sekwencję operacji prowadzącą do wyświetlenia strony startowej: a. Odszukaj ustawienie strony powitalnej w web.xml b. Odszukaj instrukcję przekierowania w pliku redirect.jsp
c. Obejrzyj konfigurację serwletu dispatchera w web.xml d. Obejrzyj deklarację 3 komponentów JavaBean w pliku konfiguracyjnym dyspozytora: i. Odwzorowującego adres /index.htm na wygenerowany przez kreator kontroler ii. Stanowiącego wspomniany wyżej kontroler, przekierowujący żądanie do widoku index iii. Zamieniającego logiczne nazwy widoku na nazwy stron JSP w podkatalogu jsp (wykorzystywanego dla widoku index ) e. Zwróć uwagę na lokalizację pliku strony widoku index.jsp 5. W pliku konfiguracyjnym dyspozytora odszukaj ustawienia komponentu odwzorowującego adresy URL na kontrolery aplikacji i dodaj mapowanie adresu today.htm na kontroler o nazwie datecontroller. 6. Wstaw w pliku konfiguracyjnym dyspozytora następujący kod definiujący kontroler datecontroler jako komponent klasy kontrolera, którą utworzymy za chwilę. <bean name="datecontroller" class="controllers.datecontroller" /> 7. Kliknij prawym przyciskiem myszy na ikonie Source Packages i z menu kontekstowego wybierz New Java Class Wprowadź nazwę klasy: DateController i nazwę pakietu: controllers. Kliknij przycisk Finish. 8. Plik DateController.java zostanie załadowany do edytora. Wprowadź do pliku następujący kod (opis działania kodu poniżej). package controllers; import org.springframework.web.servlet.modelandview; import org.springframework.web.servlet.mvc.abstractcontroller; import javax.servlet.http.*; import java.util.*; public class DateController extends AbstractController { public DateController() { public ModelAndView handlerequestinternal (HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView("..."); mav.addobject("date", new Date()); return mav; Kontroler otrzymuje żądanie, tworzy nowy obiekt wynikowy ModelAndView, dodaje do modelu obiekt biznesowy (w tym przypadku prosty obiekt java.util.date) i zwraca obiekt wynikowy. Obiekt ModelAndView reprezentuje widok, do którego ma nastąpić przekierowanie wraz z obiektami modelu, do których widok się odwołuje. W naszej aplikacji widoki będą implementowane w technologii JSP. Aby strony JSP stanowiące widoki nie były dostępne bezpośrednio, a jedynie za pośrednictwem
kontrolera będą one umieszczone w podkatalogu katalogu WEB-INF (katalog ten jest domyślnie chroniony przed dostępem z przeglądarki). Działanie kontrolera ma zakończyć się przekierowaniem do strony: /WEB-INF/jsp/today.jsp. Co w związku z tym należy podać w miejscu wielokropka jako parametr konstruktora ModelAndView? (wskazówką jest konfiguracja komponentu viewresolver w pliku konfiguracyjnym dyspozytora). 9. Kliknij prawym przyciskiem myszy na folderze jsp w sekcji Web Pages i z menu kontekstowego wybierz New JSP. Podaj nazwę dokumentu: today (nie podawaj rozszerzenia, zostanie dodane automatycznie!). Kliknij przycisk Finish. 10. Plik today.jsp zostanie otwarty w edytorze. Wprowadź następujący kod: <%@page contenttype="text/html"%> <%@page pageencoding="utf-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>current date in Spring MVC</title> </head> <body> <h1>congratulations!</h1> Current date: <c:out value="${date"/> </body> </html>
11. Uruchom aplikację i popraw adres w przeglądarce na wywołujący stronę prezentującą bieżącą datę. 12. Kolejny krok to dodanie do projektu komponentu odpowiedzialnego za nawiązanie połączenia z bazą danych. Komponent ten mógłby być skonfigurowany w pliku dyspozytora, ale ponieważ jest on związany z logiką biznesową a nie konkretnymi widokami warstwy prezentacji, lepszym rozwiązaniem jest jego zdefiniowanie w pliku konfiguracyjnym kontekstu aplikacji (fabryki komponentów Spring). Otwórz do edycji plik applicationcontext.xml i odkomentuj definicje dwóch komponentów wewnątrz znaczników <beans></beans>: komponentu udostępniającego właściwości zdefiniowane we wskazanym pliku właściwości (properties) oraz komponentu źródła danych, którego konfiguracja oparta jest o udostępnione właściwości. 13. Utwórz w katalogu WEB-INF plik właściwości o nazwie wskazanej w pliku applicationcontext.xml. 14. W pliku właściwości podaj wymagane parametry połączenia z bazą danych. Poniższa przykładowa zawartość dotyczy połączenia z lokalnym serwerem Oracle. jdbc.driverclassname=oracle.jdbc.oracledriver jdbc.url=jdbc:oracle:thin:@localhost:1521:xe jdbc.username=scott jdbc.password=tiger 15. Aby aplikacja mogła nawiązać połączenie z bazą danych wymagane jest dołączenie do projektu właściwego sterownika JDBC. W celu dodania sterownika do projektu kliknij prawym przyciskiem myszy na ikonie Libraries i z menu kontekstowego wybierz Add JAR/Folder Nazwa archiwum JAR sterownika JDBC Oracle to ojdbc5.jar lub ojdbc6.jar (zależnie od wersji Java SE dla której jest przeznaczony).
16. Komunikacja z bazą danych w aplikacji Spring może być realizowana na wiele sposobów. Spring współpracuje z wieloma technologiami odwzorowania obiektoworelacyjnego (w tym: JPA, Hibernate, Toplink, JDO), a także oferuje framework Spring JDBC ułatwiający korzystanie z JDBC. W naszej aplikacji wykorzystamy to drugie rozwiązanie. Nawiązanie połączenia, wykonanie zapytania i odczytanie wyników zapytania będzie realizowane w kontrolerze. a. Utwórz nowy kontroler controllers.querycontroller.java. Umieść w nim poniższy kod w miejscu trzech kropek wstawiając identyfikator komponentu źródła danych ustalony w pliku konfiguracyjnym kontenera Spring: package controllers; import org.springframework.web.servlet.modelandview; import org.springframework.web.servlet.mvc.abstractcontroller; import org.springframework.context.applicationcontext; import org.springframework.context.support.classpathxmlapplicationcontext; import org.springframework.jdbc.core.jdbctemplate; import org.springframework.jdbc.datasource.drivermanagerdatasource; import javax.servlet.http.*; import java.util.*; public class QueryController extends AbstractController { public QueryController() { public ModelAndView handlerequestinternal(httpservletrequest request, HttpServletResponse response) throws Exception { ApplicationContext ctx = this.getapplicationcontext(); DriverManagerDataSource ds = (DriverManagerDataSource)ctx.getBean("..."); JdbcTemplate template = new JdbcTemplate(ds); List employees = template.queryforlist("select * from pracownicy"); ModelAndView mav = new ModelAndView("query"); mav.addobject("employees",employees); return mav;
17. Utwórz stronę JSP wywoływana przez dodany przed chwilą kontroler. Umieść w niej poniższy kod wyświetlający wynik zapytania przesłany przez kontroler w obiekcie employees : <%@page contenttype="text/html"%> <%@page pageencoding="utf-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>employee list in Spring MVC</title> </head> <body> <h1>employee list</h1> <table border="1"> <tr><th>name</th><th>job</th></tr> <c:foreach var="emp" items="${employees"> <tr> <td><c:out value='${emp["nazwisko"]'/></td> <td><c:out value='${emp["etat"]'/></td> </tr> </c:foreach> </table> </body> </html> 18. Zadeklaruj kontroler QueryController w pliku konfiguracyjnym dyspozytora i zdefiniuj jego odwzorowanie na adres query.htm. 19. Uruchom aplikację, a następnie zmodyfikuj adres w przeglądarce, tak aby została wyświetlona strona z wynikami zapytania do bazy danych.
20. Umieszczenie logiki biznesowej w kontrolerze nie jest rozwiązaniem idealnym. Aby poprawić separację zadań poszczególnych komponentów aplikacji, utworzymy dedykowany komponent do obsługi informacji o pracownikach. package dao; a. Utwórz klasę dao.employeesdao i umieść w niej poniższy kod: import org.springframework.jdbc.core.jdbctemplate; import org.springframework.jdbc.datasource.drivermanagerdatasource; import java.util.*; public class EmployeesDAO { private DriverManagerDataSource empdatasource = null; public void setempdatasource(drivermanagerdatasource ds) { empdatasource = ds; public List getemployees() { JdbcTemplate template = new JdbcTemplate(empDataSource); return template.queryforlist("select * from pracownicy"); b. Utworzona klasa do poprawnego działania wymaga dostępu do źródła danych. Zamiast tworzyć instancję źródła danych lub wyszukiwać ją w kontenerze, klasa udostępnia metodę setter, która pozwoli kontenerowi na wstrzyknięcie źródła danych do instancji klasy. Informacja o obiektach zależnych, które kontener ma wstrzyknąć przy tworzeniu instancji klasy stanowi część konfiguracji komponentu w pliku konfiguracyjnym kontenera Spring. Umieść w pliku konfiguracyjnym kontenera poniższy kod: <bean id="employeesdao" class="dao.employeesdao"> <property name="empdatasource"><ref local="datasource"/></property> </bean> Wykorzystana technika to klasyczna implementacja mechanizmu wstrzykiwania zależności (ang. dependency injection), nazywanego w kontekście Spring również odwróceniem sterowania (ang. Inversion of Control). c. Zmodyfikuj kontroler tak aby nie odwoływał się do źródła danych i pobierał dane pracowników ze skonfigurowanego w poprzednich dwóch krokach komponentu. d. Uruchom aplikację i przetestuj działanie strony z wynikami zapytania. 21. Kontroler QueryController w aktualnej wersji naszej aplikacji bezpośrednio odwołuje się do kontekstu aplikacji i jawnie pobiera z niego potrzebny mu komponent (bean). Ponieważ sam kontroler jest komponentem (beanem) zarządzanym przez kontener Spring, może on skorzystać ze wstrzykiwania zależności. Jedyną różnicą w stosunku do scenariuszy wstrzykiwania zależności wykorzystanych wcześniej w ćwiczeniu jest
to, że kontroler i potrzebny mu bean są zadeklarowane w różnych plikach konfiguracyjnych (kontroler jest związany z kontekstem konkretnego dyspozytora, a potrzebny mu bean z głównym kontekstem aplikacji). Aby zrealizować współpracę kontrolera z wykorzystywanym przez niego beanem w oparciu o wstrzykiwanie zależności wykonaj następujące kroki: a. Zadeklaruj w klasie kontrolera QueryController prywatne pole do którego będzie wstrzyknięta referencja do obiektu wykonującego zapytanie do bazy danych. Następnie utwórz publiczną metodę typu setter do ustawiania z zewnątrz wartości tego pola. b. Zmodyfikuj metodę handlerequestinternal() kontrolera QueryController, tak aby wykorzystywała wstrzyknięty obiekt. c. W pliku konfiguracyjnym dyspozytora w elemencie deklarującym kontroler QueryController jako bean zadeklaruj właściwość dla wstrzykiwanego beana realizującego zapytanie. Możesz wzorować się na przykładzie wstrzykiwania źródła danych do beana realizującego zapytanie, z tą różnicą, że odwołanie do beana zadeklarowanego w innym pliku musi być zrealizowane poprzez atrybut bean, a nie local jak w przypadku beanów zadeklarowanych w tym samym pliku. (Wiązanie beanów zadeklarowanych w tym samym pliku atrybutem local umożliwia weryfikację powiązań na etapie parsowania pliku XML.) Uwagi końcowe na temat Spring i Spring MVC: Spring MVC poza wykorzystanym w ćwiczeniu AbstractController oferuje również bardziej zaawansowane kontrolery: obsługujące parametry zawarte w żądaniu, obsługujące formularze, obsługujące różne akcje w ramach kontrolera Obecnie Spring (w tym Spring MVC) oprócz konfiguracji poprzez pliki XML-owe umożliwia również konfigurację poprzez adnotacje Aplikacje webowe w Spring mogą wykorzystywać inne frameworki MVC niż Spring MVC oraz różne technologie widoku (nie tylko JSP)