Full web project using a Java back-end to provide data for the map

The project

This is an example project with all the configuration you need. It is created using maven, uses a richfaces front-end and was deployed on a JBOSS 4.2.3 AS.

Project structure

Please create the following folder structure for your project.

folder structure

Necessary files

There are a few files that you need for the project.

pom.xml

Place your pom.xml in the root folder of your project. Below is a sample pom.xml provided.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.realdolmen.sf.mapface</groupId>
	<artifactId>tutorial</artifactId>
	<packaging>war</packaging>
	<version>1.0</version>
	<name>MapFace tutorial with backend</name>
	<url>http://maven.apache.org</url>
	<!-- Some additional repositories -->
	<repositories>
		<repository>
			<releases />
			<snapshots>
				<enabled>false</enabled>
				<updatePolicy>never</updatePolicy>
			</snapshots>
			<id>repository.jboss.com</id>
			<name>Jboss Repository for Maven</name>
			<url>http://repository.jboss.com/maven2/</url>
			<layout>default</layout>
		</repository>
		<repository>
			<id>maven2-repository.dev.java.net</id>
			<name>Java.net Repository for Maven</name>
			<url>http://download.java.net/maven/2/</url>
			<layout>default</layout>
		</repository>
	</repositories>
	<dependencies>
		<!-- JSF -->
		<dependency>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>1.2_08</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>1.2_08</version>
			<scope>provided</scope>
		</dependency>
		<!-- Facelets -->
		<dependency>
			<groupId>com.sun.facelets</groupId>
			<artifactId>jsf-facelets</artifactId>
			<version>1.1.14</version>
			<exclusions>
				<exclusion>
					<groupId>javax.el</groupId>
					<artifactId>el-api</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- Richfaces -->
		<dependency>
			<groupId>org.richfaces.framework</groupId>
			<artifactId>richfaces-api</artifactId>
			<version>3.3.1.GA</version>
		</dependency>
		<dependency>
			<groupId>org.richfaces.framework</groupId>
			<artifactId>richfaces-impl</artifactId>
			<version>3.3.1.GA</version>
		</dependency>
		<dependency>
			<groupId>org.richfaces.ui</groupId>
			<artifactId>richfaces-ui</artifactId>
			<version>3.3.1.GA</version>
		</dependency>

		<!-- LOGGING -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.13</version>
			<scope>provided</scope>
		</dependency>
		
		<!-- SERVLET API -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		
		<!-- Custom GMAP Component -->
		<dependency>
				<groupId>com.realdolmen</groupId>
				<artifactId>mapface</artifactId>
				<version>1.0</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>mapfacetutorial</finalName>		
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.5</version>
				<configuration>
					<downloadSources>false</downloadSources>
					<downloadJavadocs>false</downloadJavadocs>
					<wtpversion>2.0</wtpversion>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

web.xml

In order to create a working web project, you need a valid web.xml. Below is a working example for this project. This file needs to be placed in the src/main/webapp/WEB-INF folder.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<!-- Richfaces -->
	<context-param>
		<param-name>org.richfaces.SKIN</param-name>
		<param-value>DEFAULT</param-value>
	</context-param>
	<!-- Making the RichFaces skin spread to standard HTML controls -->
	<context-param>
		<param-name>org.richfaces.CONTROL_SKINNING</param-name>
		<param-value>enable</param-value>
	</context-param>
	<context-param>
		<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
		<param-value>com.sun.facelets.FaceletViewHandler</param-value>
	</context-param>
	<filter>
		<display-name>RichFaces Filter</display-name>
		<filter-name>richfaces</filter-name>
		<filter-class>org.ajax4jsf.Filter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>richfaces</filter-name>
		<servlet-name>Faces Servlet</servlet-name>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>INCLUDE</dispatcher>
	</filter-mapping>

	<!-- Faces Servlet -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>
	<!-- JSF parameters -->
	<context-param>
		<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
		<param-value>.xhtml</param-value>
	</context-param>
	<context-param>
		<param-name>facelets.DEVELOPMENT</param-name>
		<param-value>true</param-value>
	</context-param>
	<security-constraint>
		<display-name>Restrict raw XHTML Documents</display-name>
		<web-resource-collection>
			<web-resource-name>XHTML</web-resource-name>
			<url-pattern>*.xhtml</url-pattern>
		</web-resource-collection>
		<auth-constraint />
	</security-constraint>
	<session-config>
		<session-timeout>10</session-timeout>
	</session-config>
</web-app>

faces-config.xml

Because we use JSF and Facelets, we need a faces-config.xml which is placed in the same folder as the web.xml, e.g. src/main/webapp/WEB-INF.

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    <application>
        <message-bundle>messages</message-bundle>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>en</supported-locale>
        </locale-config>
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    </application>
</faces-config>

Import the project in your IDE

