Wicket in Action

Wicket 1.5 - Mounting pages

20 July 2011, by martin-g

In the previous article I described how IRequestMappers work. In this installment I'll show you how to mount pages at nice looking urls.

In Wicket 1.4 there were several implementations of IRequestTargetUrlCodingStrategy with which the developer was able to mount a page at a given path and the request parameters were encoded/decoded depending on the chosen coding strategy. E.g. with QueryStringUrlCodingStrategy the parameters were read/written in the request's query string - /mount/path?param1=value1¶m2=value2, with IndexedParamUrlCodingStrategy the parameters are represented as part of the request path - /mount/path/param1/param2, with MixedParamUrlCodingStrategy it was possible to use both query string based and indexed based ones.

In Wicket 1.5 all these are combined in MountedMapper. It can encode/decode the parameters in the query string, as indexed and as named indexed.

To mount a page with MountedMapper you should do something like:

public void init() {
  mountPage("/mount/path", MyPage.class);
  // #mountPage() is a shortcut for:
  // mount(new MountedMapper("/mount/path", MyPage.class));

Now a request to http://host/mount/path will be handled by MyPage and it wont have any parameters. A request to http://host/mount/path/indexed?queryNamed=queryValue will have one indexed and one named parameters. They can be read with PageParameters#get(0) and #get("queryNamed") respectfully.

The new functionality in 1.5 is that now you can have indexed parameters which have names.
If you use mountPage("/mount/path/${named1}/${named2}", MyPage.class); then the request url may look like http://host/mount/path/value1/value2 and the parameters' values can be read with PageParameters#get("named1") and #get("named2"). MyPage will handle this request only if both parameters are provided. If 'named2' is not provided then the request mapper wont match and will let another mapper to handle the request.
One more cool thing is that you can have optional indexed named parameters. The difference with mandatory ones is that they use hash sign instead of dollar sign - #{optional}. A mapping like mountPage("/mount/path/${named1}/#{named2}", MyPage.class); will match for both requests http://host/mount/path/value1 and http://host/mount/path/value1/value2.

To mount all pages in a package now you should use:

1 public void init() {
2   super.init();
3   mountPackage("package", com.example.pages.SomePage.class);
4 }

With this a request to http://host/package/AnotherPage will be handled by AnotherPage only if it is in the same package as SomePage, i.e. com.example.pages.

The last mapper which we will discuss today is BookmarkableMapper. This is the mapper which is used when there is no explicit mapping for a page. For example using setResponsePage(com.example.pages.NotMappedPage.class) will produce an url like http://host/wicket/bookmarkable/com.example.pages.NotMappedPage. This functionality is the same as ?wicket:bookmarkable=com.example.pages.NotMappedPage in Wicket 1.4. To change the namespace - wicket/bookmarkable - you'll have to setup custom IMapperContext by overriding Application.newMapperContext().

For more information about other mappers provided by Wicket read Request Mappers wiki page.
Some code exploring this topic can be found at: Mappers examples.

In the next article I'll show you how to mount resources.