Konfiguracja deskryptora

W tej części stworzymy pierwszy kontroler, który zwróci prosty widok. Widok będziemy mogli wyświetlić klikając na odpowiedni link w menu systemowym (wtyczka doda odpowiedni link).

Wymagane moduły:

 

Deklaracja tych modułów odbywa się w deskryptorze wtyczki:

<?xml version="1.0" encoding="UTF-8"?>
<plugin key="com.suncode.plugin-tutorial" name="Tutorial Plugin">
	<plugin-details>
		<description>
			<localized language="en">Description</localized>
			<localized language="pl">Opis</localized>
		</description>
		<author>Suncode</author>
	</plugin-details>
	
	<!-- I18N -->	
	<i18n key="i18n-bundle" location="locale/messages" />
	
	<!-- Web MVC -->
	<web-mvc key="mvc" />
</plugin>

Stworzenie strony

Kontroler odpowiedzialny jest za przyjęcie żądania HTTP i zwrócenie widoku albo innej odpowiedzi (np. json).

Nasz kontroler będzie wyświetlał widok w odpowiedzi na żądanie /hello oraz odpowiadał obiektem json w odpowiedzi na /api/hello.

package com.suncode.plugin.tutorial;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController
{
    @RequestMapping( value = "/hello", method = RequestMethod.GET )
    public String showHelloView( Model model )
    {
        // dodajemy do modelu atrybut "date"
        model.addAttribute( "date", new Date() );

        // wyświetlamy widok "/views/hello.ftl"
        return "hello";
    }

    @RequestMapping( value = "/api/hello", method = RequestMethod.GET, produces = "application/json" )
    @ResponseBody
    public Map<String, Object> sayHello()
    {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put( "say", "hello" );
        result.put( "date", new Date() );

        // zwracamy mapę, która zostanie przetworzona na obiekt json
        return result;
    }
}

 

Widok wyświetli prosty tekst i przesłaną z kontrolera datę:

<p>Hello World</p>
<p>Current date: ${date?datetime}</p>

Widoki muszą być wykonane w technologii Freemarker. Wszystkie widoki muszą znajdować się w katalogu /views i mieć rozszerzenie .ftl (katalog i rozszerzenie są automatycznie dodawane do nazwy zwróconego widoku).

Standardowo Eclipse nie posiada wbudowanego edytora szablonów Freemarker. Taki edytor wchodzi w skład jBoss Tools.

Struktura projektu jest następująca:

Po zainstalowaniu/aktualizacji wtyczki możemy wypróbować działanie naszego kontrolera. W tym celu należy wysłać żądanie na odpowiedni adres URL:

