Spring MVC Part 2 Spencer Uresk Notes This

  • Slides: 30
Download presentation
Spring MVC Part 2 Spencer Uresk

Spring MVC Part 2 Spencer Uresk

Notes • • • This is a training, NOT a presentation Please ask questions

Notes • • • This is a training, NOT a presentation Please ask questions This is being recorded https: //tech. lds. org/wiki/Java_Stack_Training Prerequisites – Beginning Spring MVC (and all of its prerequisites)

Overview • Last time, we showed how to map requests to handler methods, get

Overview • Last time, we showed how to map requests to handler methods, get information about the request, and how to pass information back to the view • We’ll see what an HTTP message looks like • This week, we’ll look at some of Spring MVC’s RESTful features, including Request. Body, Response. Body, Http. Message. Converters, Http. Entity objects, and dealing with exceptions • These are useful for RESTful web services and normal form-based interactions

HTTP Message • What does an HTTP message look like? • Sample Requests: GET

HTTP Message • What does an HTTP message look like? • Sample Requests: GET /view/1 HTTP/1. 1 User-Agent: Chrome Accept: application/json [CRLF] Request Line Headers POST /save HTTP/1. 1 Request Line User-Agent: IE Content-Type: application/x-www-form-urlencoded [CRLF] name=x&id=2 Request Body Headers

HTTP Message (Responses) • Sample Responses HTTP/1. 1 200 OK Content-Type: text/html Content-Length: 1337

HTTP Message (Responses) • Sample Responses HTTP/1. 1 200 OK Content-Type: text/html Content-Length: 1337 [CRLF] <html> Some HTML Content. </html> HTTP/1. 1 500 Internal Server Error HTTP/1. 1 201 Created Location: /view/7 [CRLF] Some message goes here. Status Line Headers Response Body

Request. Body • Annotating a handler method parameter with @Request. Body will bind that

Request. Body • Annotating a handler method parameter with @Request. Body will bind that parameter to the request body @Request. Mapping("/echo/string") public void write. String(@Request. Body String input) {} @Request. Mapping("/echo/json") public void write. Json(@Request. Body Some. Object input) {}

Response. Body • Annotating a return type with @Response. Body tells Spring MVC that

Response. Body • Annotating a return type with @Response. Body tells Spring MVC that the object returned should be treated as the response body • No view is rendered in this case @Request. Mapping("/echo/string") public @Response. Body String read. String() {} @Request. Mapping("/echo/json") public @Response. Body Some. Object read. Json() {}

Http. Message. Converters • How does Spring MVC know how to turn a JSON

Http. Message. Converters • How does Spring MVC know how to turn a JSON string into Some. Object, or vice-versa? • Http. Message. Converters • These are responsible for converting a request body to a certain type, or a certain type into a response body • Spring MVC figures out which converter to use based on Accept and Content-Type headers, and the Java type • Your Accept and Content-Type headers DON’T have to match. For example, you can send in JSON and ask for XML back

Http. Message. Converters • A number of Http. Message. Converters are already provided •

Http. Message. Converters • A number of Http. Message. Converters are already provided • You can define your own, but that is outside the scope of this training • You don’t specify which ones are used to convert request/response bodies – they are selected based on the Content-Type/Accept headers

MIME Types • Http. Message. Converters make heavy use of MIME types (RFC 2046)

MIME Types • Http. Message. Converters make heavy use of MIME types (RFC 2046) • These are the value for Accept and Content-Type headers • Two-part identifier for content formats • First part is the type. ie, application • Second part is the sub-type. ie, json • application/json

