惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
GRAHAM CLULEY
V
V2EX
WordPress大学
WordPress大学
博客园 - Franky
Last Week in AI
Last Week in AI
博客园 - 司徒正美
有赞技术团队
有赞技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
V
Visual Studio Blog
C
CERT Recently Published Vulnerability Notes
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
腾讯CDC
The Hacker News
The Hacker News
Hugging Face - Blog
Hugging Face - Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
J
Java Code Geeks
人人都是产品经理
人人都是产品经理
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
S
SegmentFault 最新的问题
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
A
Arctic Wolf
量子位
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News and Events Feed by Topic
雷峰网
雷峰网
博客园_首页
Google Online Security Blog
Google Online Security Blog
Spread Privacy
Spread Privacy
罗磊的独立博客
H
Hacker News: Front Page
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
IT之家
IT之家
The Cloudflare Blog
爱范儿
爱范儿
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - 岁月无声

Spring Boot(3)---自定义spring boot starter 问题 那就开始吧---写在2014年8月 从操作系统机制浅谈服务器及服务平台方案的选择 Node.JS平台上的数据库Redis,MongoDB,HBASE,MySQL Node.JS 模块,包管理与开发 Node.JS进行简单新技术分析及环境搭建 MongoDB (1)---复制集与sharding安装配置 MongoDB (5)---不仅仅是数据库 MongoDB (0)---写在前面 NoSQL--MongoDB选择 云平台综述 物联网(1)----手机NFC识别方案平台 快速建立一个手机网站 基于HTML5手机技术方案(如Phonegap)的调试方案 由NodeJS浅谈无敌的前端开发工程师 PHP调试环境 大话网站---从Hello World到高并发网站 浅谈预演框架选择 最后的绝唱-----Symbian 最新的IDE开发环境搭建(Updated on 2011-03-07)
基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)
岁月无声 · 2013-03-03 · via 博客园 - 岁月无声

快十年没玩SSH这类东西了,由于上个产品用Restful Service 作为应用服务接口,所以顺手整理一下。考虑到当年我刚入门时经历的一些痛苦,所以这里我会讲得详细些,共享之。

一,选择一个合适的,Web开发环境:

   我选择的是Eclipse for J2EE,当然大家可以选择MyEclipse我只是嫌最新版的MyEclipse Crack太烦,所以没用它。当年我也是最喜欢它的哟。如果你手头只有Eclipse for Java没关系,安装一个WTP就可以了。

   a.首先创建一个Dynamic Web Project :

     在创建的第一页,Project Name 我用的是"MyServices"中要在Target Runtime中选择一个容器服务器,我这里测试环境下,选择的是Tomcat ,如果没有,可以在右边点击“New Runtime"进行新增Tomcat 运行环境。

     在Project创建的最后一页最好选中创建一个web.xml省得你去创建,缺省情况下,这个web.xml只配置了欢迎页面。如index.php等。

  b.测试一下,是否这个环境可以发布Build后的代码及网页到Tomcat测试环境中运行:

     在左边的"Web Content"目录下的”WEB-INF"子目录,创建一个index.jsp文件进行测试。创建完成后,重新build项目,然后在右下方的Server Tab里会自动列出你刚才选择的Tomcat发布环境。你点击这个Tomcat Server

    我的环境是Tomcat Server 7.0 然后右键菜单中选择“Publish" 你会看到 服务器,及服务器下面你的项目右边会由”Republish"变成“Synchronized" ,说明工程编译结果都已成功发布到Tomcat Server测试环境下了。

    点击Tomcat Server 7.0 选择”Start" 服务启动,你就可以在你的网页里输入“http://localhost:8080/MyServices/index.jsp"你就可以看到你的网页内容了。

   因为这个网站插图不方便,有时间再插一些图示吧。

