lishman levelup
«previous  next»


Getting Started
Form Processing
IoC Container
Hibernate ORM



Spring IoC Container Quick Start


Get up and running with Spring autowiring and component scanning.

Follow the instructions below and the application structure should look like this:

Application Structure for Spring Web MVC

1. Download

Download and install the Spring Framework.

2. Country.java

Create the Country class. This is the same file as the one created in Spring MVC Forms Quick Start.
package levelup.world.domain;

import java.util.Date;

public class Country {

  private Integer id;
  private String name;
  private Integer area;
  private Long population;
  private Date populationLastUpdated;
  private String currency;

  public Country () {}

  public Country (Integer id,
                  String name,
                  Integer area,
                  Long population,
                  Date populationLastUpdated,
                  String currency) {
    setId(id);
    setName(name);
    setArea(area);
    setPopulation(population);
    setPopulationLastUpdated(populationLastUpdated);
    setCurrency(currency);
  }

  public boolean isNew() {
    return id==null;
  }

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

  public Integer getId() {
    return id;
  }

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

  public String getName() {
    return name;
  }

  public void setArea(Integer area) {
    this.area = area;
  }

  public Integer getArea() {
    return area;
  }

  public void setPopulation(Long population) {
    this.population = population;
  }

  public Long getPopulation() {
    return population;
  }

  public void setPopulationLastUpdated(Date populationLastUpdated) {
    this.populationLastUpdated = populationLastUpdated;
  }

  public Date getPopulationLastUpdated() {
    return populationLastUpdated;
  }

  public void setCurrency(String currency) {
    this.currency = currency;
  }

  public String getCurrency() {
    return currency;
  }

}

3. WorldService.java

Create the WorldService interface. This is the same file as the one created in Spring MVC Forms Quick Start.
package levelup.world.domain.service;

import java.util.Collection;
import levelup.world.domain.Country;

public interface WorldService {

  public Collection<Country> getAllCountries();

  public Country getCountryById(int countryId);

  public Country getCountryByName(String countryName);

  public void saveCountry(Country country);

  public void deleteCountry(Country country);

}

4. MockWorldService.java

Create the MockWorldService class.
package levelup.world.domain.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import levelup.world.domain.Country;

import org.springframework.stereotype.Service;


@Service
public class MockWorldService implements WorldService {

  private static Map<Integer, Country> countries = new HashMap<Integer, Country>();
  private static int nextCountryId = 200;

  static {
    countries.put(14,   new Country(14,   "Germany",      137847,   82046000L,  parseDate("30-nov-2008"),   "Euro"));
    countries.put(48,   new Country(48,   "Ghana",        92098,    23837000L,  null,                       "Cedi"));
    countries.put(53,   new Country(53,   "Australia",    2966200,  21884000L,  parseDate("04-sep-2009"),   "Australian Dollar"));
    countries.put(73,   new Country(73,   "Greece",       50949,    11257285L,  parseDate("1-jan-2009"),    "Euro"));
    countries.put(122,  new Country(122,  "Georgia",      26900,    4382100L,   parseDate("1-jan-2009"),    "Lari"));
    countries.put(123,  new Country(123,  "New Zealand",  104454,   4320300L,   parseDate("4-sep-2009"),    "New Zealand Dollar"));
    countries.put(147,  new Country(147,  "Gambia",       4361,     1705000L,   null,                       "Dalasi"));
    countries.put(149,  new Country(149,  "Gabon",        103347,   1475000L,   null,                       "CFA franc"));
  }

