A Maven Quickstart on Wicket, Spring and Hibernate
Apache Wicket seems to gain popularity. At least it looks like more and more (large) organisations use Wicket in their (production) web applications.
And why not?
- It’s open source (under the Apache licence)
- There is a large and active community
- There is no XML configuration
- There is good separation between logic (Java) and view (Html)
- It’s pure (OO) Java!
That last item tells me this is an ideal framework for Java developers like you(?) and me. If you’re familiar with other webframeworks like JSF of Spring MVC perhaps, you might have to switch a button in your mind though. Wicket is different in a few ways, you will notice that later.
A simple web application with just Wicket would probably not be sufficient in most cases. Usualy there is the need of a database and preferably we want to have a nice architecture with separated Dao-, Service- and front-end layers, where you can continue to use other frameworks in the backend. And, of course, we want Maven as our build environment.
In this blogpost I’ll show you how to quickly setup a Wicket application using Maven (2), Spring and Hibernate. In this case I use a HsqlDB file-database but other Hibernate configuration are easily Google-able.
I will explain the setup with an example application of which I have created a maven archetype. The application created by the archetype has actually done all the work for you, but keep reading if you want to know how.
Create the application
To create the example application execute the Maven archetype command like this:
mvn archetype:generate -DarchetypeGroupId=nl.iprofs -DarchetypeArtifactId=wicket-spring-hibernate-quickstart -DarchetypeVersion=1.3 -DarchetypeRepository=http://www.iprofs.nl/repository/ -DinteractiveMode=false -DgroupId=com.mycompany -DartifactId=myproject
The command will create a map with your demo application. Do this inside the map where you want to have it created, for example C:\myWorkspace\. Also you may want to change the last 2 arguments, groupId and artifactId to your own values.
After the archetype created your project you should be able to run it with the following command from within your application’s directory:
mvn jetty:run
… and open your browser at http://localhost:8080/myproject (or whatever name you have given it).
Play around with the five different (growing) examples in the *web.examples packages. Be sure to have the corresponding parent in the WicketApplication class as you head to newer examples and uncomment the insertion of the userManager in the applicationContext once you are at the fourth example.
Let’s start
We will start with the maven project. In the pom.xml we see the folowing dependencies:
| groupId | artifactId | version | Note |
|---|---|---|---|
| org.apache.wicket | wicket | 1.4.15 | The core Wicket library |
| org.apache.wicket | wicket-spring | 1.4.15 | The integration of a Wicket application in Spring |
| org.apache.wicket | wicket-extensions | 1.4.15 | Extentions to the core Wicket with lots of perfect (markup) components out of the box. Not needed in a simple Hello World but comes in handy very quickly |
| junit | junit | 3.8.2 | For a simple unit test of our homepage, we might want a newer version here |
| org.springframework | spring | 2.5.6 | The core Spring library |
| org.springframework | spring-test | 2.5.6 | Spring library used for unit testing using Spring beans |
| org.hibernate | hibernate | 3.2.6ga | Hibernate core library (3.2.6ga is a popular version) |
| hsqldb | hsqldb | 1.8.0.7 | The Hsql (file) database library |
| commons-dbcp | commons-dbcp | 1.2.2 | Used as the HsqlDB datasource |
| javax.servlet | servlet-api | 2.5 | Only needed for a handy lookup in our HsqlDB configuration in this example |
| log4j | log4j | 1.2.14 | Used for the logging in our application |
| org.slf4j | slf4j-log4j12 | 1.4.2 | Used for formatting our logging. |
Now, our map structure should look familiar, like this:
- src/main/java/ – Containing our Java packages. In the web subpackages where we place our Wicket code we will see the Java files as well as the html files!
- src/main/resources/ – Containing our Hibernate mapping files (in this example we’re not using JPA annotations), the Spring applicationContext.xml and our HsqlDB files.
- src/test/java/ – Containing our unit tests
- src/main/webapp/ – Containing our css stylesheets / javascripts / images but NOT our Html files! Plus of course our WEB-INF/web.xml defining our Spring-Wicket web-application.
The Spring configuration
In the applicationContext.xml we will describe our Spring configuration. It will contain the following beans:
- wicketApplication. This is the root of the Wicket application, it is associated with an instance of ‘the’ WicketServlet, handling all requests for Wicket.
- dataSource. The source to our data using the (jdbc) driver. (in this case to our Hsql database)
- transactionManager. A manager (for the service layer) handling the (database) transactions, implemented by Spring’s HibernateTransactionManager
- managerTemplate. A template bean (parent) for our managers (servicelayer). This template is a Spring AOP proxyFactoryBean which we’ll give an interceptor (another Spring bean) for transations using the transactionManager.
- sessionFactory. A factoryBean for the Hibernate sessions. This bean, implemented by Spring’s LocalSessionFactoryBean uses the dataSource bean and gets the Hibernate mappingfiles and other Hibernate proberties
- Dao- and manager-beans. These backend interfaces can be injected in the wicketApplication bean so we will be able to reach the backend from within our front-end Wicket code.
The Hibernate configuration
The Hibernate configuration is mostly done in the Spring configuration as mentioned before. Look in the applicationContext.xml and the files in src/main/resources/hibernatemappings/ for more details.
As I don’t want to (and can) get into details about Hibernate itself I suggest to Google around for more information.
The Wicket configuration
For a simple Wicket application like this, there is not much to configure. As we saw in the Spring configuration we’ll need a wicketApplication bean. This bean should be an extention of the org.apache.wicket.protocol.http.WebApplication class which is used by the (single) WicketServlet. The only 2 methods we have to implement here are:
- getHomePage() Returning the class of the homepage (an implementation of org.apache.wicket.markup.html.WebPage)
- init() An initialisation method called during startup. Here it is possible to create bookmarkable pages for example or authorization. You can leave it empty for now.
It is good practice to create a bookmarkable pages. This means giving a logical name to a page (which is allways a class extended from org.apache.wicket.markup.html.WebPage) so you can enter the URL to a page manualy (or add it to some third party menu). You can do this in the WicketApplication class by calling the mountBookmarkablePage(path, classfile). As parameters you’ll give a (web)path to the page, for example “/homepage”, or “/admin/users”, and the class of that page (for example HomePage.class).
Since you have implemented the getHomePage() method, Wicket knows which page to show you when you’ll enter the URL to your application (being the WicketServlet) in your browser.
The web.xml configuration
As mentioned before, there is a single WicketServlet handling all requests for Wicket(pages). In the web.xml you will see that we only need a Wicket filter and corresponding filter-mapping.
<filter>
<filter-name>wicket.wicketSpringHibernateQuickstart</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
</filter><filter-mapping>
<filter-name>wicket.wicketSpringHibernateQuickstart</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
You will notice that we use the org.apache.wicket.spring.SpringWebApplicationFactory (from our wicket-spring dependency) as a factory class instead of directly pointing to our WebApplication class. This is where Wicket and Spring come together. the SpringWebApplicationFactory will look for a bean with an implementation of Wicket’s WebApplication and forwards the request to Wicket.
That’s it! Have a look at the Apache Wicket website for more information, read a book of have a look at some examples.
Enjoy!
Hello,
The archetype does not seem to work. I get the following exception :
[ERROR] org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested exception: Content is not allowed in prol
og.
org.apache.maven.archetype.exception.ArchetypeGenerationFailure: org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in
prolog. Nested exception: Content is not allowed in prolog.
at org.apache.maven.archetype.generator.DefaultFilesetArchetypeGenerator.generateArchetype(DefaultFilesetArchetypeGenerator.java:236)
at org.apache.maven.archetype.generator.DefaultArchetypeGenerator.processFileSetArchetype(DefaultArchetypeGenerator.java:215)
at org.apache.maven.archetype.generator.DefaultArchetypeGenerator.generateArchetype(DefaultArchetypeGenerator.java:130)
at org.apache.maven.archetype.generator.DefaultArchetypeGenerator.generateArchetype(DefaultArchetypeGenerator.java:290)
at org.apache.maven.archetype.DefaultArchetype.generateProjectFromArchetype(DefaultArchetype.java:75)
at org.apache.maven.archetype.mojos.CreateProjectFromArchetypeMojo.execute(CreateProjectFromArchetypeMojo.java:185)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:451)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:558)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:512)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:482)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:330)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:227)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:142)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:287)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested exception: Content is not allowed in p
rolog.
at org.dom4j.io.SAXReader.read(SAXReader.java:482)
at org.dom4j.io.SAXReader.read(SAXReader.java:365)
at org.apache.maven.archetype.common.DefaultPomManager.addModule(DefaultPomManager.java:88)
at org.apache.maven.archetype.generator.DefaultFilesetArchetypeGenerator.processPomWithParent(DefaultFilesetArchetypeGenerator.java:698)
at org.apache.maven.archetype.generator.DefaultFilesetArchetypeGenerator.processFilesetProject(DefaultFilesetArchetypeGenerator.java:594)
at org.apache.maven.archetype.generator.DefaultFilesetArchetypeGenerator.processFilesetModule(DefaultFilesetArchetypeGenerator.java:515)
at org.apache.maven.archetype.generator.DefaultFilesetArchetypeGenerator.generateArchetype(DefaultFilesetArchetypeGenerator.java:206)
… 23 more
[INFO] ————————————————————————
[ERROR] BUILD FAILURE
[INFO] ————————————————————————
[INFO] : org.apache.maven.archetype.exception.ArchetypeGenerationFailure: org.dom4j.DocumentException: Error on line 1 of document : Content is not a
llowed in prolog. Nested exception: Content is not allowed in prolog.
org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested exception: Content is not allowed in prolog.
org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested exception: Content is not allowed in prolog.
Regards,
Arnaud
Hello Arnaud,
I don’t have any problems here on multiple machines. Can you tell me what maven version you use and which OS you are running.
Do you have any specific settings in your settings.xml?
You might want to temporary remove it and try it again (and perhaps clean or move your local repository).
Thanks for your response.
I found the problem : my local repository was corrupt.
I cleared it, and it’s work.
Regards,
Arnaud
Hi, I’m newbie in Java Development and Wicket and I don’t know how to change the first testing example to even the second or the third one.
All my workaround failed.
Please help me with using you perfect examples cause it’s very important to me.
Hi Evgenioni,
My guide is written for people who already have java experience but sure I would like to help you out a bit. Can you give me specific errors or problems you experience?
Maybe as a newbie it’s better to start reading a java book and perhaps a few chapters of the Wicket in Action book first and have them next to you when working on the examples.
Try to find and understand the differences between the given examples.
Thank you for answering. I’ll start reading the java and wicket books. But it’s to difficult for me to find solution or article where could be included some different technologies.
In my application I need to use PostgreSQL database for storing data, AJAX for dynamic information updates on the site.
I’ve started to read Wicket Cookbook, but also will read Wicket in Actoin.
Thank you.
There is a nice Wicket plugin for eclipse out there – qwickie which opens the view and its related controller simultatiously (when either one is clicked). It also has a handy outline view of code. When clicking on id’s the corresponding code will be opened in the other file (view-> controller, controller -> view).
Be sure to check out these and other features of qwikcie from apache:
http://code.google.com/p/qwickie
Hi! Thanks a lot for the tutorial!
I’m trying to replicate the first example in a clean project and after setting all the configs files and everything ‘the same’ as yours (I’m using wicket + spring + hibernate), it displays this error:
ContextLoaderListener
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1688)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1533)
at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:525)
at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:507)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:124)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5260)
The only difference that I see is that in your projects deployment assembly you have a persisted container reference, don’t know if this is the reason why the context is not being loaded.
Appreciate any help.
Thanks!
Hi,
I followed the instructions and kept my project name crystal360. I did mvn jetty:run and it ran successfully. When I try to to access http://localhost:8080/crystal360, I get below error.
Access to the webpage was denied
You are not authorized to access the webpage at http://localhost:8080/crystal360. You may need to sign in.
HTTP Error 403 (Forbidden): The server refused to fulfill the request.