In our example, we used Eclipse, but feel free to use any IDE you like. To create an eclipse-project, run the following command:

mvn eclipse:eclipse

Now your are ready to start with the web pages and the java code.

Import the project in your IDE

Once you have imported the project into your IDE, you can start with creating the domain model and some service/DAO (data access object) classes. In our example, we used three classes (see below for the code):

  • com.realdolmen.sf.mapface.tutorial.domain.Office
  • com.realdolmen.sf.mapface.tutorial.dao.OfficeDaoImpl
  • com.realdolmen.sf.mapface.tutorial.service.OfficeServiceImpl

We haven't used any database in this example, just to keep it simple.

Java code

Office.java
package com.realdolmen.sf.mapface.tutorial.domain;

public class Office {

	private Long id;

	private String name;

	private String street;

	private String houseNumber;

	private String postalCode;

	private String city;
	 
	private String country;

	private Double latitude;

	private Double longitude;
	
	private final String iconLink = "img/RDMarker.png";

	public Office() {
	};

	public Office(Long id, String name, String street, String houseNumber,
			String postalCode, String city ,String country,Double latitude, Double longitude) {
		super();
		this.id = id;
		this.name = name;
		this.street = street;
		this.houseNumber = houseNumber;
		this.postalCode = postalCode;
		this.city = city;
		this.latitude = latitude;
		this.longitude = longitude;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getHouseNumber() {
		return houseNumber;
	}

	public void setHouseNumber(String houseNumber) {
		this.houseNumber = houseNumber;
	}

	public String getPostalCode() {
		return postalCode;
	}

	public void setPostalCode(String postalCode) {
		this.postalCode = postalCode;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public Double getLatitude() {
		return latitude;
	}

	public void setLatitude(Double latitude) {
		this.latitude = latitude;
	}

	public Double getLongitude() {
		return longitude;
	}

	public void setLongitude(Double longitude) {
		this.longitude = longitude;
	}
	
	public String getCountry(){
		return this.country;
	}
	
	public void setCountry(String country){
		this.country = country;
	}
	
	public String getInfoWindowText(){
		StringBuffer sb = new StringBuffer();
		sb.append("<b>" + name + "</b><br />");
		sb.append(street + " " + houseNumber + "<br />");
		sb.append(postalCode + " " + city + "<br />");
		return sb.toString();
	}
	
	public String getSearchValue(){
		StringBuffer sb = new StringBuffer();
		sb.append(name);
		sb.append(" ");
		sb.append(city);
		return sb.toString();
	}

	public String getIconLink() {
		return iconLink;
	}	
}
OfficeDaoImpl
package com.realdolmen.sf.mapface.tutorial.dao;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.realdolmen.sf.mapface.tutorial.domain.Office;

public class OfficeDaoImpl implements OfficeDao {

	@Override
	public List<Office> findAllOffices() {
		List<Office> offices = new ArrayList<Office>();
		Office office1 = new Office(1L, "Headquarters Huizingen",
				"A. Vaucampslaan", "42", "1654", "Huizingen", "Belgium",
				50.7520688, 4.2634274);
		Office office2 = new Office(2L, "Office Kontich Boudewijnlaan",
				"Prins Boudewijnlaan", "26", "2550", "Kontich", "Belgium",
				51.1410521, 4.4378872);
		Office office3 = new Office(3L, "Office Brussel", "Bruidstraat", "11",
				"1000", "Brussel", "Belgium", 50.8470177, 4.352505);
		Office office4 = new Office(4L, "Office De Pinte", "Grote Steenweg",
				"15", "9840", "De Pinte", "Belgium", 50.9955609, 3.6847499);
		Office office5 = new Office(5L, "Office Harelbeke",
				"Kortrijksesteenweg", "307", "8530", "Harelbeke", "Belgium",
				50.8430976, 3.2920447);
		Office office6 = new Office(6L, "Office Houthalen", "Centrum-Zuid",
				"1527", "3530", "Houthalen", "Belgium", 51.019571, 5.3599932);
		Office office7 = new Office(7L, "Office Axias", "Prins Boudewijnlaan",
				"24", "2550", "Kontich", "Belgium", 51.1401392, 4.4382415);
		Office office8 = new Office(8L, "Office Kontich Veldkant", "Veldkant",
				"33", "2550", "Kontich", "Belgium", 51.1414364, 4.441827);
		Office office9 = new Office(9L, "Office Luxemburg", "Rue d'Eich",
				"33", "1461", "Luxemburg", "Luxemburg", 49.6295829, 6.1318144);
		Office office10 = new Office(10L, "Office Namen", "Rue de Gembloux",
				"9", "5080", "Rhisnes", "Belgium", 50.4985411, 4.7978059);
		Office office11 = new Office(11L, "Office Turnhout", "Steenweg op Mol",
				"148", "2360", "Oud-Turnhout", "Belgium", 51.3125503, 4.9956365);
		Office office12 = new Office(12L, "Office Zaventem",
				"Leuvensesteenweg", "542", "1930", "Zaventem", "Belgium",
				50.8749381, 4.4923216);
		Office office13 = new Office(13L, "Office Frankrijk - Airial",
				"Rue Bellini", "3", "92806", "Puteaux", "France", 48.8860766,
				2.2504484);
		Office office14 = new Office(14L, "Office Frankrijk - Oriam",
				"Parvis de Saint-Maur", "8", "94106", "Saint-Maur", "France",
				48.806489, 2.4725422);
		Collections.addAll(offices, office1, office2, office3, office4,
				office5, office6, office7, office8, office9, office10,
				office11, office12, office13, office14);
		return offices;
	}

}
OfficeServiceImpl
package com.realdolmen.sf.mapface.tutorial.service;

import java.util.List;

import com.realdolmen.sf.mapface.tutorial.dao.OfficeDaoImpl;
import com.realdolmen.sf.mapface.tutorial.domain.Office;

public class OfficeServiceImpl implements OfficeService {

	@Override
	public List<Office> getAllOffices() {
		return new OfficeDaoImpl().findAllOffices();
	}
}

Adding the service class to the faces-config.xml

We need to register the OfficeServiceImpl class as a backing bean, in order for our application to work. This is how our faces-config looks now:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    <application>
        <message-bundle>messages</message-bundle>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>en</supported-locale>
        </locale-config>
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    </application>
    <managed-bean>
    	<managed-bean-name>officeService</managed-bean-name>
    	<managed-bean-class>com.realdolmen.sf.mapface.tutorial.service.OfficeServiceImpl</managed-bean-class>
    	<managed-bean-scope>request</managed-bean-scope>
    </managed-bean>
</faces-config>

Creating the web pages

Now we are ready to create the front-end of the application. First of all, create a folder named template inside the webapp folder. Inside this folder create a file names template.xhtml, this will be our template for the webpages.

template.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
	<head>
		<title>MapFace tutorial</title>
		<link href="css/style.css" rel="stylesheet" type="text/css" />
	</head>
	<body>
		<div id="container">
			<div id="bodyContent">
				<ui:insert name="content">Content</ui:insert>
			</div>
		</div>
	</body>
</html>

Next is the index.jsp file, which is placed under src/main/webapp. This file doesn't contain much, just a single line to redirect the user to the map.

index.jsp
<% response.sendRedirect("map.html"); %>

Finally, we are going to create the page containing the Google Map. (For the images and CSS styles used, please download the project sources).

map.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:rd="http://www.realdolmen.com/mapface"
	xmlns:rich="http://richfaces.org/rich"
	template="./template/template.xhtml">
	<ui:define name="content">
		<div id="leftPanel">
			<rich:tabPanel width="100%" height="100%" switchType="client">
				<rich:tab label="Search">
					<rd:searchPanel id="searchPanel" />
				</rich:tab>
				<rich:tab label="Routeplannner">
					<rd:directionsPanel id="directionsPanel" />
				</rich:tab>
			</rich:tabPanel>
		</div>
		<div id="mapPanel">
			<rd:map mapId="map_canvas" width="100%"	height="100%" key="abcdefg" showDirections="true" 
				search="true" autoCenter="true" mapControl="largeMap3D" scrollWheelZoom="true"
				overviewMap="true" scaleControl="true">
				<rd:clusterer gridSize="16" minMarkersPerCluster="3" maxVisibleMarkers="13">
					<rd:clusterIcon iconLink="img/cluster.png"
						shadowLink="img/shadow_cluster.png" iconWidth="28" iconHeight="46" 
						shadowWidth="51" shadowHeight="46" iconAnchorX="12" iconAnchorY="30" 
						infoWindowAnchorX="12" infoWindowAnchorY="3" infoShadowAnchorX="24" infoShadowAnchorY="34" />
				</rd:clusterer>
			<rd:mapTypeControl useMenu="true" normalMap="true" satelliteMap="true" 
				hybridMap="true" physicalMap="true" />
			<ui:repeat value="#{officeService.allOffices}" var="office">
				<rd:marker id="marker#{office.id}" name="#{office.name}"
					address="#{office.street} #{office.houseNumber}" city="#{office.postalCode} #{office.city}"
					latitude="#{office.latitude}" longitude="#{office.longitude}"
					searchValue="#{office.searchValue}" iconLink="#{office.iconLink}">
					<rd:infoWindow for="marker#{office.id}"	text="#{office.infoWindowText}" />
				</rd:marker>
			</ui:repeat>
		</rd:map>
		</div>
	</ui:define>
</ui:composition>

That's it. All you have to do now is deploy your application and browse to it. Have fun!