Wszystkie adresy URL wtyczki poprzedzone są prefixem składającym się z /plugin/{identyfikator wtyczki}/ (np. /plugin/com.suncode.plugin-tutorial/)

 

  1. /plugin/com.suncode.plugin-tutorial/hello

     

    Wszystkie widoki zwracane przez wtyczkę są domyślnie dekorowane (za wyjątkiem żądań z nagłówkiem X-Requested-With: XMLHTTPREQUEST.

    Jeżeli nie chcemy dekorować naszej strony, musimy dodać parametr: decorator=none (np: /plugin/com.suncode.plugin-tutorial/hello?decorator=none) dzięki czemu otrzymamy czystą stronę:

    Wszystkie dostępne dekoratory opisane są Tworzenie widoków Freemarker - Dekoratory widoków

  2. /plugin/com.suncode.plugin-tutorial/api/hello

    {"say":"hello","date":1399446110308}

Serwowanie statycznych zasobów

Wtyczki mogą serwować dowolne zasoby statyczne (skrypty, zdjęcia etc.). Zasoby takie muszą znajdować się w katalogu /resources:

 

 

 

 

 

 

 

Zasoby statyczne mogą być pobierane przy użyciu 2 adresów URL (różniących się polityką cache):

  • /plugin/{id}/resources/{resource} - zasoby odczytane w ten sposób nie są cache'owane:
    • (np. plugin/com.suncode.plugin-tutorial/resources/data.js)
  • /plugin/{id}/resources/{lastUpdate}/{resource} - zasoby odczytane w ten sposób są cache'owane(do aktualizacji wtyczki, kiedy zmienia się również link do zasobu):
    •  (np. plugin/com.suncode.plugin-tutorial/resources/1399542968944/data.js)

gdzie: 

  • id - identyfikator wtyczki
  • resource - adres zasobu wewnątrz wtyczki relatywny do /resources
  • lastUpdate - data ostatniej aktualizacji wtyczki

Ze względów wydajnościowych, należy zawsze dążyć do wykorzystywania URL z datą ostatniej aktualizacji, ze względu na politykę cache'owania.

 

Serwowanie zasobów statycznych dla nieuwierzytelnionych użytkowników

Zasoby wtyczki standardowow serwowane są tylko dla uwierzytelnionych użytkowników. Jeżeli chcemy aby zasoby były dostępne dla wszystkich należy umieścić je w katalogu /public znajdującym się w wyżej zdefiniowanym katalogu /resources (/resources/public/<zasób>).

Dostęp do zasoby możliwy jest poprzez adresy (z cache lub bez):

  • /plugin/{id}/resources/public/{resource} - (np. plugin/com.suncode.plugin-tutorial/resources/public/data.js)
  • /plugin/{id}/resources/{lastUpdate}/public/{resource} -  (np. plugin/com.suncode.plugin-tutorial/resources/1399542968944/public/data.js)

Dynamiczny link do zasobów w widokach Freemarker

Dynamiczny link do zasobów tworzony jest poprzez dodanie do adresu URL daty ostatniej aktualizacji wtyczki. W widokach Freemarker można ułatwić sobie pobieranie gotowego linku:

Wykorzystany niżej obiekt i makro są opisane w dokumentacji tworzenia widoków Freemarker.

<!-- Pomocnicze makro -->
<#import "/plugin.ftl" as plugin/>
 
<!-- Wykorzystując obiekt pluginContext -->
<script src="${pluginContext.pluginResourcesPath}/data.js"></script>
 
<!-- Wykorzystując pomocnicze makro -->
<script src="<@plugin.resourceUrl 'data.js'/>"></script>

Descriptor configuration 

 In this part, we will create the first controller that will return a simple view. We will be able to preview the view by clicking on the appropriate link in the system menu (the plugin will add the appropriate link).

Required modules:

 

Declaration of these modules takes place in the plug-in descriptor:

<?xml version="1.0" encoding="UTF-8"?>
<plugin key="com.suncode.plugin-tutorial" name="Tutorial Plugin">
	<plugin-details>
		<description>
			<localized language="en">Description</localized>
			<localized language="pl">Opis</localized>
		</description>
		<author>Suncode</author>
	</plugin-details>
	
	<!-- I18N -->	
	<i18n key="i18n-bundle" location="locale/messages" />
	
	<!-- Web MVC -->
	<web-mvc key="mvc" />
</plugin>

Page creation

The controller is responsible for accepting the HTTP requestand returning the view or other response (e.g., json).

Our controller will display the view in response to the request / hello and respond to thejsonobject in response to /api/hello.

package com.suncode.plugin.tutorial;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController
{
    @RequestMapping( value = "/hello", method = RequestMethod.GET )
    public String showHelloView( Model model )
    {
        // we add the attribute to the model "date"
        model.addAttribute( "date", new Date() );

        // we display the view "/views/hello.ftl"
        return "hello";
    }

    @RequestMapping( value = "/api/hello", method = RequestMethod.GET, produces = "application/json" )
    @ResponseBody
    public Map<String, Object> sayHello()
    {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put( "say", "hello" );
        result.put( "date", new Date() );

        // we return a map that will be processed into an object json
        return result;
    }
}

 

The view will display a simple text and the date sent from the controller:

<p>Hello World</p>
<p>Current date: ${date?datetime}</p>

Views must be made in Freemarker technology. All views must be in the /views directory and have the .ftl extension (the directory and extension are automatically added to the name of the returned view).

By default, Eclipse does not have a built-in Freemarker template editor. This editor is part of jBoss Tools.

The project structure is as follows:

After installing/updating the plugin, we can try out our controller. To do this, send a request to the appropriate URL:

All URLs of the plugin are preceded by a prefix consisting of /plugin/{plugin ID}/(eg. /plugin/com.suncode.plugin-tutorial/)

 

  1. /plugin/com.suncode.plugin-tutorial/hello

     

    All views returned by the plugin aredecorated by default (except for requests with the X-Requested-With header: XMLHTTPREQUEST).

    If we do not want to decorate our site, we need to add the parameter: decorator = none(eg.: /plugin/com.suncode.plugin-tutorial/hello?decorator=none) so that we get a clean page:

    All available decorators are described in Creating Freemarker Views - View decorators .

  2. /plugin/com.suncode.plugin-tutorial/api/hello

    {"say":"hello","date":1399446110308}

Serving static resources 

Plug-ins can serve any static resources (scripts, photos etc.). Such resources must be located in the /resourcesdirectory:

 

 

 

 

 

 

 

Static resources can be downloaded using 2 URLs(differing in the cache policy):

  • /plugin/{id}/resources/{resource} - resources read in this way are not cached:
    • (np. plugin/com.suncode.plugin-tutorial/resources/data.js)
  • /plugin/{id}/resources/{lastUpdate}/{resource} - the resources read in this way are cached(to update the plugin when the link to the resource also changes):
    •  (np. plugin/com.suncode.plugin-tutorial/resources/1399542968944/data.js)

where:

  • id– plugin identificator
  • resource- resource address inside the plug relative to/resources
  • lastUpdate - date of the last update of the plugin

 

For performance reasons, always try to use the URL with the last update date due to the cache policy.

 

Serving static resources for anonymous users

 

By default serving static resources requires the requesting user to authenticate first. To allow access for anonymous users they have to be put in /public folder, inside the /resources folder (/resources/public/<resource>).

 

The resources is then available via URL's (cached and non-cached):

 

  • /plugin/{id}/resources/public/{resource} - (i.e. plugin/com.suncode.plugin-tutorial/resources/public/data.js)
  • /plugin/{id}/resources/{lastUpdate}/public/{resource} -  (i.e. plugin/com.suncode.plugin-tutorial/resources/1399542968944/public/data.js)

Dynamic link to resources to Freemarker views 

A dynamic link to resources is created by adding the date of the last update to the URL. In the Freemarker views, you can make it easier to download a link:

The following object and macro are described in documentation for creating Freemarker views.

<!-- Pomocnicze makro -->
<#import "/plugin.ftl" as plugin/>
 
<!-- Wykorzystując obiekt pluginContext -->
<script src="${pluginContext.pluginResourcesPath}/data.js"></script>
 
<!-- Wykorzystując pomocnicze makro -->
<script src="<@plugin.resourceUrl 'data.js'/>"></script>