二,关于cxf 框架的运行时序的个人思考过程:

     0.Tomcat启动时,加载web.xml,根据web.xml的配置,把CXF 的Servlet 放到Tomcat的侦听端口的映射中,同时也把Spring的Bean加载器也加载到Tomcat的进程空间中,Spring根据初始化的配置文件(比如application-context.xml),加载Bean对象。在加载过程中,会根据配置文件中的xml中的xmlns进行分析(比如,...xmlns:jaxrs ="http://cxf.apache.com", 先到

spring的handlers配置文件中,根据“http://cxf.apache.com"字符串找到对映的handler组件,用这个组件加载所有配置文件中,以jawrs为xml命名空间的配置部分,比如,<jaxrs:server id="services" address="/">     <jaxrs:serviceBeans>       <bean class="com.services.rest.HelloWorld" />     </jaxrs:serviceBeans>     <jaxrs:providers>  可参考:http://blog.csdn.net/javabenface/article/details/7441923)调用对应的加载器进行解释加载,这里调用cxf的加载器进行加载。cxf加载器会根据 beans.xml中对应的项加载最终实现的class文件,这些class在对应的java源文件编译过程中,根据java文件中的annomation标记符进行处理,使得这些class加载时形成正确的path 与对象的映射。

     1.客户端发出请求,通过XML/HTTP把请求及参数对象转为XML经过HTTP传到Servlet容器中。

     2.CXF会根据Path与对象的映射找到正确的对象,如果是Restful Web Service还会再根据映射找到Path中对应的执行方法。

三,创建一个基于CXF及Spring的SOAP Web Service:

     1.创建Web Service 相关的类:

       因为这种类型Web Service是SOA(面象服务架构)的,所以是提供一个远程的RPC接口。所以首先要有一个接口,当然,在服务端要提供真正的服务,所以要有一个这个接口在服务端的实现。下面分别实现:

 IHelloWorld.java:  

package com.services.soap;

import javax.jws.WebParam;

import javax.jws.WebService;

@WebService 

public interface IHelloWorld {

        public String speakoutUserInfo(@WebParam(name = "param") ParamDTO obj);

}

HelloWorld.java:

package com.services.soap;

import javax.jws.WebService;

/**  *   * 使用@WebService指向Interface定义类即可.  */ 

@WebService(endpointInterface = "com.services.soap.IHelloWorld") 

public class HelloWorld implements IHelloWorld{

 @Override

 public String speakoutUserInfo(ParamDTO obj) {

  // TODO Auto-generated method stub

        return "hello";  

}

}

上述的服务实现用到一个对象,这个对象可以做为参数远程进行传递,一般叫做DTO(数据传输对象)。当然你可以不用对象,用普通的数据类型这个实例一次性都表现一下。

ParamDTO.java:

package com.services.soap;

import javax.xml.bind.annotation.XmlAccessorType;

import javax.xml.bind.annotation.XmlAccessType;

import javax.xml.bind.annotation.XmlType;

/**  

* Web Service传输信息的DTO.  

* 分离entity类与web service接口间的耦合,隔绝entity类的修改对接口的影响. 使用JAXB 2.0的annotation标注JAVA-XML映射,尽量使用默认约定.  *   

*/ 

@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "User") 

public class ParamDTO  {

        protected Integer id;

        protected String name; 

         public Integer getId()      {

              return id;

        }

        public void setId(Integer value)      {

              id = value;

       }

        public String getName()      {

              return name;

      }

        public void setName(String value)      {

             name = value;

      } 

}

2.在配置文件中体映射这个Service:

我们定义这个Beans.xml

<?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:jaxws="http://cxf.apache.org/jaxws
    xsi:schemaLocation=" 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">   
    <jaxws:endpoint id="webServiceHelloWorld" 
        address="/HelloWorld" implementor="com.services.soap.HelloWorld"/> 
</beans> 

这个Beans.xml放到Spring的加载Beans的配置文件中被引用:

applicationContext.xml:

<?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.5.xsd"> 
    <import resource="classpath*:META-INF/cxf/cxf.xml" /> 
    <import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" /> 
    <import resource="classpath*:META-INF/cxf/cxf-servlet.xml" /> 
    <import resource="classpath:beans.xml" />  //注意这行代码的引用
   
</beans> 