String. Http. Message. Converter • Reads and writes Strings. • Reads text/* • Writes

String. Http. Message. Converter • Reads and writes Strings. • Reads text/* • Writes text/plain

String. Http. Message. Converter @Request. Mapping("/echo/string") public @Response. Body String echo. String(@Request. Body String

String. Http. Message. Converter @Request. Mapping("/echo/string") public @Response. Body String echo. String(@Request. Body String input) { return “Your Text Was: “ + input; } • a POST /echo/string HTTP/1. 1 Accept: text/plain Content-Type: text/plain REQUEST Hello! HTTP/1. 1 200 OK Content-Type: text/plain Content-Length: 17 Your Text Was: Hello! RESPONSE

Mapping. Jackson. Http. Message. Converter • Maps to/from JSON objects using the Jackson library

Mapping. Jackson. Http. Message. Converter • Maps to/from JSON objects using the Jackson library • Reads application/json • Writes application/json

Mapping. Jackson. Http. Message. Converter public Person { // String name, int age; }

Mapping. Jackson. Http. Message. Converter public Person { // String name, int age; } • a @Request. Mapping("/echo/json") public @Response. Body Person echo. Json(@Request. Body Person person) { // Upper case name, square age return person; } POST /echo/string HTTP/1. 1 Accept: application/json Content-Type: application/json REQUEST { “name” : “Spencer”, “age” : 5 } HTTP/1. 1 201 Created Content-Type: application/json { “name” : “SPENCER”, “age” : 25 } RESPONSE

Jaxb 2 Root. Element. Http. Message. Converter • Maps to/from XML objects • Must

Jaxb 2 Root. Element. Http. Message. Converter • Maps to/from XML objects • Must have your object at least annotated with @Xml. Root. Element • Reads text/xml, application/xml • Writes text/xml, application/xml

Jaxb 2 Root. Element. Http. Message. Converter @Xml. Root. Element public Person {// String

Jaxb 2 Root. Element. Http. Message. Converter @Xml. Root. Element public Person {// String name, int age; } • a @Request. Mapping("/echo/xml") public @Response. Body Person echo. Xml(@Request. Body Person person) { // Upper case name, square age return person; } POST /echo/string HTTP/1. 1 Accept: application/xml Content-Type: application/xml REQUEST <thing><name>Spencer</name><age>5</age></thing> HTTP/1. 1 201 Created Content-Type: application/xml <thing><name>SPENCER</name><age>25</age></thing> RESPONSE

Byte. Array. Http. Message. Converter • Can read/write byte arrays (useful for dealing with

Byte. Array. Http. Message. Converter • Can read/write byte arrays (useful for dealing with binary data, such as images) • Reads */* • Writes application/octet-stream

