2009年2月16日 星期一

使用 springframework 3.0.0 建立 RESTful 網路應用程式 Controller

RESTful是一種新的Webapp設計概念,可以減少很多傳統Webapp程式的code,
傳統Webapp以一個 url mapping 到一個 service ,如 java servlet 或 spring controller,
以操作資料庫的 CRUD 四個步驟來說,一張資料表至少就需要4個 service 命令來完成實作。
也就是要分別對四個 url 進行操作。

RESTful 則將資料當成一種資源,利用 http 原本就有的 Get、Post、Delete、Put…
等七個 method ,對同一個 url 進行操作,如下圖。
















spring 在 3.0版之後的 spring MVC 框架就有提供 RESTful 相關的支援,並使用 java 5.0 的
annotation 語法,用起非常簡單方便。

spring 3.0.0 相依的 jar有:
antlr-3.0.1.jar
asm-3.1.jar
asm-common-3.1.jar
commons-logging.jar
log4j-1.2.13.jar

簡單的 RESTful 範例 /rest/{i}/{n} : i、n 均為變數


web.xml 加入 DispatcherServlet 的servlet定義,並mapping到 /rest/*

<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/conf/spring-restful-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

需注意:
DispatcherServlet 因為被 mapping 到 /rest/* 所以在 DispatcherServlet 帶起來的WebApplicationContext 之下 做mapping時, "/"符號就等於 "/rest/"這一層 ,
也就是說 html form action 的 "/rest/1/2/3/4" mapping 要寫成 "/1/2/3/4"。

在 web.xml 指定了 /WEB-INF/conf/spring-restful-config.xml 這個檔為 spring bean config
內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

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

<bean id="testController"
class="com.transtep.restful.server.framework.spring.controller.TestController">
</bean>
</beans>

spring-restful-config.xml 檔裡有 2 個 bean 負責 spring 2.5 開始有的 annotation MVC功能,
DefaultAnnotationHandlerMapping -> 處理 class level 的 annotation。
AnnotationMethodHandlerAdapter -> 處理 method level 的 annotation。
底下再定義 Controller 的 bean class,這些 bean 就可以用 annotation 的語法來定義了。
如這裡的 TestController :

@Controller
public class TestController {

@RequestMapping(value = "/1/{ii}/{nn}", method = RequestMethod.GET)
public ModelAndView getTest(@PathVariable(value = "ii") String id, @PathVariable(value = "nn") String number) {
System.out.println("run 1");
Map model = new HashMap();
model.put("message", "id " + id + "\n" + "number " + number);
return new ModelAndView("test", model);
}

@RequestMapping(value = "/1/{ii}/{nn}", method = RequestMethod.POST)
public ModelAndView postTest(@PathVariable(value = "ii") String id, @PathVariable(value = "nn") String number) {
Map model = new HashMap();
model.put("message", "id " + id + "\n" + "number " + number);
return new ModelAndView("test", model);
}
}

首先在 class 宣告上以 @Controller 定義這是一個 Controller (不需要再implements Controller)
再以
@RequestMapping 定義各別的 method 的 URI 、 method mapping,特別是 URI 可以{}
定義成變數的格式,再配合 @PathVariable 將變數的實際值綁到 method的參數上,同時根據
方法的參數型別不同,自動轉換成正確的型別。

上面的例子以 get /rest/1/123/456 則會執行 getTest() 方法,id=123,number=456
而如果以 post /rest/1/456/789 則會執行 postTest() 方法,id=456,number=789

沒有留言: