Dans cet article, je vais vous présenter trois examples pratiques de ce qui peut être fait avec Wicket :

  • Comment adapter la stratégie d’encodage de l’URL (URLCodingStrategy)
  • Comment améliorer la navigation grace au Breadcrumb
  • Comment déleguer un comportement à un composant Image

Tous ces exemples sont mis en pratique dans l’application noolazysite.

Gestion de la stratégie de codage de l’URL

Je souhaitai, pour cette application, avoir une URL qui laissait clairement apparaitre le chemin dans lequel l’utilisateur se trouve, par exemple :

http://www.noocodecommit.com/noolazysite/browse/folder/2008/8/

Le /folder permet de savoir qu’on navigue dans un répertoire, et ce qui suit est le répertoire en lui même.
Cependant, la classe par défaut qui s’occupe de coder l’URL ([BookmarkablePageRequestTargetUrlCodingStrategy] dans le cas d’un montage d’URL “bookmarkable”) n’est absolument pas en mesure de prendre en charge une telle URL. (en effet pour elle, il faut des couples de key/value)

J’ai donc créé, la classe [LazyRequestTargetUrlCodingStrategy] qui hérite de [BookmarkablePageRequestTargetUrlCodingStrategy], et qui surcharge plusieures méthodes, à savoir :

  • [appendParameters(AppendingStringBuffer url, Map parameters)]
  • [decodeParameters(String urlFragment, Map urlParameters)]

qui s’occupent respectivement de la création de l’URL avec ses paramètres, et du décodage de ces derniers.

[appendParameters(AppendingStringBuffer url, Map parameters)] à été reprise tel que de la classe [AbstractRequestTargetUrlCodingStrategy] (dont hérite [BookmarkablePageRequestTargetUrlCodingStrategy]), la seule
subtilité étant dans l’ajout de cette méthode :

private void appendValue(AppendingStringBuffer url, String key, String value)
{
  String escapedValue = urlEncodePathComponent(value);
 
  // on repasse le caractere "/" sans encodage 
  escapedValue = escapedValue.replace("%2F", "/");
 
  if (!Strings.isEmpty(escapedValue))
  {
    if (!url.endsWith("/"))
    {
      url.append("/");
    }
    url.append(key).append("/").append(escapedValue).append("/");
  }
}

ensuite la partie qui nous concerne de la méthode [decodeParameters(String urlFragment, Map urlParameters)] est :

  ...
  if (pairs.length > 0 && pairs[0].equals("folder"))
  {
  	String key = pairs[0];
  	String value = "";
 
  	String separator = "";
  	for (int i = 1; i < pairs.length; i++)
  	{
  		value += separator + urlDecodePathComponent(pairs[i]);
  		separator = File.separator;
  	}
  	parameters.add(key, value);
  }
  else
  {
  	// If we don't have an even number of pairs
  	if (pairs.length % 2 != 0)
  	...
  }
  ...

quand nous sommes en présence du requestParameter [folder] on considere la suite comme étant sa valeur. (dans notre exemple : folder = 2008/8)

Pour pouvoir appliquer cette stratégie de codage, il faut le dire à la classe [LazySiteApplication.java]:

  ...
  @Override
  protected void init()
  {
  	super.init();
  	mount(new LazyRequestTargetUrlCodingStrategy("/browse", HomePage.class, null));
  }
  ...

Voila, avec tout ça, on obtient exactement le comportement souhaité!
Si vous aussi vous voulez que les URL de votre application soit codées différemment, je vous invite à regarder ce qui existe dans le package [org.apache.wicket.request.target.coding],
ou alors de créer, comme ici, votre propre stratégie.

Navigation simplifiée grace au Breadcrumb

Selon Wikipédia, les Breadcrumbs,
représentent une technique de navigation utilisée en interface utilisateur ou IHM (Interface Homme Machine), par exemple sur les pages Web.
Leur but est de donner aux utilisateurs un moyen de garder une trace de leur emplacement à l’intérieur de programmes, documents ou pages Web.
Le terme vient des traces formées de miettes de pain que laissèrent Hansel et Gretel dans le conte populaire bien connu des frères Grimm (tout comme dans l’histoire du Petit Poucet de Charles Perrault plus connue des Français).

Je souhaitai, pour cette application, permettre à l’utilisateur de naviguer simplement dans les différents répertoire. Le breadcrumb est tout naturellement apparu sous la forme :

lienVersRacine / lienVersRepertoire1 / lienVersRepertoire2

En regardant un peu ce qui est fourni par Wicket, via la librairie wicket-extensions, il existe un [BreadCrumbBar] (dans le package [org.apache.wicket.extensions.breadcrumb]).
Cependant, cet implémentation de BreadCrumb est intimement liée à l’affichage de [Panel]. Or, dans mon cas ce sont des URL paramétrées dont j’ai besoin.

Je me suis donc inspiré de ce qui est fait dans wicket-extensions, mais en l’adaptant à mes besoins.
J’ai donc 3 nouvelles classes : [BreadCrumbsListView], [BreadCrumbComponent] et [BreadCrumbElement].

