Table of Contents | ||||
---|---|---|---|---|
|
...
Wicket 1.4
To mount a page in Wicket 1.4 the developer had to use org.apache.wicket.protocol.http.WebApplication's:
- #mount
#mount(IRequestTargetUrlCodingStrategy)
- #mount
#mount(String, PackageName)
- #mountBookmarkablePage
#mountBookmarkablePage(String, Class<T>)
#mountBookmarkablePage #mountBookmarkablePage(String, String, Class<T>)
an And to mount a resource:- #mountSharedResource
#mountSharedResource(String, String)
For more information about these methods check https://cwiki.apache.org/WICKET/url-coding-strategies.html
A new way in Wicket 6
The org.apache.wicket.protocol.https.HttpsMapper can now be subclassed. This means that by overriding the org.apache.wicket.protocol.https.HttpsMapper.getDesiredScheme method you can programmatically determine what scheme to use.
Add this to your Application.java:
Code Block |
---|
public void init() {
super.init();
setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), new HttpsConfig(80, 443)) {
@Override
protected Scheme getDesiredSchemeFor(Class<? extends IrequestablePAge> pageClass) {
if (getConfigurationType()==RunTimeConfigurationType.DEVELOPMENT)
return Scheme.HTTP;
else
return super.getDesiredSchemeFor(pageClass);
}
}
|
The new way in Wicket 1.5
Wicket 1.5
org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy
interface and all its implementations are replaced with the org.apache.wicket.request. IRequestMapper
and its respective implementations.
To add a mapper into the list of mappers which Wicket will use to process a request use org.apache.wicket. Application.getRootRequestMapperAsCompound().add(mapperInstance)
.
When a request comes Wicket will ask all registered mappers whether they are able to process the request. Mappers with bigger org.apache.wicket.request. IRequestMapper.getCompatibilityScore(Request)
are asked first. So Wicket calls org.apache.wicket.request. IRequestMapper.mapRequest(Request)
for each mapper and if it returns non-null IRequestHandler
then this is the handler which will be used to process the current request. In #mapRequest(Request)
the mapper have to check request's segments (this is similar to httpServletRequest#getPath()
) and request's parameters (GET and POST) and decide whether they match to the mapper's functionality. For exampleorg.apache.wicket.request.mapper., HomePageMapper
is the mapper used to process all requests without any segments, i.e. requests to '/' with or without any query parameters.
The actual processing of the request is being done with org.apache.wicket.request. IRequestHandler.respond(IRequestCycle)
. During the processing Wicket asks the mappers to create a org.apache.wicket.request.Url objects Url
object for each callback handler (e.g. link, form, ....) via org.apache.wicket.request. IRequestMapper.mapHandler(IRequestHandler)
.
Sometimes you may want a specific IRequestMapper to be process all incoming requests. To do this you should use org.apache.wicket. Application.setRootRequestMapper(IRequestMapper)
. This mapper may manipulate the Request's Url URL and then pass it for further processing to the registered non-root mappers. For examples of this idea see the source code of org.apache.wicket.request.mapper. CryptoMapper
and org.apache.wicket.protocol.https.HttpsMapper HttpsMapper
.
Default mapper implementations
HomePageMapper
This mapper is pre-configured by Wicket and there is no need to register it. It is used to create IRequestHandler
for requests to the root ('/') of the application context.
BookmarkableMapper
This mapper decodes and encodes bookmarkable URLs like:
- /wicket/bookmarkable/com.example.pages.MyPage - using
BookmarkablePageRequestHandler
for stateless pages and using RenderPageRequestHandler for stateful/hybrid pages - /wicket/bookmarkable/com.example.pages.MyPage?2-click-foo-bar-baz - using
BookmarkableListenerInterfaceRequestHandler
to process bookmarkable listeners (e.g. Behavior).
...
To change 'wicket' and 'bookmarkable' segments in the Url URL to something else see org.apache.wicket.request.mapper. IMapperContext.getNamespace()
(the default implementation can be replaced with org.apache.wicket. Application.newMapperContext()
).
MountedMapper
This mapper is similar to BookmarkableMapper
but the difference is that the user application defines the mount point where this mapper matches.
For example:
- /path/to/page1
- /path/to/pageN
- /path/to/page?2-5.click.1-foo-bar-baz (2 is the page version, 5 is render count, 1 is behavior index)
Usage:
Code Block | ||
---|---|---|
|
...
Code Block | |
---|---|
public void init() { super.init(); getRootRequestMapperAsCompound().add(new MountedMapper("/mount/point", MyPage.class)); mountPage("/mount/point", MyPage.class); // convenient method doing the same as above } |
This mapper is a combination of all IRequestTargetUrlCodingStrategy
implementations from Wicket 1.4. It supports:
Indexed parameters
...
- /page/idx1/idx2
mountPage("/page", MyPage.class);
Now a request to "/page/a/b/c" will be handled by MyPage and the parameters can be get with PageParameters.get(int)
(e.g. parameters.get(2) will return "c")
Named parameters
...
- /page/${named1}/${named2}
mountPage("/page/${named1}/${named2}", MyPage.class);
Now a request to "/page/a/b" will be handled by MyPage and the parameters can be get with PageParameters.get(String)
(e.g. parameters.get("named1") will return "a")
Optional named parameters
...
- /page/${named1}/#{named2\
mountPage("/page/${named1}/#{named2}", MyPage.class);
This means the second parameter is optional. Requests to "/page/a/b" , "/page/a/b/" and "/page/a/" will be handled by MyPage and the parameters can be get with PageParameters.get(String)
(e.g. parameters.get("named2") will return "b" for the first case and null for the second).
The mapper is smart enough to handle optional named parameters in any segment, not just the last one.
Arbitrary named parameters - /page/param1Name/param1Value/param2Name/param2Value
...
mount(new MountedMapper("/page", MyPage.class, new UrlPathPageParametersEncoder()));
Now a request to "/page/a/1/b/2" will be handled by MyPage and the parameters can be get with PageParameters.get(String)
(e.g. parameters.get("a") will return "1")
Query parameters - /page?param1Name=param1Value¶m2Name=param2Value
mountPage("/page", MyPage.class);
Now a request to "/page?a=a1&b=b1" will be handled by MyPage and the parameters can be get with PageParameters.get(String)
(e.g. parameters.get("a") will return "a1")
The mapper can handle a mix of the supported parameters - indexed + named + query.
PackageMapper
This mapper can mount a whole package. That is you mount a single page with a mount path prefix and then the mapper knows how to map all Page
implementations in that package.
Usage:
Code Block | ||
---|---|---|
|
...
public void init() { super.init(); getRootRequestMapperAsCompound().add( new MountMapper("/mount/point", new PackageMapper( PackageName.forClass(Page3.class)))); mountPackage("/mount/point", Page3.class); } |
Assuming that PageA package is "com.example.pages" a request to "/mount/point/PageB" will use com.example.pages.PageB if it exists and is an instance of Page.
ResourceMapper
A mapper which mounts ResourceReference
implementations.
Usage:
Code Block | ||
---|---|---|
|
...
public void init() { super.init(); getRootRequestMapperAsCompound().add(new ResourceMapper("/company/logo", new PackageResourceReference(MyPage.class, "res/logo.gif"))); mountResource("/company/logo", new PackageResourceReference(MyPage.class, "res/logo.gif"))); // convenient method doing the same as above } |
CryptoMapper
A wrapper around another mapper which will encrypt/decrypt the URLs generated by the inner one.
Usage:
Code Block | ||
---|---|---|
|
...
Code Block | |
---|---|
public void init() { super.init(); IRequestMapper cryptoMapper = new CryptoMapper(getRootRequestMapper(), this); setRootRequestMapper(cryptoMapper); } |
HttpsMapper
A mapper which makes a redirect to the same URL with HTTPS protocol if the requested page is annotated with @RequireHttps or to HTTP protocol if the last processed page had @RequireHttps and the one going to be processed has no such annotation.
...
Code Block |
---|
public class MyApplication extends WebApplication { public void init() { super.init(); getRootRequestMapperAsCompound().add(new MountedMapper("secured", HttpsPage.class)); setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), new HttpsConfig(80, 443))); } } |
Making all urls absolute
You can override RequestCycle#newUrlRenderer() with a different UrlRenderer to force all links to be absolute.
Since Wicket 6.x HttpsMapper can be easily extended
The HttpsMapper
can now be subclassed. This means that by overriding the HttpsMapper.getDesiredScheme
method you can programmatically determine what scheme to use.
Add this to your Application.java:
Code Block |
---|
public void init() |
Code Block |
import org.apache.wicket.request.Request; import org.apache.wicket.request.Url; import org.apache.wicket.request.UrlRenderer; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.string.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link UrlRenderer} which generates absolute urls * * @author Bas * */ public class AbsoluteUrlRenderer extends UrlRenderer { private static final Logger log = LoggerFactory.getLogger( AbsoluteUrlRenderer.class ); private final Url contextUrl, filterUrl; public AbsoluteUrlRenderer( Request request, String prefix ) { super( request ); this.contextUrl = buildContextUrl( request, prefix .init(); this.filterUrl = buildFilterUrl( request, prefix ); log.debug( "Prefix for absolute urls: {}", filterUrl ); } @Override public String renderRelativeUrl( Url url ) { Args.notNull( url, "url" ); if( url.isAbsolute() ) setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), new HttpsConfig(80, 443)) { return url.toString();@Override } protected else { Url absolute = fromFilterRelativeToAbsolute( url ); log.debug( "renderRelativeUrl: {} => {}", url, absolute ); String renderedUrl = absolute.toString(); return Strings.isEmpty( renderedUrl ) ? "." : renderedUrl; } } @Override public String renderContextRelativeUrl( String url ) { Args.notNull( url, "url" ); // Prevent prefixing a url twice Scheme getDesiredSchemeFor(Class<? extends IRequestablePage> pageClass) { if( url.startsWith( contextUrl.toString() ) ) { return url; } if( url.startsWith( "/" ) ) { url = url.substring( 1 ); } Url relativeUrl = Url.parse( url ); Url absoluteUrl = fromContextRelativeToAbsolute( relativeUrl );(getConfigurationType()==RunTimeConfigurationType.DEVELOPMENT) log.debug( "renderContextRelativeUrl: {} -> {}", relativeUrl, absoluteUrl ); return absoluteUrlScheme.toString()HTTP; } private Url buildContextUrl( Request request, String prefix ) { else Url url = new Url(); if( prefix != null && prefix.length() > 0 ) { url.getSegments().addAll( Url.parse( prefix ).getSegments() ); } String contextPath = request.getContextPath(); if( contextPath.length() > 0 ) { url.getSegments().addAll( Url.parse( contextPath.substring( 1 ) ).getSegments() ); } if( !url.isAbsolute() ) { url.getSegments().add( 0, "" ); } return url; } private Url buildFilterUrl( Request request, String prefix ) { Url url = buildContextUrl( request, prefix ); String filterPath = request.getFilterPath(); if( filterPath.length() > 0 ) { url.getSegments().addAll( Url.parse( filterPath.substring( 1 ) ).getSegments() ); } return url; } private Url fromContextRelativeToAbsolute( Url url ) { Url absolute = new Url( url ); absolute.prependLeadingSegments( contextUrl.getSegments() ); return absolute; } private Url fromFilterRelativeToAbsolute( Url url ) { Url absolute = new Url( url ); absolute.prependLeadingSegments( filterUrl.getSegments() ); return absolute; } } |
There is an optional prefix parameter which you can supply to the constructor to set a fixed prefix. The sole purpose of this prefix is to handle the case where the app server is behind a reverse proxy, and the reverse proxy maps a folder to a root-mapped application. E.g. the reverse proxy maps "/app" to an app running at "/" with the WicketFilter handling "/*". All urls need to be prefixed with "/app", but AbsoluteUrlRenderer cannot detect this.
Installing this custom UrlRenderer can be done by installing a custom IRequestCycleProvider:
Code Block |
---|
import org.apache.wicket.IRequestCycleProvider;
import org.apache.wicket.request.UrlRenderer;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.cycle.RequestCycleContext;
/**
* {@link RequestCycle} provider which overrides the {@link UrlRenderer} to generate absolute links.
*
* @see {@link AbsoluteUrlRenderer}
* @see {@link RequestCycle#getUrlRenderer()}
*
* @author Bas
*
*/
public class AbsoluteUrlRequestCycleProvider implements IRequestCycleProvider
{
private final String prefix;
public AbsoluteUrlRequestCycleProvider()
{
this( null );
}
public AbsoluteUrlRequestCycleProvider( String prefix )
{
this.prefix = prefix;
}
@Override
public RequestCycle get( RequestCycleContext context )
{
return new RequestCycle( context )
{
@Override
protected UrlRenderer newUrlRenderer()
{
return new AbsoluteUrlRenderer( getRequest(), prefix );
}
};
}
}
|
In your Application#init() method, call
...
return super.getDesiredSchemeFor(pageClass);
}
}
|
Making all URLs absolute
See page Making all URLs absolute
...