Spring Boot – Widoki

W poprzednich postach pisałem jak zacząć przygodę ze Spring Bootem oraz jak się połączyć z bazą danych. Dotychczas dane do przeglądarki zwracane były jako stringi. Jak już pewnie się domyślasz istnieją lepsze sposoby aby ładnie zaprezentować nasze dane, a do tego oddzielić logikę aplikacji od prezentacji.

Spring wspiera różne technologie widoków. Od tradycyjnych JSP(http://pl.wikipedia.org/wiki/JavaServer_Pages), do Themyleaf (http://www.thymeleaf.org/), Twig (http://twig.sensiolabs.org/, implementacja dla Javy JTWIG: http://jtwig.org/), FreeMarker, Groovy czy Velocity.

Widoki JSP mają kilka znanych ograniczeń, przez co powinny być unikane. Osobiście lubię widoki TWIG dlatego skupie się na nich, inne silniki szablonów implementuje się w analogiczny sposób.

Kod źródłowy gotowego projektu można znaleźć pod adresem: https://github.com/mloza/spring-boot-views

Konfiguracja początkowa

Możesz użyć projektu z poprzedniego postu: http://blog.mloza.pl/spring-boot-szybkie-tworzenie-aplikacji-web-w-javie/. W takim wypadku możesz pominąć ten rozdział.

Zacznijmy od stworzenia nowego projektu Maven i dodaniu następujących elementów w pom.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

Całość powinna wyglądać mniej więcej tak:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

Następnie potrzebujemy klasę uruchamiającą projekt. Powinna wyglądać w ten sposób:

@EnableAutoConfiguration
@ComponentScan
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class);
    }
}

Możemy już uruchomić aplikację, gdy na konsoli pojawi się wpis:

2015-03-03 12:09:42.570  INFO 12396 --- [           main] pl.mloza.spring.boot.views.Main          : Started Main in 2.435 seconds (JVM running for 2.812)

W przeglądarce wklepujemy adres: http://localhost:8080/ pod którym powinna ukazać się strona błędu jak poniżej:
Widok błędu

Konfiguracja JTWIG

Pierwszym krokiem jest dodanie kolejnej zależności do pom.xml:

        <dependency>
            <groupId>com.lyncode</groupId>
            <artifactId>jtwig-spring</artifactId>
            <version>2.1.7</version>
        </dependency>

Następnie musimy powiedzieć Springowi gdzie ma szukać naszych widoków. Robimy to poprzez utworzenie klasy z adnotacją @Configuration. Klasa ta dostarczy Bean, który zostanie użyty do rozwiązywania widoków:

@Configuration
public class WebAppConfiguration {
    @Bean
    public ViewResolver viewResolver() {
        JtwigViewResolver jtwigViewResolver = new JtwigViewResolver();
        jtwigViewResolver.setPrefix("classpath:views/");
        jtwigViewResolver.setSuffix(".twig");
        return jtwigViewResolver;
    }
}

Teraz potrzebujemy kontroler, który obsłuży wywołanie, zacznijmy od najprostszej wersji:

@Controller
public class MainController {
    @RequestMapping("/")
    public ModelAndView index() {
        return new ModelAndView("index");
    }
}

Stwórzmy teraz widok. W katalogu src/main/resources/views/ dodajemy plik index.twig, klasycznie o treści:

Hello World from view!

I to już prawie wszystko, ostatnim krokiem jest poinformowanie Springa, że powinien szukać naszych klas i rozwiązywać konfigurację. Jeśli wszystkie klasy zostały umieszczone w jednym pakiecie powinien je wykryć automatycznie. Jeśli nie, to adnotację @ComponentScan w klasie Main należy zmodyfikować do postaci:

@ComponentScan(basePackageClasses = {MainController.class, WebAppConfiguration.class})

Po restarcie aplikacji i odświeżeniu strony powinniśmy otrzymać nasz widok.

Przekazywanie zmiennych do widoku

Użycie widoków pozwala na odseparowanie logiki aplikacji od sposobu prezentacji danych. Jednak dane te musimy jakoś przekazać z kontrolera do widoku. Najczęściej dane będą pochodzić z bazy danych, jednak dla uproszczenia dane zostaną stworzone w kontrolerze. Zmodyfikujmy kontroler do postaci:

@Controller
public class MainController {
    @RequestMapping("/")
    public ModelAndView index() {
        ModelAndView modelAndView = new ModelAndView("index");
        
        modelAndView.addObject("greetings", "Hello world from variable!");
        modelAndView.addObject("greetingsArray", new String[] {"Hello", "World", "!"});
        
        return modelAndView;
    }
}

Zwracana wartość została przypisana do zmiennej aby można było jej użyć przed zwróceniem z kontrolera. Następnie wywołujemy na niej metodę addObject(nazwa, wartość). Dzięki temu wartość przekazana do metody będzie widoczna w widoku pod wybraną nazwą. Możemy tutaj przekazywać zarówno prymitywy (int, long, double) jak i obiekty, tablice, listy. W tym przykładzie przekazujemy String i tablicę Stringów. Zacznijmy od wyświetlenia zmiennej greetings. W Twigu do zmiennych odwołujemy się poprzez {{ zmienna }}. Zmodyfikujmy widok do postaci:

<h3>{{ greetings }}</h3>

Restartujemy aplikacje i odświeżamy przeglądarkę. Powinniśmy ujrzeć napis: Hello world from variable!

TIP: jeśli używasz IntelliJ, możesz uruchomić aplikację w trybie debugowania, wtedy wywołanie Make Project (Ctrl+F9) wystarczy aby zaktualizować widok. W ten sposób również można aktualizować klasy jeśli dokonujemy tylko zmian zawartości metod, zmiana interfejsu lub adnotacji wymaga pełnego restartu. Ten sam sposób powinien zadziałać w Eclipse jednak nie sprawdzałem tego.

Iterowanie po zmiennych

Wiemy już jak wyświetlić zmienną. Co jeśli chcemy wyświetlić zawartość tablicy? Dodajmy do widoku następujący kod:

<ul>
    {% for i in greetingsArray %}
        <li>{{ i }}</li>
    {% endfor %}
</ul>

Kod ten to nic innego jak pętla for na sterydach. Udostępnia ona też zmienną loop która posiada kilka ciekawych elementów jak np. aktualny index. Używając go możemy dodać numerację elementów:

<ul>
    {% for i in greetingsArray %}
        <li>{{ loop.index+1}}. {{ i }}</li>
    {% endfor %}
</ul>

W wyniku powinniśmy otrzymać coś podobnego:
przechwytywanie1

Podsumowanie

Umiemy już pracować z widokami. Opis składni szablonów TWIGa można znaleźć na stronie TWIGa oraz JTWIG. Aby użyć innego silnika szablonów wystarczy go dodać jako zależność do Mavena i zmienić ViewResolver. W kolejnym poście dodam więcej informacji o pracy z samymi szablonami Twiga i możliwościami jakie one dają.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *