This documents summarizes the content of a lecture I held at TU Dresden in support of the Sofware Engineering Lab. It’s primary goal is to ramp up the students with the very basics of Java web application development.

Introduction

The fundamental goals of the lecture are:

  • Learn how to create, setup and run a Spring-based Java web application.

  • How to control the build and project dependencies using Maven.

  • How to build Spring and Spring MVC based web applications.

The lecture content is three-fold: we’re going to start by looking at the infrastructure prerequisites so that everyone is aware of what’s going to be needed to follow the practical examples. Based on that we’re going to walk through a quick start guide to give students a general idea of how to set up a new Spring (Boot) based Java web project. At this point we’re not going to go into details but just see it working.

We’re also going to have a look into details of Maven and the way it does dependency management as students will probably use other libraries than presented in the sample application and should also be able to set up a command line build (e.g for continuous integration).

Once that’s done we’re exploring more fundamental concepts when working with a Spring application, it’s core concepts to understand what the Guestbook sample application[1] consistes of. We’re then going to cover aspects of Spring Data JPA to implement persistence and Spring MVC for the web layer.

To round things off, we’re briefly discussing continuous integration to make sure the tests introduced in previous sections are continuously executed.

The source document for this script can be found in this GitHub repository. Feel free to create tickets for improvements or provide patches via pull requests.

1. Infrastructure prerequisites

  • JDK → current version 8 (Download SDK)

  • Maven (optional) → to execute the build at the command line (for continuous integration, release builds) (Download)

  • STS → IDE, Spring flavored Eclipse[2], a standard Eclipse will do as well, but lacks some Spring-related support (Download)

  • Git → version control (Download)

2. A Java web application — Quick start

2.1. Objectives

  • Learn how to create, setup and run a Java based web project

  • Learn how to handle a web request

  • Learn how to efficiently work with web related code

2.2. Create a new project

IDE centric style
  1. Start STS.

  2. Create a new project File ▸ New… ▸ Other (or +N).

  3. Select "Spring Starter Project".

  4. Keep settings (details on that below).

  5. Select "Web" in the Dependencies matrix.

  6. Select Finish.

Manual version
  1. Browse to http://start.spring.io.

  2. Keep settings (details on them below).

  3. Select "Web" in the Dependencies matrix.

  4. Select Generate project.

  5. Open up your IDE.

  6. In Eclipse select File ▸ Import….

  7. Select "Existing Maven Projects".

The result

The result should be a Java project created in the IDE looking something like this:

project

What do we have here?

  • Application.java in src/main/java - The main (startable) application class.

  • static / templates folders in src/main/resources - Folders for static resources and view templates.

  • application.properties - Configuration file.

  • ApplicationTests.java - Integration test to test the application.

  • pom.xml - The POM (Project Object Model). A Maven configuration file to control project setup, build and dependencies.

2.3. Add minimal functionality and run this thing

  • Create a new class, e.g. in the demo package: Select src/main/java, press ++N, type Class or select File ▸ New… ▸ Class to bring up the new class wizard. Enter demo for the package name, WelcomeController as type name. Edit the created class to look like this:

    Example 1. A simple Spring MVC controller
    @RestController (1)
    class WelcomeController {
    
      @RequestMapping("/welcome") (2)
      String welcome() {
        return "Welcome"; (3)
      }
    }
    1 Causes the class to be found by the Spring container and turned into a Spring bean. This is not directly caused by @RestController but the annotation being meta-annotated with @Controller which is in turn annotated with @Component. See more on that in Fundamental building blocks of a Spring Boot application.
    2 Maps /welcome to the execution of the annotated method. All HTTP request to that URI will cause the method to be invoked.
    3 The result to be written to the response. Using @RestController causes the String returned to be considered the response payload.

