spring mvc rest

35
Building RESTful applications with Spring MVC Craig Walls

Upload: craig-walls

Post on 26-May-2015

12.028 views

Category:

Documents


1 download

DESCRIPTION

My Spring MVC and REST talk, updated for NFJS Reston, VA.

TRANSCRIPT

Page 1: Spring Mvc Rest

Building RESTful applications with

Spring MVC

Craig Walls

Page 2: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: @habuma Slides: http://www.slideshare.net/habuma

Who Am I?

Java, Spring, and OSGi fanaticPrincipal Consultant with Improving

AuthorXDoclet in Action (Manning)

Spring in Action (Manning)

Modular Java (Pragmatic Bookshelf)

Page 3: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

What REST is

Web Serviceswith URLs

NOT!!!

Page 4: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

It’s about Resources

Things, not actions

Requests, not demands

Resources, not services

Transfer of state, not RPC

Page 5: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

The Pillars of REST

Resources

URIs/URLs

HTTP Methods

Representations

Page 6: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

The Pillars of REST

Resources

URIs/URLs

HTTP Methods

Representations

Produced as model data in Spring MVC Controllers

Supported in handler methods by @PathParam

@RequestMapping, HiddenHttpMethodFilter, <form:form>

Rendered by view resolversHTML, XML, JSON, RSS, Atom, PDF, Excel, etc.

Negotiated by ContentNegotiatingViewResolver

Page 7: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Identifying Resources

Page 8: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Demanding URLs

http://www.somestore.com/displayProduct?sku=1234

Direct ImperativeCommand

Resource identifier is pushed into

a query parameter

Not very cacheable orsearch engine friendly

Very service-y

Page 9: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Resourceful URLs

http://www.somestore.com/product/1234

We’re requestinga product’s info

Cacheable

The focus ison the product,not the action

This URL alsoidentifies a product(within a context)

Page 10: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Spring MVC overview

Page 11: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

DispatcherServlet

In /WEB-INF/web.xml<servlet> <servlet-name>spitter</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup></servlet>

<servlet-mapping> <servlet-name>spitter</servlet-name> <url-pattern>/app/*</url-pattern></servlet-mapping>

Page 12: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

ContextLoaderListener

<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spitter-security.xml classpath:service-context.xml classpath:persistence-context.xml classpath:dataSource-context.xml classpath:setup-context.xml </param-value></context-param>

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

In /WEB-INF/web.xml

Page 13: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

UrlRewriteFilter<filter> <filter-name>UrlRewriteFilter</filter-name> <filter-class> org.tuckey.web.filters.urlrewrite.UrlRewriteFilter </filter-class></filter><filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>

In /WEB-INF/web.xml

<urlrewrite default-match-type="wildcard"> <rule> <from>/resources/**</from> <to>/resources/$1</to> </rule> <rule> <from>/**</from> <to>/app/$1</to> </rule> <outbound-rule> <from>/app/**</from> <to>/$1</to> </outbound-rule> </urlrewrite>

In /WEB-INF/urlrewrite.xml

/product/1234

/app/product/1234

Page 14: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Essential Configuration

Scan for controller (and other) components<context:component-scan base-package="com.habuma.sample.mvc" />

Resolve JSP views<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/></bean>

<mvc:annotation-driven/>

Handle annotation-driven request mappings

Page 15: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Use-case-based controllers

@Controllerpublic class DisplayProductController { @RequestMapping(value="/displayProduct.htm") public String showProductBySku(String sku, Map<String,Object> model) { Product product = // ... lookup product ... model.put("product", product); return "product"; } // ...}

VERB!!!

http://host/myApp/displayProduct.htm?sku=1234

Page 16: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Resource-oriented controller

@Controller@RequestMapping("/product")public class ProductController { @RequestMapping(value="/{sku}", method=GET) public String showProductBySku( @PathVariable String sku, Map<String,Object> model) { Product product = // ... lookup product ... model.put("product", product); return "product"; }}

Noun

http://host/myApp/product/1234

Verb

Page 17: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

HTTP Methods

GET, DELETE, PUTIdempotent

Transfers state of resourcePOST

Not IdempotentSends data (not nec. state)

Page 18: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

PUT vs. POST

PUTUsed to transfer state to server

Useful when the resource’s URL is knownPOST

Used to send data to serverUseful when the resource’s URL is unknown

or when transferring partial state

Page 19: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Handling DELETE

@Controller@RequestMapping("/product")public class ProductController {

...

@RequestMapping(value="/{sku}", method=DELETE) public String deleteProduct( @PathVariable String sku) { // ... delete product ... return "redirect:home"; }}

http://host/myApp/product/1234

Page 20: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Handling PUT

@Controller@RequestMapping("/product")public class ProductController {

...

@RequestMapping(value="/{sku}", method=PUT) public String saveProduct( @PathVariable String sku, Product product) { // ... save product ... return "redirect:/product/" + sku; }}

http://host/myApp/product/1234

Page 21: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Handling POST

@Controller@RequestMapping("/product")public class ProductController {

...

@RequestMapping(method=POST) public String setPrice(String sku, double price) { // ... update price ... return "redirect:/product/" + sku; }}

http://host/myApp/productFORM DATA: sku=1234

price=5.99

Page 22: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Using PUT/DELETE in formsMost browsers only support GET and POST

Spring’s <form:form> supports all

<form:form method="DELETE" action="http://host/myApp/product/1234">...</form:form>

<form method="POST" action="http://host/myApp/product/1234"> <input type="hidden" name="_method" value="DELETE">...</form>

Hidden method field

Page 23: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

HiddenHttpMethodFilter<filter> <filter-name>httpMethodFilter</filter-name> <filter-class> org.springframework.web.filter.HiddenHttpMethodFilter </filter-class></filter>

<filter-mapping> <filter-name>httpMethodFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>

POST_method=DELETE

DELETE

Hid

denH

ttpM

etho

dFilt

er

Page 24: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Data representation

Spring MVCViews

RSS/Atom

Excel

JSON

PDF

Page 25: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Negotiating Content

ContentNegotiating

ViewResolver

Request

Page 26: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Choosing a view

1. Determine the media type

HTTP Accept header

URL path extension/mediaTypes

format parameter

URL path extension/JAF

2. Find a view resolver thatserves that media type

Page 27: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

ContentNegotiatingViewResolver

<bean class="org.springframework.web.servlet.view. ContentNegotiatingViewResolver"> <property name="mediaTypes"> <map> <entry key="htm" value="text/html"/> <entry key="json" value="application/json"/> </map> </property> <property name="defaultViews"> <list> <bean class="org.springframework.web.servlet.view.json. MappingJacksonJsonView" /> </list> </property></bean>

<bean id="spittles" class="com.habuma.spitter.mvc.view.SpittlesAtomView"/>

Page 28: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Spring’s new views

MappingJacksonJsonView

MarshallingView

AbstractAtomFeedView

AbstractRssFeedView

Page 29: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

XML Marshalling View

<bean id="oxmMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller" />

<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml. MarshallingHttpMessageConverter"> <property name="marshaller" ref="oxmMarshaller" /> <property name="unmarshaller" ref="oxmMarshaller" /></bean>

Page 30: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Sample RSS Viewpublic class SpittlesRssView extends AbstractRssFeedView {

@Override protected List<Item> buildFeedItems( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

@SuppressWarnings("unchecked") List<Spittle> spittles = (List<Spittle>) model.get("spittles"); List<Item> items = new ArrayList<Item>(); for (Spittle spittle : spittles) { Item item = new Item(); item.setTitle(spittle.getText()); item.setPubDate(spittle.getWhen()); item.setAuthor(spittle.getSpitter().getFullName()); items.add(item); } return items; }}

Page 31: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Sample Atom Viewpublic class SpittlesAtomView extends AbstractAtomFeedView {

@Override protected List<Entry> buildFeedEntries( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { @SuppressWarnings("unchecked") List<Spittle> spittles = (List<Spittle>) model.get("spittles"); List<Entry> entries = new ArrayList<Entry>(); for (Spittle spittle : spittles) { Entry entry = new Entry(); entry.setTitle(spittle.getText()); entry.setCreated(spittle.getWhen()); entry.setAuthors(asList(spittle.getSpitter().getFullName())); entries.add(entry); } return entries; }}

Page 32: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

ETags

<filter> <filter-name>etagFilter</filter-name> <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class></filter> <filter-mapping> <filter-name>etagFilter</filter-name> <servlet-name>spitter</servlet-name></filter-mapping>

Returns HTTP 304 if content is unmodifiedif-none-match

(MD5 Hash comparison)

Saves bandwidth

Page 33: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

RestTemplate

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">

RestTemplate rest = (RestTemplate) context.getBean("restTemplate");Map result = rest.getForObject( "http://localhost:8080/mugbooks/book/1.json", Map.class);

In Spring context: (or yes, it could just be new’d up in Java)

In Java:

Page 34: Spring Mvc Rest

E-mail: [email protected] Blog: http://www.springinaction.com Twitter: habuma

Summary

•Spring provides a flexible web MVC framework

•Full support for REST as of Spring 3.0

•Can consume REST services via a template

Page 35: Spring Mvc Rest

Thank You

Don’t forget the evals!