MarcGiffing / wicket-spring-boot

Spring Boot starter for Apache Wicket
151 stars 61 forks source link
java spring spring-boot spring-boot-starter wicket

= Wicket autoconfiguration with Spring Boot

Current release version:

NOTE: http://search.maven.org/#search|ga|1|com.giffing.wicket.spring.boot

NOTE: Example projects: https://github.com/MarcGiffing/wicket-spring-boot-examples

[[introduction]] == Introduction

https://dzone.com/articles/enhance-wicket-with-spring-boot by Andrea Del Bene

This project makes it easy to create a new Wicket projects with a minimum of configuration effort. It uses Spring Boot to autoconfigure Wickets core and its extension (related projects like wicketstuff, beanvalidation...) with an reasonable default value which can be overridden over property files.

Configures an embedded Servlet Container by default (Spring Boot Feature). Autoconfiguration of the needed link:wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/WicketWebInitializer.java[Wicket Servlet filters]. Autoconfiguration for Spring/Spring-Security and dependency injection support with @SpringBean. Autoconfiguration of Wicket <>. ** Faster development support with <>

[[getting_started]] == Getting started

To get started you have to create a new Maven Project (or another preferred dependency/build-management tool) and add the wicket-spring-boot-starter dependency to your configuration.

[source,xml]

com.giffing.wicket.spring.boot.starter wicket-spring-boot-starter

Beside the Maven dependency configuration we need the following steps to do

. Create a class which is marked with @SpringBootApplication - see http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-using-springbootapplication-annotation[Springs documentation] . Create your HomePage class (with HTML) which will me marked with @WicketHomePage

[source,java]

@SpringBootApplication public class WicketApplication { public static void main(String[] args) throws Exception { new SpringApplicationBuilder() .sources(WicketApplication.class) .run(args); }

}

@WicketHomePage public class HomePage extends WebPage { }

You content

Thats all! When you execute the main method you will get a fully working and configured Wicket application. An embedded Tomcat is automatically started.

In a usal Wicket application you would like to provide custom configuration in Wickets WebApplication init() method. You could create your own 'extension' by creating a bean which implements WicketApplicationInitConfiguration

[source,java]

@ApplicationInitExtension public class YouExtensionConif implements WicketApplicationInitConfiguration {

@Override public void init(WebApplication webApplication) { // your custom configuration }

}

If this configuration is not enough and you want to override special methods of Wickets WebApplication class you have to create a bean which extends one of the following two classes

  • WicketBootStandardWebApplication - Without Security
  • WicketBootSecuredWebApplication - With Security - You'll need a security provider like <>

[source,java]

@Component public class WicketWebApplication extends WicketBootSecuredWebApplication { @Override protected void init() { super.init(); } }

The custom WicketWebApplication is automatically picked up instead of the default provided one. You can also override the getHomePage method() if you don't want to use the special @WicketHomePage annotations to mark the home page.

To package the application as an executable jar you have to add the spring-boot-maven-plugin.

[source,xml]

org.springframework.boot spring-boot-maven-plugin

Resource files (html, css, js, ...) are not copied to the target folder if placed in the src/main/java folder. You have to tell Maven to copy these files:

[source,xml]

src/main/resources src/main/java ** **/*.java

[[how_does_it_work]] == How does it work?

To fully understand how http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-developing-auto-configuration[Spring Boots autconfiguration] and in general Spring Boot works you should read the excellent http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/[documentation] from this fantastic http://projects.spring.io/spring-boot/[project].

As an an example we will look to the AnnotatedMountScanner configuration. The https://github.com/wicketstuff/core/wiki/Annotation[annotated mount scanner] is an project which supports bookmarkable URLs configured by annotations on WebPage classes. If you have this '@MountPath("login")' annotation on a WebPage then the Page is mounted to 'http://localhost/login'.

In this project each configuration is separated in two classes to configure this particular feature/extension. The extension consists of a property and a configuration class.

The property class holds properties to configure the specific feature. In the AnnotatedMountScannerProperties class we found two properties:

[source,java]

@ConfigurationProperties(prefix = AnnotatedMountScannerProperties.PROPERTY_PREFIX) public class AnnotatedMountScannerProperties { public static final String PROPERTY_PREFIX = "wicket.stuff.annotationscan"; /**

  • @see AnnotatedMountScannerConfig */ private boolean enabled = true;

