LDSTechForumProjects

Spring MVC - Part 2

This lesson continues the training begun in Introduction to Spring MVC and is continued in Spring MVC - Part 3.

Other Resources

The SpringOne 2GX 2012 conference had an excellent presentation on designing REST web services.

  • Designing a REST-ful API Using Spring 3 by Ben Hale.
    • Note that while the presenter's training uses Spring MVC for designing REST Web Services, many of the principles, techniques, and best practices discussed in the training apply to all REST service APIs.
    • The presentation also includes valuable information on how you can write functional tests for a REST web service. The Spring APIs the author uses can be used for testing any REST web service, regardless of the technology it was written in.

Notes

Before working on the lab content, there are a few things you'll need:

1. An IDE that you can use with Stack projects. If you are using the LDSTech IDE, you'll need version 1.2.1 or later. You can download the latest version of the LDSTech IDE.

2. Some sort of HTTP client that you can use to make HTTP requests to the application we are building. You'll need to be able to do POSTs and set headers, so a browser by itself won't be sufficient. Probably the best option is to use a browser plugin. I've found two that seem to work reasonably well for Firefox and Chrome:

Outline

  • RESTful features of Spring MVC
    • RequestBody
    • ResponseBody
    • HTTPMessageConverters
  • HttpEntity
  • Dealing with Exceptions
  • Data Binding
    • ConversionService
    • Adding new converters

Slides

Download presentation slides.

Presentation, Part 1

Get Adobe Flash player

Lab #1

In this lab, we'll create several controller handlers to deal with various types of inputs and outputs.

First, we need to create a Stack Project that uses Spring MVC.

1. Create a project with Java Stack Starter, changing the following options:

  1. Give it the name mvc-training (you can give it a different name, but you'll need to adjust future steps accordingly)
  2. Security tab: Uncheck 'Use LDS Account Authentication'
  3. Service Layer tab: Uncheck 'Use a database?'

2. Import your new project into your IDE of choice and associate it with a Tomcat server. If you are unsure about how to do this, see our guides for doing so in Eclipse, IntelliJ, or NetBeans.

3. Create a class called 'RestController' in your org.lds.view package and annotate it with @Controller. We'll use this controller for all of our examples.

4. Create a controller method that takes a String request body and echoes back a String and is available at /echo/string. Test it with your HTTP Client. The solution is below.

@RequestMapping("/echo/string")
public @ResponseBody String echoString(@RequestBody String input) {
	return input;
}

Request Message:

POST /echo/string
Accept: text/plain
Content-Type: text/plain

Hello

5. Create a controller method that takes a JSON request body, creates some object with it, and then returns that object as JSON. Make it available at /person/create. Test it with your HTTP Client. The solution is below.

Model class:

package org.lds.model;

public class Person {

	private String name;
	private int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

Controller method:

@RequestMapping("/person/create")
public @ResponseBody Person createPerson(@RequestBody Person person) {
	return person;
}

Request Message:

POST /person/create
Accept: application/json
Content-Type: application/json

{ "name" : "Spencer", "age" : 29 }

6. Create a controller method that takes XML input and returns JSON. For this, we'll add one annotation to our Person class: @XmlRootElement. Create your controller at /person/echo. Test it with your HTTP Client. The solution is below.

Updated model class:

package org.lds.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Person {

	private String name;
	private int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

Controller method:

@RequestMapping("/person/echo")
public @ResponseBody Person echoPerson(@RequestBody Person person) {
	return person;
}

Request Message:

POST /person/echo
Accept: application/json
Content-Type: application/xml

<person><name>Spencer</name><age>29</age></person>

Solution, Lab 1

Get Adobe Flash player

Presentation, Part 2

Get Adobe Flash player

Lab #2

In this lab, we'll do a few things with HttpEntity objects to get familiar with them.

1. First, convert your String controller HttpEntity instead of @RequestBody/@ResponseBody and use your HTTP Client to make sure it still works like it did before. The solution is below:

Controller method:

@RequestMapping("/echo/string")
public HttpEntity<String> echoString(HttpEntity<String> input) {
	return new ResponseEntity<String>(input.getBody(), HttpStatus.OK);
}

Request Message:

POST /echo/string
Accept: text/plain
Content-Type: text/plain

Hello

2. Now, let's create rewrite the Person Create controller method and set some custom headers and a different response code. The solution is below:

@RequestMapping("/person/create")
public HttpEntity<String> createPerson(HttpEntity<Person> input) {
	Person person = input.getBody();
	
	HttpHeaders headers = new HttpHeaders();
	headers.add("Location", "/person/" + person.getName());
	
	return new ResponseEntity<String>("Created", headers, HttpStatus.CREATED);
}
POST /person/create
Content-Type: application/json
Accept: application/json

{ "name" : "Spencer", "age" : 29 }

Solution, Lab 2

Get Adobe Flash player

Presentation, Part 3

Get Adobe Flash player

Lab #3

In this lab, we'll experiment with some of the exception handling capabilities in Spring MVC.

1. The Stack project you created already has a SimpleMappingExceptionResolver configured. Open up mvc-training-servlet.xml (in src/main/webapp/WEB-INF) and look at it there:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key=".DataAccessException">errors/dataAccessFailure</prop>
			<prop key=".AccessDeniedException">errors/dataAccessFailure</prop>
			<prop key=".TypeMismatchException">errors/resourceNotFound</prop>
			<prop key=".NoSuchRequestHandlingMethodException">errors/resourceNotFound</prop>
			<prop key=".MissingServletRequestParameterException">errors/resourceNotFound</prop>
		</props>
	</property>
	<property name="defaultErrorView" value="errors/generalError"/>
	<property name="warnLogCategory" value="org.lds.stack.petstore"/>
</bean>

2. Throw a MissingServletRequestParameterException, and test it in your browser. You should get a "Resource Not Found" page, per the mappings above. The solution can be found below:

@RequestMapping("/error")
public void doSomething() throws ServletException {
	throw new MissingServletRequestParameterException("name", "string");
}

3. Remove that block of configuration from your Spring MVC config. Change the exception to HttpMediaTypeNotSupportedException. Verify that you get a 415 using your Http Client.

@RequestMapping("/error")
public void doSomething() throws ServletException {
	throw new HttpMediaTypeNotSupportedException("Not acceptable!");
}

4. Implement an @ExceptionHandler method that turns that exception into a different error code. Make sure (using your HTTP client) that you get a different response code. Solution:

@ResponseStatus(value=HttpStatus.PAYMENT_REQUIRED, reason="You owe me money.")
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public void handleError(HttpMediaTypeNotSupportedException ex) {}

Solution, Lab 3

Get Adobe Flash player
This page was last modified on 12 July 2013, at 19:31.

Note: Content found in this wiki may not always reflect official Church information. See Terms of Use.