跟隨 Web Service 一路走來, 記憶中的 Apache SOAP, Apache Axis, XFire, 標准化的JAX-RPC, JAX-WS, 到后來半路殺出的的 Spring-WS, CXF
一切剛剛開始,一切望塵莫及,短命是純技術的特征。
RPC 的平台局限性,SOAP 的類型 bind 的易脆性, JAX-WS 工具的信賴度, Spring-WS contract first 使一個小時可以完成(甚至在IDE中十分鍾可以完成)的工作,要整一天,還要到看到 JUnit 的 Green bar 才算數。
已經標准化的JAX-RS,證明 RESTful 已經成為SOA加架的主流,以至於 Spring-WS 停止在了他的 1.59 版本,SpringSource 放棄了這個市場么?
呵呵!它早已意識到了問題的所在,市場上有多少 Spring-WS 的需求? 相比於它的 IoC, Spring-WS 是個失敗的產品。它已經轉移了重點:
2.5.6.1 Comprehensive REST support
Server-side support for building RESTful applications has been provided as an extension of the existing annotation driven MVC web framework. Client-side support is provided by the RestTemplate class in the spirit of other template classes such as JdbcTemplate and JmsTemplate. Both server and client side REST functionality make use of HttpConverters to facilitate the conversion between objects and their representation in HTTP requests and responses.
The MarshallingHttpMessageConverter uses the Object to XML mapping functionality mentioned earlier.
下面的代碼 使用 RestTemplate 訪問,SpringMVC 3 的一個 Controller (RESTful service),service 要求一個 SHA512 key.
RestTemplate 封裝了一個 ClientHttpRequestFactory,Spring3 提供兩種實現:
1. SimpleClientHttpRequestFactory 采用JDK URLConnection
2. CommonsClientHttpRequestFactory 采用 commons/httpclient 3.x (注意不是4)
- @SuppressWarnings("unchecked")
- private List<BufferedImage> searchProductImage(String keyword, String apikey, int page, int max) {
- final String restUri = "http://localhost:8080/hjpetstore/rest/products/{keyword}?apikey={apikey}&page={page}&max={max}";
- Source product = restTemplate.getForObject(restUri, Source.class, keyword, apikey, page, max);
- final String imageUrl = "http://localhost:8080/hjpetstore/images/{imageFileName}";
- List<BufferedImage> images = (List<BufferedImage>) xpathTemplate.evaluate("//image", product, new NodeMapper() {
- @Override
- public Object mapNode(Node node, int i) throws DOMException {
- //Element image = (Element) node;
- org.jdom.Element image = new DOMBuilder().build((Element) node);
- String imageFileName = image.getValue();
- //String imageFileName = image.getFirstChild().getNodeValue();
- return restTemplate.getForObject(imageUrl, BufferedImage.class, imageFileName);
- }
- });
- return images;
- }
邏輯的處理是 Xpath 解析 Response的XML,再次 請求 image 的url,然后利用 org.springframework.http.converter.BufferedImageHttpMessageConverter 返回一個 BufferedImage 的列表,送給 Swing 組件渲染出來。

- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:util="http://www.springframework.org/schema/util"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
- <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>application.properties</value>
- </list>
- </property>
- </bean>
- <bean id="searchProductListRest" class="org.pprun.hjpetstore.client.SearchProductListRest">
- <constructor-arg ref="restTemplate"/>
- <constructor-arg ref="xpathTemplate"/>
- </bean>
- <!-- the template can be used to call home-grown or external RESTful service -->
- <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
- <property name="requestFactory">
- <bean class="org.springframework.http.client.CommonsClientHttpRequestFactory">
- <constructor-arg>
- <bean class="org.apache.commons.httpclient.HttpClient">
- <constructor-arg index="0">
- <bean id="httpClientParams" class="org.apache.commons.httpclient.params.HttpClientParams">
- <property name="authenticationPreemptive" value="true"/>
- </bean>
- </constructor-arg>
- <constructor-arg index="1">
- <bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager">
- <property name="params">
- <bean class="org.apache.commons.httpclient.params.HttpConnectionManagerParams">
- <property name="soTimeout" value="${rest.service.timeout}" />
- <property name="connectionTimeout" value="${rest.service.connectionTimeout}" />
- <property name="defaultMaxConnectionsPerHost" value="${rest.service.maxConnections}" />
- <property name="maxTotalConnections" value="${rest.service.maxTotalConnections}" />
- <property name="staleCheckingEnabled" value="${rest.service.staleCheckEnabled}" />
- </bean>
- </property>
- </bean>
- </constructor-arg>
- </bean>
- </constructor-arg>
- </bean>
- </property>
- <!-- 19.9.2 HTTP Message Conversion
- several main media type converters have been registered,
- but if we overwrite tihs property, we have to list all our need
- -->
- <property name="messageConverters">
- <list>
- <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
- <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
- </list>
- </property>
- </bean>
- <bean id="xpathTemplate" class="org.springframework.xml.xpath.Jaxp13XPathTemplate"/>
- </beans>