    /**

  • An alternative package name for scanning for mount path if the
  • WicketApplication should not used as the root scan package */ private String packagename;

This property file can be imported in the configuration class AnnotatedMountScannerConfig.

[source,java]

/**

  • Auto configuration for the {@link AnnotatedMountScanner}.
  • It uses the user defined {@link WebApplication} as the default package scan
  • root directory.
  • Enables annotate mount scanner if the following two condition matches:
    1. The {@link AnnotatedMountScanner} is in the classpath.
    1. The property {@link AnnotatedMountScannerProperties#PROPERTY_PREFIX}
  • .enabled is true (default = true)
  • @author Marc Giffing
  • */ @ApplicationInitExtension @ConditionalOnProperty(prefix = AnnotatedMountScannerProperties.PROPERTY_PREFIX, value = "enabled", matchIfMissing = true) @ConditionalOnClass(value = org.wicketstuff.annotation.scan.AnnotatedMountScanner.class) @EnableConfigurationProperties({ AnnotatedMountScannerProperties.class }) public class AnnotatedMountScannerConfig implements WicketApplicationInitConfiguration {

    @Autowired private AnnotatedMountScannerProperties prop;

    @Override public void init(WebApplication webApplication) { String packagename = webApplication.getClass().getPackage().getName(); if (prop.getPackagename() != null) { packagename = prop.getPackagename(); } new AnnotatedMountScanner().scanPackage(packagename).mount(webApplication); } }

If all conditions on the AnnotatedMountScannerConfig matches the configuration class is configured as a spring bean. All Spring beans which implements the interface WicketApplicationInitConfiguration will be injected as a list in the default WicketBootWebApplication class.

In the WicketBootWebApplication class we iterate in Wickets init method over the list and call on each the init method to configure the application.

[source,java]

public class WicketBootWebApplication extends AuthenticatedWebApplication { @Autowired(required = false) private List configurations = new ArrayList<>(); @Override protected void init() { super.init(); for (WicketApplicationInitConfiguration configuration : configurations) { configuration.init(this); } } }

[[spring_profile_dev_configuration]] === Spring profile configuration

The Wicket Spring Boot Starter project ships with a default development configuration. It can be activated by activating the 'development' Spring profile in the main class or over external JVM/Maven arguments.

The default configuration can be overridden with a custom property file. See Spring Boots reference documentation http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config[here].

include::wicket-spring-boot-starter/src/main/resources/application-development.yml[] [source,yml]

wicket: core: settings: general: configuration-type: development debug: enabled: true component-use-check: true development-utilities-enabled: true stuff: htmlcompressor: enabled: false features: removeComments: false removeMultiSpaces: false removeIntertagSpaces: false removeQuotes: false compressJavaScript: false compressCss: false simpleDoctype: false removeScriptAttributes: false removeStyleAttributes: false removeLinkAttributes: false removeFormAttributes: false removeInputAttributes: false simpleBooleanAttributes: false removeJavaScriptProtocol: false removeHttpProtocol: false removeHttpsProtocol: false preserveLineBreaks: false external: development: devutils: statelesschecker: enabled: true interceptor: enable-live-sessions-page: true diskstorebrowser: enabled: true wicketsource: enabled: true

[[custom-conditions]] == Custom conditions

This section lists custom conditional configuration like Spring Boot ones.

=== @ConditionalOnWicket

With the ConditionOnWicket annotation you can check that configuration classes only apply on a specific Wicket major version. If some functionality is only available on Wicket 7 you can use this annotation.

[source,java]

@ApplicationInitExtension @ConditionalOnWicket(value=7, range=Range.EQUALS_OR_HIGHER) public ConditionalConfig implements WicketApplicationInitConfiguration{ @Override public void init(WebApplication webApplication) { // configuration option which only apply to Wickets major version 7 or higher } }

[[extension]] == Extensions

The following section describes the current extensions and the required dependencies. An extension is a custom labeling in this project which is used to auto-configure a specific part of an Wicket application. An extension may require an external dependency or is using Wickets core features. See section <> to get a deeper knowledge.

  • <> DEPLOYMENT-CONFIGURATIONS ** <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> *** <>

DEVELOPMENT-CONFIGURATIONS ** <> <> <> <> <> <>

[[extension-general]] === General

Wicket can be started in DEVELOPMENT and DEPLOYMENT mode. You can change the configuration type over the following property configuration. The given property is automatically mapped to Wickets ConfigurationType enumeration.

[source,properties]

wicket.core.settings.general.configuration-type=development # development/deployment(default)

wicket.web.servlet.filter-mapping-param=/ wicket.web.servlet.dispatcher-types=request, error, async # request, error, async, include, forward wicket.web.servlet.init-parameters.= # map<string,string> - configuration support for additional servlet init parameters

exception settings

wicket.core.settings.exceptions.thread-dump-strategy=thread_holding_lock wicket.core.settings.exceptions.error-handling-strategy-during-ajax-requests=redirect_to_error_page

wicket.core.settings.requestcycle.render-strategy=redirect-to-buffer # redirect-to-buffer / one-pass-render / redirect-to-render wicket.core.settings.requestcycle.buffer-response=true wicket.core.settings.requestcycle.gather-extended-browser-info=false wicket.core.settings.requestcycle.response-request-encoding=UTF-8 wicket.core.settings.requestcycle.timeout-size=1 wicket.core.settings.requestcycle.timeout-unit=minutes wicket.core.settings.requestcycle.exception-retry-count=10

Markup - Settings

wicket.core.settings.markup.default-markup-encoding=UTF-8 # if null it uses the system default wicket.core.settings.markup.automatic-linking=false wicket.core.settings.markup.compress-whitespace=false wicket.core.settings.markup.strip-comments=false wicket.core.settings.markup.strip-wicket-tags=true wicket.core.settings.markup.throw-exception-on-missing-xml-declaration=false

RequestLogger - Settings

wicket.core.settings.requestlogger.enabled=false wicket.core.settings.requestlogger.record-session-size wicket.core.settings.requestlogger.requests-window-size

wicket.core.requestmapper.cryptmapper.enabled=false # URL encryption support

wicket.core.settings.pagestore.enabled=false # enables custom store settings wicket.core.settings.pagestore.session-size=2 wicket.core.settings.pagestore.session-unit=megabytes wicket.core.settings.pagestore.asynchronous= # overrides wickets default value only when set wicket.core.settings.pagestore.asynchronous-queue-capacity= # overrides wickets default value only when set wicket.core.settings.pagestore.file-store-folder= # overrides wickets default value only when set wicket.core.settings.pagestore.inmemory-cache-size= # overrides wickets default value only when set


If you insert e.g. developmentx you will get a startup error: [listing] Field error in object 'wicket' on field 'configurationType': rejected value [developmentx]; codes [typeMismatch.wicket.configurationType

==== Special Annotations

  • @WicketHomePage ** A Page marked with this annotation will be configured as the default home page. If multiple WicketHomePage annotation found an exception is thrown.
  • @WicketSignInPage ** A Page marked with this annotation will be configured as the default login page. A security provider like Spring Security is needed. If multiple annotations found an exception is thrown.
  • @WicketAccessDeniedPage ** A Page marked with this annotation will be configured as the default access denied page.
  • @WicketInternalErrorPage ** A Page marked with this annotation will be configured as the default internal error page.
  • @WicketExpiredPage
    ** A Page marked with this annotation will be configured as the default expired page.

[[extension-spring-security]] === Spring Security

This starter detects automatically Spring Security if the Spring Boot Starter Security dependency is added. Internally the WicketBootSecuredWebApplication is used instead of the WicketBootStandardWebApplication class.

[source,xml]

org.springframework.boot spring-boot-starter-security

If you wan't to disable the Spring Security configuration for Wicket use the following property.

[source,properties]

wicket.external.spring.security=false

[[extension-wicket-websocket]] === Wicket Native WebSockets

https://ci.apache.org/projects/wicket/guide/7.x/guide/single.html#nativewebsockets[Documentation]

This project provides an auto configuration support for native WebSockets. If the required dependencies are in the classpath a JavaxWebSocketFilter servlet filter is configured instead of the default WicketFilter.

To simplify the usage of sending WebSocket messages a class named WebSocketMessageBroadcaster is automatically registered as a spring bean. You can inject the class anywhere with @SpringBean and use the 'send' method to send WebSocket messages.

[source,properties]

wicket.external.websocket=true # enables WebSocket support - dependency required (move documentation to seperated section)

[source,xml]

org.apache.wicket wicket-native-websocket-javax

[[extension-beanvalidation]] === Bean validation

Wicket support for JSR 303 Bean validation. See Wickets user guide https://ci.apache.org/projects/wicket/guide/7.x/guide/single.html[Validation with JSR 303]

To enable Wickets bean validation you have to add the wicket-bean-validation dependency to your project. It will automatically configured and can be used in the project.

[source,properties]

wicket.external.beanvalidation.enabled=true # enabled by default if bean validation project is present

[source,xml]

org.apache.wicket wicket-bean-validation

[[extension-core-csrf-prevention]] === Core - Prevention of CSRF Attacks

[source,properties]

wicket.core.csrf.enabled=true wicket.core.csrf.no-origin-action=allow wicket.core.csrf.conflicting-origin-action=abort wicket.core.csrf.error-code=400 wicket.core.csrf.error-message=Origin does not correspond to request wicket.core.csrf.accepted-origins[0]=domain.name.tld # Just the domain name, no protocol wicket.core.csrf.accepted-origins[1]=other-domain.name.tld # Add more origins by increasing the index

TODO: There are some configuration options which should be added


[[extension-webjars]] === Webjars

https://github.com/l0rdn1kk0n/wicket-webjars

[source,properties]

wicket.external.webjars.enabled=true

[source,xml]

de.agilecoders.wicket.webjars wicket-webjars

[[extension-wicketstuff-annotationscan]] === Wicketstuff - annotationscan

Use wicketstuff-annotation to use Java Annotations and class path searching to mount your Wicket pages.

See https://github.com/wicketstuff/core/wiki/Annotation[documentation]

[source,xml]

org.wicketstuff wicketstuff-annotation

[source,properties]

wicket.stuff.annotationscan.enabled=true wicket.stuff.annotationscan.packagename=

[[extension-wicketstuff-htmlcompressor]] === Wicketstuff - htmlcompressor

See https://github.com/wicketstuff/core/wiki/Htmlcompressor[documentation]

[source,xml]

org.wicketstuff wicketstuff-htmlcompressor com.yahoo.platform.yui yuicompressor

[source,properties]

wicket.stuff.htmlcompressor.enabled=true wicket.stuff.htmlcompressor.features.*=

[[extension-core-serializer-deflated]] === Core - serializer-deflated

[source,properties]

wicket.core.serializer.deflated.enabled=false # has to be explicit enabled. deflates the outputstream, reducing page store size by up to a factor 8 at a price of about 2-20ms

[[extension-wicketstuff-serializer-fast2]] === Wicketstuff - serializer-fast2

See https://github.com/wicketstuff/core/wiki/FastSerializer2[documentation]

[source,xml]

org.wicketstuff wicketstuff-serializer-fast2

[source,properties]

wicket.stuff.serializer.fast2.enabled=true

[[extension-wicketstuff-serializer-kryo2]] === Wicketstuff - serializer-kryo2

See https://github.com/wicketstuff/core/wiki/Kryo-Serializer[documentation]

[source,xml]

org.wicketstuff wicketstuff-serializer-kryo2

[source,properties]

wicket.stuff.serializer.fast2.enabled=true

[[extension-wicketstuff-restannotations]] === Wicketstuff - restannotations

See https://github.com/wicketstuff/core/tree/master/wicketstuff-restannotations-parent[documentation]

[source,xml]

org.wicketstuff wicketstuff-restannotations org.wicketstuff wicketstuff-restannotations-json

[source,properties]

wicket.stuff.restannotations.enabled=true wicket.stuff.restannotations.packagename= # the package name to scan for project specific annotations

[[extension-general-debugsettings]] === General - debugsettings

Wicket provides some debug settings which could be

[source,properties]

wicket.core.settings.debug.enabled=false wicket.core.settings.debug.developmentUtilitiesEnabled=true # Enables all of the panels and pages, etc, from wicket-devutils package. wicket.core.settings.debug.ajaxDebugModeEnabled=true # if true: wicket-ajax-debug.js is added to header wicket.core.settings.debug.componentUseCheck=true wicket.core.settings.debug.outputMarkupContainerClassName=false wicket.core.settings.debug.componentPathAttributeName=

[[extension-datastore]] == Datastore

[[extension-datastore-httpsession]] === Datastore HttpSession

[source,properties]

wicket.core.datastore.httpsession.enabled=false wicket.core.datastore.httpsession.pagesNumber=20 # the maximum number of pages the data store can hold

[[extension-datastore-cassandra]] === Datastore cassandra

See https://github.com/wicketstuff/core/wiki/DataStores[Documentation]

[source,properties]

wicket.stuff.datastore.cassandra.enabled=true wicket.stuff.datastore.cassandra.contact-points= #comma-separated list wicket.stuff.datastore.cassandra.table-name=pagestore wicket.stuff.datastore.cassandra.keyspace-name=wicket wicket.stuff.datastore.cassandra.record-ttl=30 wicket.stuff.datastore.cassandra.record-ttl-unit=minutes wicket.stuff.datastore.cassandra.session-size=2 wicket.stuff.datastore.cassandra.session-unit=megabytes

[source,xml]

org.wicketstuff wicketstuff-datastore-cassandra

[[extension-datastore-hazelcast]] === Datastore hazelcast

See https://github.com/wicketstuff/core/wiki/DataStores[Documentation]

[source,properties]

wicket.stuff.datastore.hazelcast.enabled=true wicket.stuff.datastore.hazelcast.session-size=2L wicket.stuff.datastore.hazelcast.session-unit=megabytes

[source,xml]

org.wicketstuff wicketstuff-datastore-hazelcast com.hazelcast hazelcast

[[extension-datastore-memcached]] === Datastore memcached

See https://github.com/wicketstuff/core/wiki/DataStores[Documentation]

[source,properties]

wicket.stuff.datastore.memcached.enabled=true wicket.stuff.datastore.memcached.session-size=2L wicket.stuff.datastore.memcached.session-unit=megabytes wicket.stuff.datastore.memcached.expiration-time=30 wicket.stuff.datastore.memcached.port=11211 wicket.stuff.datastore.memcached.server-names= wicket.stuff.datastore.memcached.shutdown-timeout=30 wicket.stuff.datastore.memcached.shutdown-timeout-unit=minutes

[source,xml]

org.wicketstuff wicketstuff-datastore-memcached

[[extension-datastore-redis]] === Datastore redis

See https://github.com/wicketstuff/core/wiki/DataStores[Documentation]

[source,properties]

wicket.stuff.datastore.redis.enabled=true wicket.stuff.datastore.redis.session-size=2L wicket.stuff.datastore.redis.session-unit=megabytes wicket.stuff.datastore.redis.expiration-time=30 wicket.stuff.datastore.redis.port=11211 wicket.stuff.datastore.redis.server-names= wicket.stuff.datastore.redis.shutdown-timeout=30 wicket.stuff.datastore.redis.shutdown-timeout-unit=minutes

[source,xml]

org.wicketstuff wicketstuff-datastore-redis

[[extension-wicketstuff-jamon]] === Wicketstuff - JAMon

Used to monitor page requests. Provides a statistic page.

See https://github.com/wicketstuff/core/blob/master/jamon-parent/[Github]

[source,properties]

wicket.stuff.monitoring.jamon.enabled=true wicket.stuff.monitoring.jamon.include-source-name-in-monitor-label=true wicket.stuff.monitoring.jamon.mountPage=/monitoring/jamon # the url to which the statistic page is mounted

[source,xml]

org.wicketstuff wicketstuff-jamon

NOTE: JAMon includes hazelcast to gather statistics. You may need to disable the datastore hazelcast support: <>

[[extension-devutils]] === Devutils

[source,xml]

org.apache.wicket wicket-devutils

[[extension-devutils-diskstorebrowser]] ==== Devutils - diskstorebrowser

[source,properties]

wicket.external.development.devutils.diskstorebrowser.enabled=false wicket.external.development.devutils.diskstorebrowser.mountPage=devutils/diskstore/browser

[[extension-devutils-inspector]] ==== Devutils - inspector

[source,properties]

wicket.external.development.devutils.diskstorebrowser.enabled=false wicket.external.development.devutils.diskstorebrowser.mountPage=devutils/diskstore/browser

[[extension-devutils-statelesschecker]] ==== Devutils - statelesschecker

[source,properties]

wicket.external.development.devutils.interceptor.enableLiveSessionsPage=false wicket.external.development.devutils.interceptor.liveSessionPageMount=devutils/inspector/live-session-page

[[extension-wicketsource]] === Wicket-Source

See https://github.com/jennybrown8/wicket-source/wiki[documentation]

[source,xml]

com.github.jennybrown8.wicket-source wicket-source

[source,properties]

wicket.external.development.wicketsource.enabled=false

[[extension-springboot-devtools]] ==== Spring Boot - DevTools

See https://spring.io/blog/2015/06/17/devtools-in-spring-boot-1-3[Spring Boot DevTools]

The project tries to improve the development-time experience when working with Spring Boot. There is a problem with Wickets default and other serializer (fast2, kryo2...). See https://github.com/MarcGiffing/wicket-spring-boot/issues/29[Issue 29] If the spring-boot-devtools dependency is in the classpath a link:/wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/springboot/devtools/SpringDevToolsSerializer.java[special Spring serializer] will be activated.

All other serializer will only be activated if the Spring Boot DevTools dependency is not in the classpath.

[source,xml]

org.springframework.boot spring-boot-devtools

[[war_deployment]] == Configure as WAR for deploy on Servlet Container

115

To run the application as a war file in the Servlet Container like Tomcat you have to do the following steps.

[source,java]

@SpringBootApplication public class WicketApplication extends SpringBootServletInitializer {

//Can be used while developing public static void main(String[] args) throws Exception { new SpringApplicationBuilder() .sources(WicketApplication.class) .run(args); }

//Executed when deployed as a WAR in a Servlet container. @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { builder.properties( WebSocketWicketWebInitializerAutoConfiguration.REGISTER_SERVER_ENDPOINT_ENABLED + "=false" ); return super.configure( builder ); }

}

If you already extend from a Wicket specific class you can create a separated class which extends from SpringBootServletInitializer (https://github.com/MarcGiffing/wicket-spring-boot/issues/115#issuecomment-311712298).