当然我们要在Web.xml中配置Spring:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>webrest</display-name>
 
    <context-param> 
        <param-name>contextConfigLocation</param-name> 
        <param-value>WEB-INF/classes/applicationContext.xml</param-value> 
    </context-param> 
    <listener> 
        <listener-class> 
            org.springframework.web.context.ContextLoaderListener 
        </listener-class> 
    </listener> 
    <servlet> 
        <servlet-name>CXFServlet</servlet-name> 
        <servlet-class> 
            org.apache.cxf.transport.servlet.CXFServlet 
        </servlet-class> 
    </servlet> 
    <servlet-mapping> 
        <servlet-name>CXFServlet</servlet-name> 
        <url-pattern>/*</url-pattern> 
    </servlet-mapping> 
 
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

也可参考http://www.cnblogs.com/hoojo/archive/2011/03/30/1999563.html提供了另一种相似的配置方式。

四,创建一个基于CXF及Spring的Restful Web Service:

  这个就相对简单了。因为经不需要直接接供RPC接口给客户端,只是其于ROA的方式提供资源的操作,可以理解为基于一些xml,json的表达一些资源对象变态变化的传输同步给远程服务。

  所以通过xml映射对象,Annomation进行直接映射方法与path.所以直接写实现类就行了,当然cxf还有别的框架有其它的映射或配置方式。

 a.代码实现:

  先上代码:

 HelloWorld.java

package com.services.rest;

 import javax.ws.rs.Consumes;

 import javax.ws.rs.GET;

 import javax.ws.rs.POST;

 import javax.ws.rs.Path;

 import javax.ws.rs.PathParam;

 import javax.ws.rs.Produces;

 import javax.ws.rs.core.Response;

 import org.codehaus.jackson.jaxrs.JacksonJsonProvider;  

 @Path("/hello")

 public class HelloWorld {

     @GET

     @Path("/echo/{input}")

     @Produces("text/plain")

     public String ping(@PathParam("input") String input) {

         return input + ":in server!";

     }

     @POST

     @Produces("application/json")

     @Consumes("application/json")

     @Path("/jsonBean")

     public Response modifyJson(JsonBean input) {

            input.setCommand(222);

            input.getParam().put("content", "welcome to server!");

           return Response.ok().entity(input).build();

     }

}

其中用到JsonBean对象这个是可以远程传送参数对象,一般情况无需特别的定义。就可以直接用了。我这里定义如下:

JsonBean:

package com.services.rest;

import java.util.Map;

public class JsonBean {

 private Integer command;

 private Integer protocolVersion;

 private String  platformType;

 private Map<String, Object> param;

 public Integer getCommand() {

    return command;

 }

 public void setCommand(Integer command) {

     this.command = command;

 }

 public Integer getProtocolVersion() {

     return protocolVersion;

 }

 public void setProtocolVersion(Integer protocolVersion) {

     this.protocolVersion = protocolVersion;

 }

 public String getPlatformType() {

     return platformType;

 }

 public void setPlatformType(String platformType) {

    this.platformType = platformType;

 }

 public Map<String, Object> getParam() {

     return param;

 }

 public void setParam(Map<String, Object> param) {

     this.param = param;

 }

 }

 b.进行发布:

配置一个rest-services.xml进行映射:

<?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:jaxrs="http://cxf.apache.org/jaxrs"   xmlns:context="http://www.springframework.org/schema/context"   xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

  <import resource="classpath:META-INF/cxf/cxf.xml" />

  <context:property-placeholder/>   <context:annotation-config/>   <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"/>   <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"/>

   <jaxrs:server id="services" address="/">     <jaxrs:serviceBeans>       <bean class="com.services.rest.HelloWorld" />     </jaxrs:serviceBeans>     <jaxrs:providers>         <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>     </jaxrs:providers>     </jaxrs:server>

</beans>

在Spring的加载配置文件(applicationContext.xml)里引入:

<?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.5.xsd"> 
    <import resource="classpath*:META-INF/cxf/cxf.xml" /> 
    <import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" /> 
    <import resource="classpath*:META-INF/cxf/cxf-servlet.xml" />  
    <import resource="classpath:rest-services.xml" />
</beans>

OK,大功告成。

到时此我们能把这两种模式的Web Service同时在一个框架里发布吗?当然可以:)要做的只有一步,就是在上面的applicationContext.xml里同时加载两个Service的映射文件就可以了。

<?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.5.xsd"> 
    <import resource="classpath*:META-INF/cxf/cxf.xml" /> 
    <import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" /> 
    <import resource="classpath*:META-INF/cxf/cxf-servlet.xml" /> 

    <import resource="classpath:beans.xml" />
    <import resource="classpath:rest-services.xml" />
</beans>

现在就你就可以编译完成,Publish到你的tomcat上进行测试了,不过一定要注意,在发布选项里一定要把你项目工程中引用的jar依赖库(比如,cxf相关,spring相关的,Json相关的)同时发布到你的Tomcat Server的运行环境里,这里只需要修改:项目(MyServices)右键=》Properties=>Deployment Assembly=>Add=>Java Build Path Entries 不过在引入的jar过多时可能会造成冲突,假如在测试时,说CXF 的一个Discoveryxxx对象..... Null Point之类的错误:

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'bookservice': Invocation of init method failed; nested exception is org.apache.cxf.service.factory.ServiceConstructionException
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:
1422)
        .......

        Caused by: org.apache.cxf.service.factory.ServiceConstructionException
        at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:
201)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      
        ...

 Caused by: java.lang.NullPointerException
        at org.apache.cxf.ws.discovery.listeners.WSDiscoveryServerListener.startServer(WSDiscoveryServerListener.java:
64)
        at org.apache.cxf.bus.managers.ServerLifeCycleManagerImpl.startServer(ServerLifeCycleManagerImpl.java:
61)
        at org.apache.cxf.endpoint.ServerImpl.start(ServerImpl.java:
146)
        at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:
192)
          ........

就是最常见的cxf-services-ws-discovery-service-2.x.x.jar冲突,去掉这个.jar的依赖即可。如果你在项目的Java Build Path中去掉这个jar仍不行,就去你测试的Tocat Server上右键“clean" 然后再"Publish",如果这样还不行,说明是Eclipse 清除Tomcat的发布目录不彻底(Eclipse也有很多bug的),你就去Tomcat 的运行时临时Web根目录中去清除这个jar.这个目录是在Eclipse的Workspace目录下的”.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps“子目录。现在估计你能理解为什么你在Eclipse 的runtime server中用Tomcat测试发布后的文件在Tomcat的安装目录看不到的原因了吧?呵呵,因为Eclipse整合tomcat测试运行时,根本上会使用自己的临时目录作为Tomcat的运行时Web根目录。

如果你遇到:

Caused by: java.lang.NullPointerException

Class Could not found: org.springframework.web.context.ContextLoaderListener 之类的错误。你需要在你的Web project的Deployment Assemblly 中 加入Java build path的库,即点击"Add"按钮,在弹出列表窗口中选择“Java Build Path Entries"然后选中你的工程发布所需要的库即可。

到这里应该完成了。

下面就可以用各种客户端或者浏览器进行访问了,这里主要讲方法,可能部分代码在相关的博文里面附上了:

0.测试工具:

   对于restful web service因为返回的内容都可以简单的分析,所以可以用很多工具进行测试。

a. 基于firefox的 Poster

b.linux上的curl.

c.......

1.Native 客户端访问方法:

  用Java的NIO中的HttpClient就可以搞定 Restful Web Service.

a.cxf的WebClient接口:

 cxf提供了访问WebService的所有接口,例子代码如下:

import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
public
class RSETClient {

    private static WebClient client;

    public void init() {
         client = new WebClient("http://localhost:8080/restWeb/hello/teststring");

    }

    public void testGet() {

        System.out.println(client.path("sample").accept(MediaType.TEXT_PLAIN).get(String.class));
  }
}

b.Spring RestTemplate:

这个可以通过在客户端使用Spring 的RestTemplate 相关的库来访问。

 下面代码是用Spring for Android写的,PC各平台上调用大同小异,没时间在这里上代码了。

 HttpHeaders reqHeader = new HttpHeaders();
  reqHeader.setContentType(new MediaType("text", "plain"));
  HttpEntity<String> req = new HttpEntity<String>(reqHeader);
  String restUrl = "http://192.168.2.100:8080/webrest/hello/echo/testtest";// 这个地址要根据你Restful
                     // 服务器来定
  // 好戏上场了,呵呵
  RestTemplate restTemplate = new RestTemplate(true);
  
  //restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
  ResponseEntity<String> response = restTemplate.exchange(restUrl,
    HttpMethod.GET, req, String.class);
  String msgBody = response.getBody();

 System.out.println(msgBody);

2.浏览器测试:

a.可以通过Form进行简单的访问。

b. 可以通过客户端的Ajax代码来访问Restful Webservice.

可以通过客户端的Ajax代码来访问Restful Webservice.

3.手机端访问方法(访问代码见我的相关手机客户端的博文):

a.Android端:

 可以使用Android自带的HttpClient进行访问Restful Web Service。这就是Restful Web Service的优势可以一些平台上最基本的http 库来访问。

 可以使用第三方库KSoap来访问基于Soap的Web Service.

 同时你可以用Spring for Android 中的RestTemplate接口来访问 Restful Web service :

HttpHeaders reqHeader = new HttpHeaders();

  reqHeader.setContentType(new MediaType("text", "plain"));

  HttpEntity<String> req = new HttpEntity<String>(reqHeader);

  String restUrl = "http://192.168.2.100:8080/webrest/hello/echo/testtest";// 这个地址要根据你Restful

   // 服务器来定   // 好戏上场了,呵呵

  RestTemplate restTemplate = new RestTemplate(true);

    //restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

  ResponseEntity<String> response = restTemplate.exchange(restUrl,     HttpMethod.GET, req, String.class);

  String msgBody = response.getBody();

  System.out.println(msgBody);

b.IOS端:

可以使用IOS上的第三方Http库来访问 Restful Web Service,库名字叫:。