When pasting this code into your IDE it might already import the right types for you. In case it doesn’t and you see red underlines e.g. under @RestController you have a variety of options:

  • Navigate to right after @RestController and hit +Space. This will trigger code completion suggestions and either provide you with a drop down list to choose the type from (in case multiple ones matching what you typed are on the classpath).

  • Alternatively try ++O (Organize imports), which should try to resolve the type tokens you used.

  • Execute Application.java (++X,J or right click the class, Run As ▸ Java Application).

  • Browse to http://localhost:8080/welcome, should give you Welcome.

Try using +Space while typing here and there. Eclipse will usually provide you quite useful suggestions for code completion.

2.4. Make this a bit more dynamic

If you run the application in debug mode, you can change method bodies on the fly without having to restart the app. We’re going to use that mode going forward.
  • Change the method signature of the controller method to this:

    welcome(@RequestParam(value = "name") Optional<String> name)
  • Restart the application in debug mode (++D,J or Debug As ▸ Java Application).

  • Browse to http://localhost:8080/welcome, output should be unchanged.

  • Change the URI to http://localhost:8080/welcome?name=Java, doesn’t have any effect yet.

  • While the application is running, change the method body to:

    return "Welcome ".concat(name.orElse("World")).concat("!");
  • Refresh the browser tab and the response should now adapt to changes of the name attribute.

3. Project dependencies and project build

3.1. Maven

  • Open source project to build Java applications

  • Command line execution and IDE integration (to see the output of Maven related IDE activities in the console view, open up the Maven console by clicking the icon with the plus in the upper right).

    maven console
  • pom.xml as the central build configuration file

    Example 2. A sample pom.xml
    <?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/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>org.test</groupId> (1)
      <artifactId>demo</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging> (2)
    
      <name>java-web-sample</name>
      <description>Demo project for Spring Boot</description>
    
      <parent> (3)
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.8.RELEASE</version>
        <relativePath/>
      </parent>
    
      <properties> (4)
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <start-class>demo.Application</start-class>
      </properties>
    
      <dependencies> (5)
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.hsqldb</groupId>
          <artifactId>hsqldb</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>
    
      </dependencies>
    
      <build> (6)
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    
    </project>
    1 Project coordinates: group identifier, artifact identifier, version.
    2 Project packaging: reasonable values for web applications are jar (packaging as a so called fat-JAR) or war (deployable into an application server).
    3 Parent POM declaration (optional): we’re using a Spring Boot parent pom here to benefit from predefined plugin declarations, version declarations for dependencies etc.
    4 Properties to customize general project setup.
    5 Project dependencies: libraries or sets of libraries the project will work with.
    6 Build plugins: plugins to customize the build behavior. In this case we’re using the Spring Boot Maven plugin to let the build result in an executable JAR file.
  • 3 main goals: general project setup, dependency management, execute build.

General project setup
  • Open pom.xml

  • Alter the property for the Java version (java.version) to 1.8.

Some changes (such as this one) need manual project refresh in Eclipse (+F5 or right-click the project, select Maven ▸ Update Project…).