BreadCrumbElement

Cette classe est un objet métier représentant ce que je souhaite afficher dans mon Breadcrumb, à savoir un libellé et un répertoire.

public class BreadCrumbElement implements Serializable
{
	private String label;
	private String folder;
 
	public BreadCrumbElement(String label, String folder)
	{
		this.label = label;
		this.folder = folder;
	}
 
	//Getter/Setter
}

BreadCrumbComponent

Cette classe est un composant au sens Wicket du terme.
Plus précisement, c’est un composant qui hérite de [Panel] qui se chargera d’afficher le [Label] et le [Link] en rapport avec ce qui est défini dans l’objet [BreadCrumbElement].

public class BreadCrumbComponent extends Panel
{
	public BreadCrumbComponent(String id, int index, BreadCrumbElement crumb)
	{
		super(id);
		add(new Label("sep", (index > 0) ? "/ " : "").setEscapeModelStrings(false).setRenderBodyOnly(true));
		PageParameters params = new PageParameters();
		params.add("folder", crumb.getFolder());
		BookmarkablePageLink link = new BookmarkablePageLink("link", HomePage.class, params);
		add(link);
		link.add(new Label("label", crumb.getLabel()).setRenderBodyOnly(true));
	}
}

Cette classe est associée à un fichier HTML, qui défini la structure de l’affichage :

<wicket:panel>
<span wicket:id="sep"></span><a href="#" wicket:id="link"><span wicket:id="label">link label</span></a>
</wicket:panel>

BreadCrumbsListView

Cette classe est un Repeater, il affichera la liste de tous les [BreadCrumbElement] via un ensemble de [BreadCrumbComponent]

public class BreadCrumbsListView extends ListView<BreadCrumbElement>
{
	public BreadCrumbsListView(String id, final ArrayList<BreadCrumbElement> crumbs)
	{
		super(id);
		setReuseItems(false);
		setDefaultModel(new LoadableDetachableModel()
		{
			protected Object load()
			{
				return crumbs;
			}
		});
	}
 
	@Override
	protected void populateItem(ListItem<BreadCrumbElement> item)
	{
		int index = item.getIndex();
		BreadCrumbElement crumb = item.getModelObject();
		item.add(new BreadCrumbComponent("crumb", index, crumb));
	}
}

Il ne nous reste plus qu’a ajouter cette ListView dans notre page [HomePage.java]

  ...
  private void init(String path)
  {
    ...
  	// Création de la liste des Objets pour le BreadCrumb
  	ArrayList<BreadCrumbElement> listCrumbs = blabla; //la création nous importe peu ici
 
  	// Création du Composant Visuel BreadCrumb
  	BreadCrumbsListView crumbs = new BreadCrumbsListView("crumbs", listCrumbs);
  	add(crumbs);
  	...
  }
  ...

Et dans [HomePage.html]

  ...
  <div id="header">
 
 
 
    ...
    <h1><a href="./">NooLazySite</a> / <span wicket:id="crumbs"><span wicket:id="crumb">[notre crumb]</span></span></h1>
  </div>
  ...

Ce qui nous donne le résultat escompté :

Breadcrumb

Composant personnalisé “Image”

Rien de bien particulier ici, mais je voulai juste montrer ce composant qui a pour but final d’être une image.

public class ExtensionImage extends WebComponent
{
	List<String> extensions = Arrays.asList(new String[] { "avi.png", "bat.png", "bin.png", "bmp.png", "default.png", ... });
 
	public ExtensionImage(String id, String icon)
	{
		super(id);
 
		if (!extensions.contains(icon))
			icon = "default.png";
 
		WebRequestCycle cycle = (WebRequestCycle) RequestCycle.get();
		String context = cycle.getWebRequest().getHttpServletRequest().getContextPath();
 
		add(new AttributeModifier("src", true, new Model(context + "/icons/" + icon)));
	}
 
	protected void onComponentTag(ComponentTag tag)
	{
		super.onComponentTag(tag);
		checkComponentTag(tag, "img");
	}
}

On voit dans le code précédent que nous avons ajouté un [AttributeModifier] à notre composant,
ce qui aura pour finalité de dire à Wicket que, au moment ou il construira le code HTML de sortie, il devra ajouter un attribut “src”.

Conclusion

Voila donc quelques petits examples qui peuvent vous être utile un jour. Ou pas…

Les sources du projet se trouvent ici.

Imprimer cet article Imprimer cet article

  3 Responses to “Wicket par la pratique : URLCodingStrategy, Breadcrumb et Image”

  1. Génial ton article!

  2. voleur de template ! ;)

  3. @Tom : arrete tu va me faire rougir :p

    @Grego : depeche toi de remettre ton site en ligne que je puisse te linker (vu que tu es quasiment mon lead web designer :x )

 Leave a Reply

(required)

(required)


× nine = 81

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

   
© 2011 NooCodeCommit Suffusion theme by Sayontan Sinha