WebService (三)使用CXF框架开发webservice
1、CXF框架概念介绍
Apache CXF 是一个开源的 Services 框架,CXF 帮助您来构建和开发 Services 这些 Services 可以支持多种协议,比如:SOAP、POST/HTTP、RESTful HTTP CXF 大大简化了 Service可以天然地和 Spring 进行无缝集成。
1、1ServerFactoryBean来发布web服务
服务类代码如下:
// 注解是无效的 @WebService(name="Hello",targetNamespace="http://icast.cn") public class HelloWorld { public String sayHi(String name) { return "hello---->" + name; } } |
发布类代码如下:
public static void main(String[] args) { // 发布服务的类, 类似Endpoint ServerFactoryBean serverFactoryBean=new ServerFactoryBean(); // 注册服务器地址和端口 serverFactoryBean.setAddress("http://127.0.0.1:9999/hello"); // 注册哪个类提供服务 serverFactoryBean.setServiceBean(new HelloWorld()); // 发布一个cxf服务 serverFactoryBean.create(); // 一分钟有服务终止 Thread.sleep(1 * 60 * 1000); // 正常退出程序 System.exit(0); } |
ServerFactoryBean注意事项:
这种方式没有添加webService注解,也就是说没有注解也可以发布webService服务,但是这种方式不是很规范,比如我们不可以通过注解的方式来修改WSDL的标签信息,
1、2JaxWsServerFactoryBean来发布web服务
1. JaxWsServerFactoryBean是ServerFactoryBean的子类,也是功能扩展类。
2. 此类,必须要在被发布为服务的类上添加@WebService注解,如果不加注解,虽然不出错,但也不会对外暴露任何方法。使用此类生成的wsdl文件更加规范
3. 更重要的是可以通过添加拦截器拦截请求.
客户端代码如下:
@WebService public class HelloWorld { public String sayHi(String name) { return "hello---->" + name; } } |
发布类代码如下:
public static void main(String[] args)throws Exception { // 发布服务的类, 类似Endpoint JaxWsServerFactoryBean jaxWsServer=new JaxWsServerFactoryBean(); // 注册服务器地址和端口 jaxWsServer.setAddress("http://127.0.0.1:9999/hello"); // 注册哪个类提供服务 jaxWsServer.setServiceBean(new HelloWorld()); // 配置输入输出日志拦截器 jaxWsServer.getInInterceptors().add(new LoggingInInterceptor()); jaxWsServer.getOutInterceptors().add(new LoggingOutInterceptor()); // 发布一个cxf服务 jaxWsServer.create(); // 一分钟有服务终止 Thread.sleep(1 * 60 * 1000); // 正常退出程序 System.exit(0); } |
访问:http://127.0.0.1:9999/hello?wsdl 控制台第一次握手拦截器日志如下:
---------------------------- ID: 1 Address: http://127.0.0.1:9999/hello?wsdl Http-Method: GET Content-Type: Headers: {Accept=[*/*], accept-encoding=[gzip, deflate], Accept-Language=[zh-CN], connection=[Keep-Alive], Content-Type=[null], Host=[127.0.0.1:9999], User-Agent=[Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)]} -------------------------------------- |
通过Java客户端调用服务类
public static void main(String[] args) { HelloWorldService helloWorldService=new HelloWorldService(); HelloWorld helloWorld=helloWorldService.getHelloWorldPort(); System.out.println(helloWorld.sayHi("test")); } |
拦截器日志如下:
---------------------------- ID: 1 Address: http://127.0.0.1:9999/hello?wsdl Http-Method: GET Content-Type: text/xml Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], content-type=[text/xml], Host=[127.0.0.1:9999], Pragma=[no-cache], User-Agent=[Apache CXF 2.4.2]} -------------------------------------- 2013-1-6 11:28:17 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Inbound Message ---------------------------- ID: 2 Address: http://127.0.0.1:9999/hello Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[191], content-type=[text/xml; charset=UTF-8], Host=[127.0.0.1:9999], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 2.4.2]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi xmlns:ns2="http://jaxws.cxf.g.itcast.cn/"><arg0>test</arg0></ns2:sayHi></soap:Body></soap:Envelope> -------------------------------------- 2013-1-6 11:28:17 org.apache.cxf.interceptor.AbstractLoggingInterceptor log 信息: Outbound Message --------------------------- ID: 2 Encoding: UTF-8 Content-Type: text/xml Headers: {} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://jaxws.cxf.g.itcast.cn/"><return>hello---->test</return></ns2:sayHiResponse></soap:Body></soap:Envelope> -------------------------------------- |
1、3CXF与Spring集成发布WebService
前面的服务发布包括创建服务类都是硬编码的方式.是否可以使用配置的方式来发布服务类呢. 答案是肯定的这就要同Spring集成了, 由于cxf的项目已经集成了Spring(自带了Spring lib)所以CXF的服务都是在Spring的配置文件中完成的, 并且我们需要把项目发布到tomcat中,所以我们可以创建一个web项目
配置开发环境:
l 建立一个web项目
l 准备所有jar包,将CXF_HOME\lib项目下的所有jar包,全部都拷贝新项目的lib目录下.其中里面已经包含了Sring3.0的jar包 其中jetty 服务器的包可以不要.因为我们要部署的tomcat服务器中了
l 在web.xml中配置cxf的核心servlet,CXFServlet
l 此配置文件的作用类 拦截/ws/*的所有请求 类似Struts2的过滤器
<servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> |
通过Spring配置文件发布服务
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- 这样配置自身的服务也可以使用 --> <bean id="userImpl" class="cn.itcast.i.cxf.spring.ws.UserImpl" /> <!-- id:逻辑名 serviceClass=服务接口类 address:调用的路径 http://localhost:8888/项目名/ws/hello?wsdl> --> <jaxws:server id="userService" serviceClass="cn.itcast.i.cxf.spring.ws.IUser" address="/hello"> <jaxws:serviceBean> <ref bean="userImpl" /> </jaxws:serviceBean> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" /> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> </jaxws:outInterceptors> </jaxws:server> </beans> |
服务接口如下:
@WebService public interface IUser { public void saveUser(User user); public User getUser(int uid); } |
服务类如下:
public class UserImpl implements IUser { private List<User> users=new ArrayList<User>();
public User getUser(int uid) { for(User temp:users){ if(temp.getUid()==uid){ return temp; } } return null; } public void saveUser(User user) { // TODO Auto-generated method stub users.add(user); } } |
实体类如下:
public class User { private int uid; private String uname; public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } } |
通过JSP+Servlet调用本地服务:
Servlet在web.xml中配置如下:
<servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>cn.itcast.i.cxf.servlet.UserServlet</servlet-clas> </servlet> |
Servlet核心代码调用如下:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User user = new User(); user.setUid(Integer.parseInt(request.getParameter("uid"))); user.setUname(request.getParameter("uname")); userImpl.saveUser(user); } public void init() throws ServletException { // Put your code here WebApplicationContext springContext = WebApplicationContextUtils .getWebApplicationContext(this.getServletContext()); userImpl = (IUser) springContext.getBean("userImpl"); } |
WEB页面调用代码如下:
<form action="/day01/servlet/UserServlet" method="post"> 用户编号:<input type="text" name="uid" /><br/> 用户名:<input type="text" name="uname" /><br/> <input type="submit" value="提交" /> </form> |
通过Java远程调用访问CXF+Spring服务如下:
public static void main(String[] args) { IUserService userService=new IUserService(); User user=new User(); user.setUid(1); user.setUname("admin"); userService.getIUserPort().saveUser(user); User temp=userService.getIUserPort().getUser(1); System.out.println(temp.getUid() + "|" + temp.getUname()); } |
通过ajax远程调用访问CXF+Spring服务如下:
<body> <button οnclick="mobile()">cxf+Spring测试</button> </body> <script language="javascript"> // 1:创建XMLHTTP对象 var xhr=null; function mobile(){ // 声明在访问的ws的地址 var url="http://localhost:8888/day01/ws/hello"; // 书写要发送的XML文件,即 SOAP var soap='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>' + '<ns2:getUser xmlns:ns2="http://ws.spring.cxf.i.itcast.cn/"><arg0>1</arg0></ns2:getUser></soap:Body></soap:Envelope>'; // 3:打开连接 xhr.open("POST",url,true); xhr.setRequestHeader("Content-Type","text/xml; charset=utf-8"); xhr.setRequestHeader("Accept","*/*"); xhr.onreadystatechange=callBack; xhr.send(soap); } function callBack(){ if(xhr.readyState==4){ var a=xhr.responseXML; alert(xhr.responseXML.getElementsByTagName("uid")[0].text); alert(xhr.responseXML.getElementsByTagName("uname")[0].text); } } function init(){ xhr=new ActiveXObject("MSXML2.XMLHTTP.3.0"); } init(); </script> |