  private static Date parseDate(String textDate) {
    try {
      return new SimpleDateFormat("dd-MMM-yyyy").parse(textDate);
    } catch (ParseException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
  }

  public Collection<Country> getAllCountries() {
    return countries.values();
  }

  public Country getCountryById(int countryId) {
    // Returns a new object and not just a reference
    // to an object in the collection.
    Country country = countries.get(countryId);
    return new Country(country.getId(),
                       country.getName(),
                       country.getArea(),
                       country.getPopulation(),
                       country.getPopulationLastUpdated(),
                       country.getCurrency());
  }

  public Country getCountryByName(String countryName) {
    for (Country country : countries.values()) {
      if (country.getName().toLowerCase().equals(countryName.toLowerCase())) {
        return country;
      }
    }
    return null;
  }

  public void saveCountry(Country country) {
    if (country.isNew()) {
      nextCountryId++;
      country.setId(nextCountryId);
      countries.put(nextCountryId, country);
    } else {
      countries.put(country.getId(), country);
    }
  }

  public void deleteCountry(Country country) {
    countries.remove(country.getId());
  }

}

5. CountryController.java

Create the CountryController class.
package levelup.world.web;

import java.util.Collection;

import levelup.world.domain.Country;
import levelup.world.domain.service.WorldService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;


@Controller
public class CountryController {

  @Autowired
  private WorldService worldService;

  @RequestMapping("/countryList.html")
  @ModelAttribute("countries")
  public Collection<Country> getCountries() {
    return worldService.getAllCountries();
  }

  @RequestMapping("/countryDetails.html")
  public Country getCountry(@RequestParam(value="id", required=true) int countryId) {
    return worldService.getCountryById(countryId);
  }

}

6. CountryValidator.java

Create the CountryValidator class.
package levelup.world.domain.validation;

import levelup.world.domain.Country;
import levelup.world.domain.service.WorldService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;


@Component
public class CountryValidator {

  @Autowired
  private WorldService worldService;

  public void validate(Country country, Errors errors) {

    if (country.getArea() != null && country.getArea() <= 0) {
      errors.rejectValue("area", "validation.negative", "must be > 0");
    }

    if (country.getPopulation() != null && country.getPopulation() <= 0) {
      errors.rejectValue("population", "validation.negative", "must be > 0");
    }

    if (!errors.hasFieldErrors("name")) {
      Country existingCountry = worldService.getCountryByName(country.getName());
      if (existingCountry != null &&
          (country.isNew() || !country.getId().equals(existingCountry.getId()))) {
        errors.rejectValue("name", "validation.exists", "exists");
      }
    }
  }

}

7. CountryForm.java

Create the CountryForm class.
package levelup.world.web;

import java.text.SimpleDateFormat;

import java.util.Date;

import levelup.world.domain.Country;
import levelup.world.domain.service.WorldService;
import levelup.world.domain.validation.CountryValidator;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;


@Controller
@RequestMapping("/countryForm.html")
@SessionAttributes("country")
public class CountryForm {

  @Autowired
  private CountryValidator countryValidator;

  @Autowired
  private WorldService worldService;

  @InitBinder
  public void initBinder(WebDataBinder dataBinder) {

    dataBinder.setDisallowedFields(new String[] {"id"});
    dataBinder.setRequiredFields(new String[] {"name", "area", "population", "currency"});
    dataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(false));

    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");
    dateFormat.setLenient(false);
    dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
  }

  @RequestMapping(method = RequestMethod.GET)
  public Country setUpForm(@RequestParam(value="id", required = false) Integer countryId) {
    if (countryId == null) {
      return new Country();
    } else {
      return worldService.getCountryById(countryId);
    }
  }

  @RequestMapping(params = "create", method = RequestMethod.POST)
  public String create(Country country, BindingResult result, SessionStatus status) {
    return update(country, result, status);
  }

  @RequestMapping(params = "update", method = RequestMethod.POST)
  public String update(Country country,
                       BindingResult result,
                       SessionStatus status) {
    countryValidator.validate(country, result);
    if (result.hasErrors()) {
      return "countryForm";
    } else {
      worldService.saveCountry(country);
      status.setComplete();
      return "redirect:countryList.html";
    }
  }

  @RequestMapping(params = "delete", method = RequestMethod.POST)
  public String delete(Country country, BindingResult result, SessionStatus status) {
    worldService.deleteCountry(country);
    status.setComplete();
    return "redirect:countryList.html";
  }

}

8. countryList.jsp

