【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)
转载:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.html
一,选择一个合适的,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.xsdhttp://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,库名字叫:。
【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)的更多相关文章
- Java——搭建自己的RESTful API服务器(SpringBoot、Groovy)
这又是一篇JavaWeb相关的博客,内容涉及: SpringBoot:微框架,提供快速构建服务的功能 SpringMVC:Struts的替代者 MyBatis:数据库操作库 Groovy:能与Java ...
- 基于 Hexo 从零开始搭建个人博客(五)
阅读本篇前,请先阅读前几篇文章: 基于 Hexo 从零开始搭建个人博客(一) 基于 Hexo 从零开始搭建个人博客(二) 基于 Hexo 从零开始搭建个人博客(三) 基于 Hexo 从零开始搭建个人博 ...
- 基于cxf开发restful风格的Web Service
一.写在前面 webservice一些简单的其他用法和概念,就不在这里赘述了,相信大家都可以在网上查到,我也是一个新手,写这篇文章的目的一方面是想记录自己成长的历程,另一方面是因为学习这个的时候花了点 ...
- 开发基于CXF的 RESTful WebService web 项目 webservice发布
配置步骤 开发基于CXF的 RESTful WebService 1.创建Web项目并导入CXF的jar 2.在Web.xml中配置 CXFServlet <servlet> <se ...
- 基于jersey和Apache Tomcat构建Restful Web服务(一)
基于jersey和Apache Tomcat构建Restful Web服务(一) 现如今,RESTful架构已然成为了最流行的一种互联网软件架构,它结构清晰.符合标准.易于理解.扩展方便,所以得到越来 ...
- 基于jersey和Apache Tomcat构建Restful Web服务(二)
基于jersey和Apache Tomcat构建Restful Web服务(二) 上篇博客介绍了REST以及Jersey并使用其搭建了一个简单的“Hello World”,那么本次呢,再来点有趣的东西 ...
- 基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置
经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - ...
- Java Web学习总结(20)——基于ZooKeeper的分布式session实现
1. 认识ZooKeeper ZooKeeper-- "动物园管理员".动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始 ...
- 基于Flask框架搭建视频网站的学习日志(三)之原始web表单
基于Flask框架搭建视频网站的学习日志(三)1.原始Web 表单 本节主要用于体验一下前端后端直接数据的交互,样例不是太完善,下一节会加入Flash处理,稍微完善一下页面 (备注:建议先阅读廖雪峰老 ...
随机推荐
- 生成月初月末便于拼接sql
for ($i=1; $i < 13; $i++) { $date = strtotime(date("2015-$i-01")); $firstday = date(&qu ...
- java利用16进制来辨别png格式的图片
很多人知道利用.png的字符串结尾可以判断前端传入的图片是否为png格式,但是这只是潜意识的判断!那么如何利用png读写的特殊内容来深意识地判断图片格式呢?最近在做东西的时候遇到了点问题,在加载图片的 ...
- 解决JS传参中文乱码
function PopupFK(cNum,type){ var url = "contract!Paying.action"; url = url + "?contra ...
- nginx用户认证配置( Basic HTTP authentication)
ngx_http_auth_basic_module模块实现让访问着,只有输入正确的用户密码才允许访问web内容.web上的一些内容不想被其他人知道,但是又想让部分人看到.nginx的http aut ...
- const成员函数
尽管函数名和参数列表都相同,void foo( ) const成员函数是可以与void foo( )并存的,可以形成重载! 我们假设调用语句为obj.foo(),如果obj为non-const对象,则 ...
- .NET中的流
当应用程序需要和磁盘上的文件打交道的时候,就有了流的概念.流就像架设在应用程序所在内存和磁盘之间的一个管道. 大致思路 → 建立管道 //FileMode.Open打开现有文件,另外还有FileMod ...
- 努力学习 HTML5 (2)—— 元素的增和删
HTML5 放松了某些规则,HTML5 的制定者想让这门语言更紧密地反映浏览器的现实. 放松的规则 不要求包含 <html>.<head> 和 <body> 元素. ...
- 解决chi_sim.traineddata报read_params_file: parameter not found: allow_blob_division
在使用语音库时候 遇到报错:allow_blob_division,例如使用chi_sim.traineddata;在chi_sim.traineddata(注意版本)文件目录下,使用命令行执行: c ...
- TCP/IP 端口号大全
常用端口: 20 ftp-data FTP 数据端口 21 ftp 文件传输协议(FTP)端口:有时被文件服务协议(FSP)使用 22 ssh 安全 Shell(SSH)服务 23 telnet T ...
- Codeforces Round #384 (Div. 2)B. Chloe and the sequence 数学
B. Chloe and the sequence 题目链接 http://codeforces.com/contest/743/problem/B 题面 Chloe, the same as Vla ...