Your SlideShare is downloading. ×
0
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Spring MVC 3 Restful
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Spring MVC 3 Restful

26,486

Published on

Spring MVC 3 Restful

Spring MVC 3 Restful

Published in: Technology, News & Politics
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
26,486
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
0
Comments
0
Likes
10
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Spring 3 MVC Rest (3.0.5 기준)<br />김용환<br />Knight76 at gmail.com<br />Knight76.tistory.com<br />맛보기<br />
  • 2. 특징<br />REST를 쓰기 위해서 Spring MVC 모델을 그대로 차용, Annotation 이용(Controller)<br />JSR 311을 따르지는 않지만, 대부분의 기능 구현<br />하나의 리소스는 여러 개의 Represenation을 가질 수있도록함 (JSON/XML/ATOM/RSS)<br />브라우저에서 지원하지 않는 PUT & POST 요청을 처리할 수 있음<br />Custom parser 이용 가능<br />UTIL(converter..) 클래스 지원<br />=> REST 관련 Conception만 조금 공부하면 되고, 나머지는 기존 MVC만 알면 되기 까닭에재사용성이 큼<br />
  • 3. Spring 3 Rest 지원#1<br />Annotation 지원 <br />@Controller : MVC<br />@RequestMapping : HTTP 메소드, URI, 헤더 처리@RequestMapping(method=RequestMethod.GET, value="/members", <br />@PathVariable: 메소드 안에서 파라미터와매핑하기 위해서 사용public ModelAndViewgetEmployee(@PathVariable String id) { … } <br />@RequestParam : URL 매개변수 이용<br />@RequestHeader<br />@RequestBody<br />@HttpEntity<T><br />@ResponseEntity<T> : 정의한대로 response 리턴<br />public @ResponseBody Employee getEmployeeBy(@RequestParam("name") String name, @RequestHeader("Accept") String accept, @RequestBody String body) {…} <br />public ResponseEntity<String> method(HttpEntity<String> entity) {…} <br />
  • 4. Spring 3 Rest 지원 #1<br />Annotation 지원<br />@ResponseStatus<br />@ExceptionHandler<br />
  • 5. Spring 3 Rest 지원 #2<br />ContentNegotiatingViewResolver<br />요청 데이터 포맷에 맞춰 다양한 MIME(미디어 타입) 이나 content type으로 전달 가능<br />ATOM, RSS, XML, JSON, OXM<br />예)<br />http://localhost:8080/fruit/banana.xml<br />http://localhost:8080/fruit/banana.rss<br />http://localhost:8080/fruit/banana.html<br />Accept : application/xml<br />Accept : application/json<br />Accept : application/html<br />
  • 6. 좋은자료<br />http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html<br />http://dev.anyframejava.org/docs/anyframe/plugin/restweb/1.0.1/reference/html/index.html<br />http://www.mkyong.com/spring-mvc/spring-3-mvc-contentnegotiatingviewresolver-example/<br />http://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html<br />http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/<br />
  • 7. 개념 살펴보기<br />
  • 8. @Controller<br />@Controller<br />@RequestMapping("/restful")<br />public class RestfulController {<br />@RequestMapping(value = "/message/{name}", method = RequestMethod.GET)<br /> public String getMessage(@PathVariable String name, ModelMap model) {<br />model.addAttribute("message", name);<br /> return "list";<br /> }<br />…<br />}<br />
  • 9. Request Parameter Type<br />Strong<br />@Controller<br />@RequestMapping("/restful")<br />public class RestfulController {<br /> @RequestMapping(value = "/message/{name}", method = RequestMethod.GET)<br /> public String getMessage(@PathVariableString name, ModelMap model) {<br />model.addAttribute("message", name);<br /> return "list";<br /> }<br />…<br />}<br />
  • 10. @PathVariable<br />@Controller<br />@RequestMapping("/restful")<br />public class RestfulController {<br /> @RequestMapping(value = "/message/{name}", method = RequestMethod.GET)<br /> public String getMessage(@PathVariable String name, ModelMap model) {<br />model.addAttribute("message", name);<br /> return "list";<br /> }<br />…<br />}<br />
  • 11. @ResponseBody<br />@Controller<br />@RequestMapping("/restful")<br />public class RestfulController {<br />@RequestMapping(value = "/messagebody/{message}", method = RequestMethod.GET)<br />@ResponseBody<br />public Body getMessageBody(@PathVariable String message, ModelMap model) {<br />Body body = new Body();<br />body.setMessage(message);<br />return body;<br />}<br />…<br />}<br />@XmlRootElement(name = "body")<br />public class Body {<br />@XmlElement<br />private String msg;<br />public String getMessage() {<br /> return msg;<br />}<br />public void setMessage(String message) {<br /> this.msg = message;<br />}<br />}<br />
  • 12. @ResponseStatus<br />@RequestMapping(value = "/exception", method = RequestMethod.GET)<br />public String throwException() {<br /> throw new ResourceNotFoundException();<br />}<br />@ExceptionHandler(ResourceNotFoundException.class)<br />@ResponseStatus(value = HttpStatus.BAD_GATEWAY) <br />public void handleNotFoundException(ResourceNotFoundException ex, HttpServletRequest request) {<br />System.out.println("handleNotFoundException:" + ex);<br />}<br />…..<br />class ResourceNotFoundException extends RuntimeException { <br />} <br />$ curl -i localhost:8080/restful/exception<br />HTTP/1.1 502 Bad Gateway<br />Content-Length: 0<br />Server: Jetty(6.1.26)<br />결과<br />
  • 13. Rest 방식과 기존 파라미터요청 방식 을 같이 사용가능??<br />@RequestMapping(value = "/test/{name}/id/{id}", method = RequestMethod.GET)<br />public String getString(@PathVariable String name, @PathVariableint id, String email, ModelMap model) {<br />model.addAttribute("message", name);<br />model.addAttribute("id", id);<br />model.addAttribute("email", email);<br /> return "test";<br />}<br />가능<br />// test.jsp<br /><html><br /><head></head><br /><body><br /><h1>Test</h1><br /><h3>message : ${message}</h3><br /><h3>email : ${email}</h3><br /></body><br /></html><br />$ curl http://localhost:8080/restful/test/jaja/id/11?email=aaa@google.com<br /><html><br /><head></head><br /><body><br /> <h1>Test</h1><br /> <h3>message : jaja</h3><br /> <h3>email : aaa@google.com</h3><br /></body><br /></html><br />결과<br />
  • 14. JSON Payload 요청 #1<br />@Controller<br />@RequestMapping("/comm")<br />@ResponseStatus(value = HttpStatus.ACCEPTED)<br />public class JsonRequestController {<br /> @RequestMapping(method = RequestMethod.GET) <br /> @ResponseStatus(value=HttpStatus.FOUND)<br /> public void sendFruitMessage(@RequestBody Message name) {<br />System.out.println("name : " + name.getName());<br /> return ;<br /> }<br />}<br />Spring MVC가 <br />알아서 deserialization을 해줌<br />@XmlRootElement(name = "message")<br />public class Message {<br />@XmlElement<br />private String name;<br />public String getName() {<br />return name;<br />}<br /> public void setName(String name) {<br /> this.name = name;<br /> }<br />}<br />
  • 15. JSON Payload 요청 #2<br />결과 : xml <br /><클라이언트><br />$ curl -i -H "Content-Type: application/xml" -X get -d '<message><name>Kim Yong Hwan</name></message>' localhost:8080/comm<br />HTTP/1.1 302 Found<br />Content-Length: 0<br />Server: Jetty(6.1.26)<br /><서버><br />name : Kim Yong Hwan<br />결과 : json<br /><클라이언트><br />$ curl -i -H "Content-Type: application/json" -X get -d '{"name":"Kim Yong Hwan"}' localhost:8080/comm<br />HTTP/1.1 302 Found<br />Content-Length: 0<br />Server: Jetty(6.1.26)<br /><서버><br />name : Kim Yong Hwan<br />
  • 16. DEMO<br />
  • 17. WEB.XML<br /><web-app id="WebApp_ID" version="2.4"<br />xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee <br />http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><br /><display-name>Spring Web MVC Rest Demo Application</display-name><br /><servlet><br /> <servlet-name>mvc-dispatcher</servlet-name><br /> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><br /> <load-on-startup>1</load-on-startup><br /></servlet><br /><servlet-mapping><br /> <servlet-name>mvc-dispatcher</servlet-name><br /> <url-pattern>/</url-pattern><br /></servlet-mapping><br /><context-param><br /> <param-name>contextConfigLocation</param-name><br /> <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value><br /></context-param><br /><listener><br /> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class><br /></listener><br /></web-app><br />
  • 18. mvc-dispatcher-servlet.xml<br /><beans xmlns="http://www.springframework.org/schema/beans"<br />xmlns:context="http://www.springframework.org/schema/context"<br />xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />xsi:schemaLocation="<br /> http://www.springframework.org/schema/beans <br /> http://www.springframework.org/schema/beans/spring-beans-3.0.xsd<br /> http://www.springframework.org/schema/context <br /> http://www.springframework.org/schema/context/spring-context-3.0.xsd<br /> http://www.springframework.org/schema/mvc<br /> http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><br /><context:component-scan base-package="com.google.controller" /><br /><mvc:annotation-driven /><br /><bean<br />class="org.springframework.web.servlet.view.InternalResourceViewResolver"><br /> <property name="prefix" value="/WEB-INF/pages/" /><br /> <property name="suffix" value=".jsp" /><br /></bean><br /></beans><br />
  • 19. RestfulController.java<br />@Controller<br />@RequestMapping("/restful")<br />public class RestfulController {<br />@RequestMapping(value = "/message/{name}", method = RequestMethod.GET)<br /> public String getMessage(@PathVariable String name, ModelMap model) {<br />model.addAttribute("message", name);<br /> return "list";<br /> }<br />@RequestMapping(value = "/command/{id}/content/{content}", method = RequestMethod.GET)<br /> public String getCommand(@PathVariable("id") String id, @PathVariable("content") long content, ModelMap model) {<br />model.addAttribute("id", id);<br />model.addAttribute("content", content);<br /> return "command";<br /> }<br />@RequestMapping(value = "/link/{id}", method = RequestMethod.DELETE)<br /> public String deleteLink(@PathVariable("id") String id, ModelMap model) {<br />model.addAttribute("id", id);<br /> return "delete";<br /> }<br />}<br />
  • 20. JSP 소스<br />// WEB-INF/pages/list.jsp<br /><html><br /><body><br /><h1>Spring MVC Restful Test</h1><br /><h3>message : ${message}</h3><br /></body><br /></html><br />// WEB-INF/pages/command.jsp<br /><html><br /><body><br /><h1>Spring MVC Restful Test</h1><br /> <h3>command id : ${id}</h3><br /><h3>content : ${content}</h3><br /></body><br /></html><br />// WEB-INF/pages/delete.jsp<br /><html><br /><body><br /><h1>Spring MVC Restful Test</h1><br /><h3>deleted id : ${id}</h3><br /></body><br /></html><br />
  • 21. 결과 (웹 브라우저)<br />http://localhost:8080/restful/message/reset<br />http://localhost:8080/restful/command/aa/content/111<br />
  • 22. 결과 (리눅스/Cygwin)<br />curl -X DELETE http://localhost:8080/restful/link/1<br /> curl -X DELETE http://localhost:8080/restful/message/3<br />
  • 23. Content Negotiation<br />
  • 24. Content Negotiation<br />HTTP 1.1 스펙에서 정의<br />의미<br />media type, 언어, 문자집합, 인코딩 등에 대해 브라우저가 제공한 선호도에 따라 자원의 가장 적합한 표현을 선택. <br />불완전한 협상 정보를 보내는 브라우저의 요청을 지능적으로 처리하는 기능<br />일반적으로 다른 프로토콜을 쓰려면, request의 “type” 파라미터를 확인하고, 이에 맞는 marshalling정보를 전달해야 한다.<br />트위터API가 이렇게 사용되고 있음<br />Spring MVC에서는 한번에 해결해주는 클래스 사용 ContentNegotiatingViewResolver<br />
  • 25. DEMO<br />
  • 26. FruitController<br />@Controller<br />@RequestMapping("/fruit")<br />public class FruitController{<br /> @RequestMapping(value="{fruitName}", method = RequestMethod.GET)<br /> public String getFruit(@PathVariable String fruitName, ModelMap model) {<br /> Fruit fruit = new Fruit(fruitName, 1000);<br />model.addAttribute("model", fruit);<br /> return "listfruit";<br /> }<br />}<br />
  • 27. Fruit<br />@XmlRootElement(name = "fruit")<br />public class Fruit {<br />String name;<br />intquality;<br />public Fruit() {}<br />public Fruit(String name, int quality) {<br /> this.name = name;<br />this.quality = quality;<br />}<br />@XmlElement<br />public void setName(String name) {<br />this.name = name;<br />}<br />@XmlElement<br />public void setQuality(int quality) {<br />this.quality = quality;<br />}<br />}<br />
  • 28. mvc-dispatcher-servlet.xml<br /><bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><br /> <property name="order" value="1" /><br /> <property name="mediaTypes"><br /><map><br /> <entry key="json" value="application/json" /><br /> <entry key="xml" value="application/xml" /><br /> <entry key="rss" value="application/rss+xml" /><br /></map><br /> </property><br /> <property name="defaultViews"><br /><list><br /> <!-- JSON View --><br /> <bean<br />class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"><br /> </bean><br /> <!-- RSS View --><br /> <bean class="com.google.rss.RssFeedView" /><br /> <!-- JAXB XML View --><br /> <bean class="org.springframework.web.servlet.view.xml.MarshallingView"><br /><constructor-arg><br /><bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><br /> <property name="classesToBeBound"><br /><list><br /> <value>com.google.bean.Fruit</value><br /></list><br /> </property><br /></bean><br /></constructor-arg><br /> </bean><br /> </list><br /> </property><br /> <property name="ignoreAcceptHeader" value="true" /><br /></bean><br /><bean<br />class="org.springframework.web.servlet.view.InternalResourceViewResolver"><br /><property name="order" value="2" /><br /><property name="prefix" value="/WEB-INF/pages/" /><br /><property name="suffix" value=".jsp" /><br /></bean><br />
  • 29. 결과<br />$ curl -H 'Accept: application/xml' localhost:8080/fruit/banana.xml<br /><?xml version="1.0" encoding="UTF-8" standalone="yes"?><fruit><name>banana</name<br />><quality>1000</quality></fruit><br />$ curl -H 'Accept: application/rss'localhost:8080/fruit/banana.rss<br /><?xml version="1.0" encoding="UTF-8"?><br /><rssxmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><br /> <channel><br /> <title>Sample Title</title><br /> <link>http://google.com</link><br /> <description>Sample Description</description><br /> <item><br /> <link>http://www.google.com</link><br /> <content:encoded>banana1000</content:encoded><br /> <author>Test</author><br /> </item><br /> </channel><br /></rss><br />$ curl -H 'Accept: application/json' localhost:8080/fruit/banana.json<br />{"model":{"quality":1000,"name":"banana"}}<br />
  • 30. Demo에서 @XmlElement사용시 유의할 점<br />Set메소드를 사용하려면, 다음과 같이 한다. <br />클래스의 멤버 필드에서 @XmlElement를 정의할 때는 set 메소드를 사용하지 않는다. <br />@XmlRootElement(name = "fruit")<br />public class Fruit {<br /> private String name;<br /> private int quality;<br />@XmlElement<br /> public void setBody(Body body) {<br />this.body= body;<br /> }<br /> public String getName() {<br /> return name;<br /> }<br />@XmlElement<br /> public void setQuality(int quality) {<br />this.quality= quality;<br /> }<br /> public intgetQuality() {<br /> return quality;<br /> }<br />…<br />}<br />@XmlRootElement(name = "fruit")<br />public class Fruit {<br />@XmlElement<br /> private String name;<br />@XmlElement<br /> private int quality;<br /> public String getName() {<br /> return name;<br /> }<br /> public intgetQuality() {<br /> return quality;<br /> }<br />…<br />}<br />JAXB에서 property를 읽을 때, 잘 사용해야 하는 구조<br />
  • 31. Demo에서 @XmlElement사용시유의할 점<br />Body 클래스앞에@XmlRootElement선언이 되어 있으면, Fruit 클래스 에서 @XmlElement를 사용하지 않아도 된다.<br />@XmlRootElement(name = "body")<br />public class Body {<br /> @XmlElement<br /> private String msg;<br /> // set/get accessory ….<br />}<br />@XmlRootElement(name = "fruit")<br />public class Fruit {<br />@XmlElement<br /> private String name;<br />@XmlElement<br /> private int quality;<br /> private Body body;<br /> public String getName() {<br /> return name;<br /> }<br /> public intgetQuality() {<br /> return quality;<br /> }<br />…<br />}<br />
  • 32. 웹 브라우져에서의PUT/DELETE의 제약<br />
  • 33. 웹 브라우져 제약 #1<br />GET/POST만 쓸 수 있는 웹 브라우져가 있을 수 있다. PUT과 DELETE 을 쓰기 위해서는 trick을 써야 한다.<br />HiddenHttpMethodFilter이용<br />Web.xml<br />  <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><br />
  • 34. 웹 브라우져 제약 #2<br />// spring mvc form tag<br /><form:form method="delete"> <br /><p class="submit"><input type="submit" value="Delete Pet"/></p> <br /></form:form><br />@RequestMapping(method = RequestMethod.DELETE)<br />public String deletePet(@PathVariableintownerId, @PathVariableintpetId) {<br />this.clinic.deletePet(petId);<br /> return "redirect:/owners/" + ownerId;<br />}<br />아마도 예전처럼 내부적으로 name=“_method” value=“Delete” 하는 형태로 <br />전달하고, Spring 서버는 이 정보를 바탕으로 구현 했을 것으로 예상<br /><form action="POST"><br />  <input type="hidden" id="_method" value="PUT"><br /></form><br />
  • 35. PUT/DELETE in HTML<br />HTML version 4 과 XHTML 1에서는 HTML form안의 HTTP 요청은 GET과 POST 방식만 허용. 그동안put/delete 메소드를 사용하려면, XMLHttpRequest를 이용하였음<br />HTTP상에서는 ok!<br />HTML5에서 put/delete는 사용하지 못한다고 나와 있음<br />http://www.w3.org/TR/html5-diff/<br />Using PUT and DELETE as HTTP methods for the form element is no longer supported.<br />참고<br />
  • 36. 클라이언트 API : RestTemplate<br />
  • 37. 클라이언트 API<br />Apache Commons의 HttpClient대신 쉽게 사용할 수 있는 RestTemplate구성<br /><bean id="restTemplate" <br />class="org.springframework.web.client.RestTemplate"><br /><property name="messageConverters"><br /> <list><br /> <ref bean="marshallingConverter" /><br /> <ref bean="atomConverter" /><br /> <ref bean="jsonConverter" /><br /> </list><br /></property><br /></bean><br />
  • 38. 클라이언트 API<br />XML 요청<br />HttpHeaders headers = new HttpHeaders();<br />headers.setContentType(MediaType.APPLICATION_XML);<br />HttpEntity<String> entity = new HttpEntity<String>(headers);<br />ResponseEntity<EmployeeList> response = restTemplate.exchange(<br />"http://localhost:8080/rest/service/emps", <br />HttpMethod.GET, entity, EmployeeList.class);<br />EmployeeListingemployees = response.getBody();<br />// handle the employees<br />
  • 39. 클라이언트 API<br />새직원포스팅/ 삭제<br />Employee newEmp = new Employee(11, “tguest", “tguest@google.com");<br />HttpEntity<Employee> entity = new HttpEntity<Employee>(newEmp);<br />restTemplate.put(<br /> "http://localhost:8080/rest/service/emp/{id}", entity, "99");<br />restTemplate.delete(<br /> "http://localhost:8080/rest/service/emp/{id}", "99");<br />
  • 40. RestTemplate클래스<br />클라이언트에서 사용할 수 있는 Rest API<br />
  • 41. RestTemplate클래스<br />
  • 42. RestTemplate예제<br />Map<String, String> vars = new HashMap<String, String>();<br />vars.put("id", "111");<br />vars.put("content", "222");<br />RestTemplaterestTemplate = new RestTemplate();<br />String result = restTemplate.getForObject("http://localhost:8080/restful/command/{id}/content/{content}", String.class, vars);<br />System.out.println("result : " + result);<br />result : <html><br /><body><br /><h1>Spring MVC Restful Test</h1><br /> <h3>command id : 111</h3><br /><h3>content : 222</h3><br /></body><br /></html><br />결과<br />
  • 43. ExampleCode<br />Knight76.tistory.com에서 ‘spring mvc restful’ 검색<br />
  • 44. End of Document<br />

×