Create the countryList.jsp file. This is the same file as the one created in Spring MVC Forms Quick Start.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<html>
  <head>
    <link rel="stylesheet" href="./css/world.css" type="text/css"/>
    <title>
      <spring:message code="country.plural"/>
    </title>
  </head>
  <body>
    <h1><spring:message code="application.name"/></h1>
    <table>
      <tr>
        <td align="right" valign="bottom">
          <button onclick="window.location='countryForm.html'">Create</button>
        </td>
      </tr>
      <tr>
        <td>
          <table class="silver" width="180">
            <tr>
              <th> </th>
              <th><spring:message code="country.plural"/></th>
            </tr>
            <c:forEach items="${countries}" var="country">
              <tr>
                <td width="20">
                  <a href="<c:url value='countryForm.html?id=${country.id}'/>">
                    <img src="images/edit.gif" style="border-style:none;"/>
                  </a>
                </td>
                <td>
                  <a href="countryDetails.html?id=${country.id}">
                    ${country.name}
                  </a>
                </td>
              </tr>
            </c:forEach>
          </table>
        </td>
      </tr>
    </table>
  </body>
</html>

9. countryDetails.jsp

Create the countryDetails.jsp file. This is the same file as the one created in Spring MVC Forms Quick Start.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<html>
  <head>
    <link rel="stylesheet" href="./css/world.css" type="text/css"/>
    <title>
      <spring:message code="country.details"/>
    </title>
  </head>
  <body>
    <h1><spring:message code="application.name"/></h1>
    <table class="silver" width="260">
      <tr>
        <th colspan=2><spring:message code="country.details"/></th>
      </tr>
      <tr>
        <td><spring:message code="country.name"/></td>
        <td>${country.name}</td>
      </tr>
      <tr>
        <td><spring:message code="country.area"/></td>
        <td><fmt:formatNumber type="number" value="${country.area}" /></td>
      </tr>
      <tr>
        <td><spring:message code="country.population"/></td>
        <td><fmt:formatNumber type="number" value="${country.population}" /></td>
      </tr>
      <tr>
        <td><spring:message code="country.updatedOn"/></td>
        <td><fmt:formatDate value="${country.populationLastUpdated}"/></td>
      </tr>
      <tr>
        <td><spring:message code="country.currency"/></td>
        <td>${country.currency}</td>
      </tr>
    </table>
    <a href="countryList.html">
      &lt;&lt;<spring:message code="navigation.back"/>
    </a>
  </body>
</html>

10. countryForm.jsp

Create the countryForm.jsp file. This is the same file as the one created in Spring MVC Forms Quick Start.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
  <head>
    <link rel="stylesheet" href="./css/world.css" type="text/css"/>
    <title>
      <spring:message code="country.details"/>
    </title>
  </head>
  <body>
    <h1><spring:message code="application.name"/></h1>
    <form:form modelAttribute="country" action="countryForm.html" method="post">
      <table>
         <tr>
          <td align="right" valign="bottom">
            <c:choose>
              <c:when test="${country.new}">
                <button type="submit"
                        name="create">
                  Create
                </button>
              </c:when>
              <c:otherwise>
                <button type="submit"
                        name="delete"
                        onclick="return confirm('Are you sure you want to delete ${country.name}?')">
                  Delete
                </button>
                <button type="submit"
                        name="update">
                  Update
                </button>
              </c:otherwise>
            </c:choose>
          </td>
        </tr>
        <tr>
          <td>
            <table class="silver">
              <tr>
                <th colspan=2><spring:message code="country.details"/></th>
              </tr>
              <tr>
                <td><spring:message code="country.name"/></td>
                <td>
                  <form:input path="name" size="20" maxlength="50" />
                  <form:errors path="name" cssClass="errors"/>
                </td>
              </tr>
              <tr>
                <td><spring:message code="country.area"/></td>
                <td>
                  <form:input path="area" size="8" maxlength="8" />
                  <form:errors path="area" cssClass="errors"/>
                </td>
              </tr>
              <tr>
                <td><spring:message code="country.population"/></td>
                <td>
                  <form:input path="population" size="10" maxlength="10" />
                  <form:errors path="population" cssClass="errors"/>
                </td>
              </tr>
              <tr>
                <td><spring:message code="country.updatedOn"/></td>
                <td>
                  <form:input path="populationLastUpdated" size="12" maxlength="12" />
                  <form:errors path="populationLastUpdated" cssClass="errors"/>
                </td>
              </tr>
              <tr>
                <td><spring:message code="country.currency"/></td>
                <td>
                  <form:input path="currency" size="20" maxlength="50" />
                  <form:errors path="currency" cssClass="errors"/>
                </td>
              </tr>
            </table>
          </td>
        </tr>
      </table>
    </form:form>
    <a href="countryList.html">
      &lt;&lt;<spring:message code="navigation.back"/>
    </a>
  </body>