3.2. Project build

  • The project build includes a certain set of steps, called lifecycle phases.

  • The most important ones are source compilation (both sources and test sources), test execution and application packaging.

  • Maven defines a standard folder structure so that it’s easier to find things:

    • src/main/java - Production code.

    • src/main/resources - Production configuration files and resources.

    • src/test/java - Test code, tests to be executed have to be named …Tests.

    • src/test/resources - Test configuration files and resources.

  • To see that in action, simply call mvn clean package on the command line:

    Example 3. Running a maven build
    Serendipity:java-web-sample olivergierke $ mvn clean package
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building java-web-sample 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ demo ---
    [INFO] Deleting /Users/olivergierke/Documents/workspace/java-web-sample/target
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] Copying 1 resource
    [INFO] Copying 0 resource
    [INFO]
    
    // Compilation
    
    [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 2 source files to /Users/olivergierke/Documents/workspace/java-web-sample/target/classes
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] skip non existing resourceDirectory /Users/olivergierke/Documents/workspace/java-web-sample/src/test/resources
    [INFO]
    [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 1 source file to /Users/olivergierke/Documents/workspace/java-web-sample/target/test-classes
    [INFO]
    
    // Executing tests
    
    [INFO] --- maven-surefire-plugin:2.15:test (default-test) @ demo ---
    [INFO] Surefire report directory: /Users/olivergierke/Documents/workspace/java-web-sample/target/surefire-reports
    …
    Results :
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    // Packaging
    
    [INFO]
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo ---
    [INFO] Building jar: /Users/olivergierke/Documents/workspace/java-web-sample/target/demo-0.0.1-SNAPSHOT.jar
    [INFO]
    [INFO] --- spring-boot-maven-plugin:1.1.8.RELEASE:repackage (default) @ demo ---
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 6.240s
    [INFO] Finished at: Mon Oct 20 15:04:30 CEST 2014
    [INFO] Final Memory: 23M/321M
    [INFO] ------------------------------------------------------------------------
    Serendipity-:java-web-sample olivergierke $

3.3. Dependency management

  • Logical definition of libraries that will be used by the project.

  • Artifact coordinates $groupId:$artifactId:$version.

To see the current list of dependencies unfold the Maven Dependencies node in the project tree in Eclipse. Alternatively run mvn dependency:list -Dsort in on the command line.
  • In the current state the output of the command should look something like this:

    Example 4. Listing dependencies of a Maven project
    Serendipity:java-web-sample olivergierke $ mvn dependency:list -Dsort
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building java-web-sample 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ demo ---
    [INFO]
    [INFO] The following files have been resolved:
    [INFO]    …
    [INFO]    org.springframework.boot:spring-boot-autoconfigure:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-logging:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-test:jar:1.1.8.RELEASE:test
    [INFO]    org.springframework.boot:spring-boot-starter-tomcat:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-web:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework:spring-aop:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-beans:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-context:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-core:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-expression:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-test:jar:4.0.7.RELEASE:test
    [INFO]    org.springframework:spring-web:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-webmvc:jar:4.0.7.RELEASE:compile
    [INFO]    org.yaml:snakeyaml:jar:1.13:runtime
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 0.943s
    [INFO] Finished at: Mon Oct 20 14:57:38 CEST 2014
    [INFO] Final Memory: 15M/309M
    [INFO] ------------------------------------------------------------------------
    Serendipity:java-web-sample olivergierke $
  • To add a new library or a few of them, add a new <dependency /> block to the POM.

  • Currently the <dependencies /> block only contains two starters, the one for web and the one for the testing libraries.

  • The web one was added due to the checkbox we flagged when setting up the project.

  • This means that we can add additional libraries by declaring the corresponding <dependency /> blocks.

  • Add the starter for JPA:

    Example 5. Declaring a dependency to Spring Boot’s JPA starter
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    Spring Boot will detect the JPA dependencies on the classpath and set up some default configuration for the persistence. Thus, if you try to run the application with that dependency added it will complain about a database missing. For now, add the following additional dependency to keep the application bootstrapable.
    Example 6. Dependeny declaration for the HSQL in-memory database
    <dependency>
      <groupId>org.hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
    </dependency>
  • Re-run mvn dependency:list -Dsort

    Example 7. Listing Maven dependencies
    Serendipity:java-web-sample olivergierke $ mvn dependency:list -Dsort
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building java-web-sample 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ demo ---
    [INFO]
    [INFO] The following files have been resolved:
    [INFO]    …
    [INFO]    org.springframework.boot:spring-boot-autoconfigure:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-aop:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-data-jpa:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-jdbc:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-logging:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-test:jar:1.1.8.RELEASE:test
    [INFO]    org.springframework.boot:spring-boot-starter-tomcat:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter-web:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot-starter:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.boot:spring-boot:jar:1.1.8.RELEASE:compile
    [INFO]    org.springframework.data:spring-data-commons:jar:1.8.4.RELEASE:compile
    [INFO]    org.springframework.data:spring-data-jpa:jar:1.6.4.RELEASE:compile
    [INFO]    org.springframework:spring-aop:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-aspects:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-beans:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-context:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-core:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-expression:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-jdbc:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-orm:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-test:jar:4.0.7.RELEASE:test
    [INFO]    org.springframework:spring-tx:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-web:jar:4.0.7.RELEASE:compile
    [INFO]    org.springframework:spring-webmvc:jar:4.0.7.RELEASE:compile
    [INFO]    org.yaml:snakeyaml:jar:1.13:runtime
    [INFO]    xml-apis:xml-apis:jar:1.0.b2:compile
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 1.007s
    [INFO] Finished at: Mon Oct 20 15:10:35 CEST 2014
    [INFO] Final Memory: 16M/309M
    [INFO] ------------------------------------------------------------------------
    Serendipity:java-web-sample olivergierke $
  • Note, how the list of dependencies changed and an entire set of new dependencies has been added due to the declaration of that single logical dependency.

  • Spring Boot takes care of providing a consistent set of dependencies for fundamental application aspects. Also, it takes away the need to declare version numbers for those dependencies to make sure they work with each other.

4. Spring — An application framework

The Spring Framework [3] is an open-source, general purpose, Java-based application framework. Parts of it can be used as a library but at the very core of it it’s an inversion-of-control[4] container which allows you to write easy to test application components.

Beyond that it provides means to apply technical services (e.g. transactions and security) in a declarative and portable way, integrations with persistence and integration technologies as well as an MVC web framework.

As a developer you usually use Spring Framework through Spring Boot, which is an opinionated add-on to automatically configure and ease the set up of a Spring based application so that you can focus on your business code[5].

4.1. Inversion of Control

Inversion of Control (otherwise also referred to as Dependency Injection) is the software design technique that frees a component from the task to look up its collaborators and rather get those handed into the component – usually as constructor arguments. This inverts the control of this lookup from the component itself to its context (hence the name). The assembly of a component is externalized and usually taken care of by a generic framework but can — and almost always is — also be used manually e.g. in test cases.

This approach especially improves testability of components as the collaborators that would be used in a production environment can easily be replaced with test components.

4.2. Fundamental building blocks of a Spring Boot application

  • Application code — code you write, e.g. the WelcomeController in the quick start example.

  • Configuration — code to configure the application container. Declares references to infrastructure components (e.g. the database, security) and defines how application components are found:

    Example 8. An example configuration class
    @SpringBootApplication
    class Application {
    
      public static void main(String... args) {
        SpringApplication.run(Application.class, args);
      }
    }

This is the primary application class (hence the name) and uses SpringApplication.run(…) in the main method to start a Spring ApplicationContext and inspect the given configuration, the Application class itself in this case.

The @SpringBootApplication is the annotation to enable very fundamental features of Spring boot. It actually acts like a combination of the following three annotations:

  • @Configuration — Declares the class to contain configuration. This will cause the container to detect methods annotated with @Bean for you to provide custom components manually.

  • @EnableAutoConfiguration — Enables Spring Boot’s auto-configuration features to activate features based on your classpath setup.

  • @ComponentScan — Activates the detection of Spring components for the package of the annotated class.

Thus, using the single annotation, all of these features get activated at application startup.

4.3. Running a Spring Boot application

The application containing a main method, makes it very easy to start it from within the IDE as the class itself becomes executable. That’s very convenient during development. However, there are a couple of more ways we might want to execute the application: packaged into an executable, so that we can actually run it on a production server, and during integration test execution to verify its behavior.

4.3.1. Standalone

  • On the command line, run mvn clean package and run the JAR (Java application ARchive) using java -jar target/*.jar. You can basically take the JAR created by the build and run that on any machine that has Java installed.

Don’t be trapped by trying to use your IDE’s JAR export mechanism. It’s crucial for the application to work as a standalone JAR to be built using the the actual build mechanism, which applies the necessary plugins to make the JAR bootable.

4.3.2. In integration tests

  • One of the most common ways of executing Test cases is with an open-source library called JUnit which has both Maven and Eclipse integration.

  • To bootstrap the application container in an integration test the test class has to look as follows:

    Example 9. Bootstrapping the Spring container from an integration test
    @SpringBootTest
    @RunWith(SpringRunner.class)
    class ApplicationTests { … }
  • @SpringBootTest expresses Boot to be used during tests. The main configuration class will be auto-detected looking for a class with an @SpringBootApplication in the current package and all above.

  • @RunWith(…) tells JUnit to give Spring Framework the control over the test execution.

4.4. Application components

Application components are usually identified by an annotation that is either @Component or an annotation which is annotated with @Component in turn (e.g. @Service, @Repository, @Controller). The component classes are discovered at bootstrap time and a single instance is created.

+ .A simple application component

@Component
class MyApplicationComponent {}

If a component needs other components to work with (e.g. the web controller needs access to the component implementing data access), the component required can be injected into the depending component by declaring a constructor taking a dependency of the necessary type.

Example 10. A simple component with a dependency
@Component
class MyDependingComponent {

  private final MyApplicationComponent dependency;

  public MyDependingComponent(MyApplicationComponent dependency) {
    this.dependency = dependency;
  }
}

If a component depended on cannot be found in the container, an exception is thrown:

Example 11. A Spring exception indicating a component cannot be found
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [demo.MyApplicationComponent] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
  at o.s.b.f.s.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(…:1118)
  at o.s.b.f.s.DefaultListableBeanFactory.doResolveDependency(…:967)
  at o.s.b.f.s.DefaultListableBeanFactory.resolveDependency(…:862)
  at o.s.b.f.s.ConstructorResolver.resolveAutowiredArgument(…:811)
  at o.s.b.f.s.ConstructorResolver.createArgumentArray(…:739)
  ... 42 common frames omitted

When using STS, classes that are Spring components carry a little S-overlay on the icon:

sts components

4.5. Data access with Spring and JPA

4.5.1. Fundamentals of Java persistence

  • Most commonly used type of persistent stores these days are relational databases.

  • JPA[6] is a standard to define the aspects of mapping Java objects to relational database and how to store into the database and retrieve objects from it in turn.

  • Most fundamental concepts are entities and repositories:[7]

    • Entity - a domain concept with identity and a certain lifecycle (can be created, updated, deleted etc.).

    • Repository - an application component simulating a collection of aggregate roots (a special kind of entity). Usually backed by some persistence mechanism.

4.5.2. Entity mapping

  • Entity ytpes are equipped with JPA annotations to customize the mapping to the database, declaring ids etc.

    Example 12. A sample JPA entity type
    @Entity
    public class GuestbookEntry {
    
      @Id
      @GeneratedValue
      private Long id;
      private String name, text;
      private Date date;
    
      …
    }

4.5.3. Spring Data JPA

  • Defines a programming model to ease the implementation of repositories.

  • Support for CRUD[8] operations, query methods, predicate executions.

    Example 13. A sample repository interfac
    interface Guestbook extends CrudRepository<GuestbookEntry, Long> {
    
      List<GuestbookEntry> findByName(String name);
    }
  • Interfaces are automatically detected by Spring Boot and can be @Autowired into clients.

  • CRUD operations available through CrudRepository.

  • Query methods follow a naming convention (see the reference documentation for details).

Writing test cases
  • Create an integration test class (see the section on testing for fundamentals).

  • Mark the test class with @Transactional to automatically roll back changes in the database after each test method.

  • Set up sample data in an @Before method (will be executed for each test method execution).

  • Autowire the repository into the test case and call methods on it.

    Example 14. A sample integration test for a repository
    import static org.hamcrest.CoreMatchers.*;
    import static org.junit.Assert.*;
    
    …
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @Transactional
    public class GuestbookIntegrationTest {
    
      @Autowired Guestbook repository;
    
      @Test
      public void persistsGuestbookEntry() {
    
        GuestbookEntry entry = new GuestbookEntry("Yoda", "May the source be with you!");
        repository.save(entry);
    
        assertThat(repository.findAll(), hasItem(entry));
      }
    }

4.6. Spring MVC

4.6.1. MVC fundamentals

  • Architectural pattern to implement user interfaces.[9]

4.6.2. Spring MVC controllers

  • A controller is the central concept within Spring MVC. Accepts requests, delegates to business logic and returns either a view name and model or an object to be marshalled as e.g. JSON or XML.

    Example 15. A sample Spring MVC controller
    @Controller (1)
    class GuestbookController {
    
      @RequestMapping( (2)
        value = "/guestbook", method = RequestMethod.POST, headers = IS_AJAX_HEADER)
      String addEntry( (3)
        @RequestParam("name") String name, @RequestParam("text") String text, Model model) {
    
        model.addAttribute("entry", …); (4)
        model.addAttribute("index", …);
        return …;
      }
    
      @RequestMapping(value = "/guestbook/{id}", method = RequestMethod.DELETE)
      String removeEntry(@PathVariable Long id) { … }
    }
    1 Declares the class as a controller (so that Spring MVC picks it up).
    2 @RequestMapping allows to bind requests (via path, HTTP method, headers etc.) to method executions.
    3 Annotations on method parameters allow to bind aspects of the request to the method execution: @RequestParam, @PathVariable. Some types are supported without annotations (see the reference documentation for details).
  • Controller methods return value depends on mode of operation:

    • REST web service (you want to server JSON/XML): return a domain object, either annotate method with @ResponseBody or the controller with @RestController.

    • A website (through a template engine): return a String and thus trigger view resolution (see next section).

4.6.3. Natural view templates with Thymeleaf

  • Thymeleaf is the state-of-the art template engine to render HTML views.

  • Supports so called natural templating, i.e. the template is a valid (and viewable) HTML page that contains directives that trigger content replacement on rendering.

  • Sample view in the Guestbook project: guestbook.html.

  • Supports partial rendering by using a special view name syntax: $viewName :: $fragmentName (see the th:fragment="entry" in the guestbook template).

5. Continuous integration with Travis

  • Create account at Travis (it’s free!).

  • Look up your repository and activate the CI job.

  • Add a .travis.yml file to the root of your project with the following content:

    Example 16. A sample .travis.yml file to configure a Java build CI job
    language: java
    jdk:
      - oraclejdk8
  • Push that change to the repository and watch Travis kicking off a build of your project.

Appendix

Appendix B: General best practices

Create work items (tickets) and reference the item from the commit message

This will allow you to trace which code has been written and changed for what reason.

Don’t check in untested code

Writing test cases will not only reduce the number of bugs you introduce while writing the code. It also will help you design the code so that it’s easy to use as it’s effectively the first client you write for your production code. Beyond that, test cases help you to be able to change your code and immediately see if your changes broke existing functionality.

Run the build before you push your changes to the server

It’s considered good practice to not break the build as you might block your team mates, if they update the code and all of a sudden cannot bootstrap the container anymore. Even better, set up continuous integration as described in Continuous integration with Travis.

Appendix D: License

88x31

1. Guestbook sample application — GitHub repository
2. Eclipse — Project website
3. Spring - Wikipedia
4. Inversion of Control - Wikipedia
5. Philosophies that Shaped Successful Frameworks - Blog post
6. Java Persistence API (JPA) - Wikipedia
7. Domain Driven Design (DDD) — Wikipedia
8. Create, Read, Update, Delete (CRUD) — Wikipedia
9. Model View Controller (MVC) Pattern — Wikipedia