Byte. Array. Http. Message. Converter @Request. Mapping("/echo/string") public @Response. Body String echo. String(@Request. Body

Byte. Array. Http. Message. Converter @Request. Mapping("/echo/string") public @Response. Body String echo. String(@Request. Body byte[] input) { return new String(input); } • a POST /echo/string HTTP/1. 1 Accept: text/plain Content-Type: text/plain REQUEST Hello! HTTP/1. 1 200 OK Content-Type: application/octet-stream Content-Length: 6 Hello! RESPONSE

Lab 1 • Create a handler that takes a request body and echoes it

Lab 1 • Create a handler that takes a request body and echoes it back. • Create a handler that takes a request body, creates an object with it, and returns it as JSON. • Create a handler that takes an XML input and echoes it back as JSON. • Test all of these with your Http. Client

Other parts of the HTTP Message • What if you need to get/set headers?

Other parts of the HTTP Message • What if you need to get/set headers? • Or set the status code? @Request. Mapping("/echo/string") public @Response. Body String echo. String(@Request. Body String input, Http. Servlet. Request request, Http. Servlet. Response response) { String request. Type = request. get. Header(“Content-Type”); response. set. Header(“Content-Type”, “text/plain”); response. set. Status(200); return input }

@Response. Status • There is a convenient way to set what the default status

@Response. Status • There is a convenient way to set what the default status for a particular handler should be • @Response. Status @Request. Mapping("/create") @Response. Status(Http. Status. CREATED) // CREATED == 201 public void echo. String(String input) { }

Http. Entity • Convenience class for dealing with bodies, headers, and status • Converts

Http. Entity • Convenience class for dealing with bodies, headers, and status • Converts messages with Http. Message. Converters @Request. Mapping("/image/upload") public Response. Entity<String> upload(Http. Entity<byte[]> r. Entity) { String t = r. Entity. get. Headers(). get. First(“Content-Type”); byte[] data = r. Entity. get. Body(); // Save the file Http. Headers response. Headers = new Http. Headers(); response. Headers. set(“Location”, “/image/1”); return new Response. Entity<String>(“Created”, response. Headers, Http. Status. CREATED); }

Lab 2 • Convert all your String controller method to use Http. Entity •

Lab 2 • Convert all your String controller method to use Http. Entity • Convert the Create Person controller method to use an Http. Entity. Also, return a Location header and a 201 (Created) response code.

Dealing with exceptions • By default, Spring MVC will map certain exceptions to status

Dealing with exceptions • By default, Spring MVC will map certain exceptions to status codes • You can implement your own Handler. Exception. Resolver, which takes an exception and returns a Model. And. View • You can register a Simple. Mapping. Exception. Resolver to map exceptions to views • You can annotate methods in the controller to handle specific exceptions

Default Exception Mappings • These take effect if you have no other configuration •

Default Exception Mappings • These take effect if you have no other configuration • • Conversion. Not. Supported. Exception => 500 No. Such. Method. Handling. Exception => 404 Missing. Servlet. Request. Parameter. Exception => 400 Http. Request. Method. Not. Supported. Exception => 405 Type. Mismatch. Exception => 400 Http. Media. Type. Not. Supported. Exception => 415 Http. Media. Type. Not. Acceptable. Exception => 406

Handler. Exception. Resolver • Allows you to control how exceptions are resolved • Implement

Handler. Exception. Resolver • Allows you to control how exceptions are resolved • Implement Handler. Exception. Resolver (but you’ll probably extend Abstract. Handler. Exception. Resolver) class An. Exception. Handler extends Abstract. Handler. Exception. Resolver { protected Model. And. View do. Resolve. Exception( Http. Servlet. Request request, Http. Servlet. Response response, Object handler, Exception ex) { System. out. println("I got an error. "); return new Model. And. View("errors/some. Error"); } }

Simple. Mapping. Exception. Resolver • Allows you to simply map exceptions to views •

Simple. Mapping. Exception. Resolver • Allows you to simply map exceptions to views • This is how the Stack comes configured <bean class="org. springframework. web. servlet. handler. Simple. Mapping. Exception. Resolver"> <property name="exception. Mappings"> <props> <prop key=". Data. Access. Exception">errors/data. Access. Failure</prop> <prop key=". Access. Denied. Exception">errors/data. Access. Failure</prop> <prop key=". Type. Mismatch. Exception">errors/resource. Not. Found</prop> </props> </property> <property name="default. Error. View" value="errors/general. Error"/> <property name="warn. Log. Category" value="org. lds. stack"/> </bean>

@Exception. Handler • Create a method to handle the exception, annotate it with @Exception.

@Exception. Handler • Create a method to handle the exception, annotate it with @Exception. Handler, and pass in the exception(s) that method can handle • Exception. Handler methods look a lot like normal handler methods @Request. Mapping("/error") public void do. Something() { throw new Recoverable. Data. Access. Exception("Unable to access that database. "); } @Exception. Handler(Data. Access. Exception. class) public @Response. Body String handle. Data. Access. Error(Data. Access. Exception ex) { return ex. get. Message(); }

@Response. Status • We saw this annotation earlier • It can also be placed

@Response. Status • We saw this annotation earlier • It can also be placed on Exception classes or @Exeption. Handler methods to return a specific status code for a particular exception @Response. Status(Http. Status. INTERNAL_SERVER_ERROR) @Exception. Handler(Data. Access. Exception. class) public void handle. Data. Access. Error(Data. Access. Exception ex) {} @Response. Status(value = Http. Status. PAYMENT_REQUIRED, message = “I need money. ”) public class Payment. Required. Exception {}

Lab 3 • Look at the Simple. Mapping. Exception. Resolver already configured in your

Lab 3 • Look at the Simple. Mapping. Exception. Resolver already configured in your project • Create a controller that throws one of those exceptions and verify that your request gets redirected to the corresponding view • Remove the config, and change your exception to Http. Media. Type. Not. Supported. Exception. Verify that you get a 415 using your Http Client • Implement an @Exception. Handler method