</html>

11. world.css

Create the world.css file. This is the same file as the one created in Spring MVC Forms Quick Start.
h1 {
  font-family: Verdana, Geneva, sans-serif;
  font-size:1.1em;
  font-weight:normal;
  color:SeaGreen;
  margin: 1em 1em 1em 1em;
}

a {
  color:DarkSlateGray;
  font-weight:normal;
  text-decoration:none;
}

a:hover {
  color:OrangeRed;
  font-weight: normal;
  text-decoration:none;
}

table.silver {
  margin: 0em 0em 1em 2em;
  background: WhiteSmoke;
  border-collapse: collapse;
}

table.silver th {
  color:DarkSlateGray;
  background: Gainsboro;
  text-align: left;
}

table.silver th, table.silver td {
  border: 1px Silver solid;
  padding: 0.2em;
}

.errors {
  color: Red;
  font-weight: bold;
}

12. web.xml

Create the web.xml file.
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <!-- Register a servlet that despatches requests to registered controllers  -->
  <servlet>
    <servlet-name>world</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--  Send all .html files to the Spring dispatcher servlet -->
  <servlet-mapping>
    <servlet-name>world</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

  <!-- Define the web application entry point -->
  <welcome-file-list>
    <welcome-file>countryList.html</welcome-file>
  </welcome-file-list>

</web-app>

13. world-servlet.xml

Create the world-servlet.xml file.
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <!-- Auto-detect controllers -->
  <context:component-scan base-package="levelup.world.web"/>

  <!--  Prepend /WEB-INF/jsp/ and append .jsp to the logical view name  -->
  <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
  </bean>

  <!-- Access resource bundles with the specified basename -->
  <bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
    p:basename="/WEB-INF/messages"/>

</beans>

14. applicationContext.xml

Create the applicationContext.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
      http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

  <!-- Auto-detect components -->
  <context:component-scan base-package="levelup.world.domain"/>

</beans>

15. messages.properties

Create the messages.properties file. This is the same file as the one created in Spring MVC Forms Quick Start.
application.name=hello world

navigation.back=Back

country.plural=Countries
country.details=Country Details
country.name=Name
country.area=Area
country.population=Population
country.updatedOn=Last Updated
country.currency=Currency

required=is required
validation.exists=already exists
validation.negative=must be positive

typeMismatch.java.util.Date=must be a valid date
typeMismatch.java.lang.Integer=must be a valid number
typeMismatch.java.lang.Long=must be a valid number

16. messages_en.properties

Create the messages_en.properties file. This is the same file as the one created in Spring MVC Forms Quick Start.
application.name=hello world

#navigation.back=Back falls back to messages.properties

country.plural=Countries
country.details=Country Details
country.name=Name
country.area=Area
country.population=Population
country.updatedOn=Last Updated
country.currency=Currency

17. messages_fr.properties

Create the messages_fr.properties file. This is the same file as the one created in Spring MVC Forms Quick Start.
application.name=bonjour monde

navigation.back=Retournez

country.plural=Pays
country.details=Détails de pays
country.name=Nom
country.area=Taille
country.population=Population
country.updatedOn=Dernier mis à jour
country.currency=Devise

18. Edit Button

Right click on Edit Image to download the edit button image.


Deploy the application and display the countryList.html page.
»