本节将实践目前最流行的第二种web service 发布和调试框架 CXF
Apache CXF 是一个开放源代码框架,提供了用于方便地构建和开发 Web 服务的可靠基础架构。它允许创建高性能和可扩展的服务,您可以将这样的服务部署在 Tomcat 和基于 Spring 的轻量级容器中,以及部署在更高级的服务器上。Java的webService实现本身就是一个很耗性能的实现方案(xml与java对象之间在服务端以及客户端的互转比较消耗性能),目前java主流的webService应用以CXF、AXIS2为主,CXF比AXIS2效率更高,并且在java 应用中CXF很成熟,因此CXF在webservice中占有非常重要的地位。
下面一张网络上的图比较好的说明了CXF 与web service的关系
下面将具体说说如何使用CXF 进行Webservice 开发。关于CXF的实践分2篇,
第一篇通过注解发布webservice,利用cxf 进行客户端开发。
第二篇:通过spring与cxf 结合进行发布
前面已经学习了使用JDK发布WebService本文内容,下面学习cxf框架完成服务器发布 和 客户端开发
需要准备环境 myeclipse 和 cxf 包 (我是用的Myeclipse2017 和 apache-cxf-3.1.15.zip的cxf包、jdk 1.8 环境 -- ps:apache-cxf-3.2.4.zip 版本太高,报错 好像跟jdk版本有关系,所以用了 apache-cxf-3.1.15.zip的cxf包)
1、服务端发布方式:用cxf 框架方式
1、首先在myeclipse中创建一个java web project
工程里面的类分别是Student.java StudentDAO.java StudentDAOImpl.java StudentWs.java StudentWsImpl.java,
本文的Student对象用的是单例模式
这里重点贴一下 StudentWs.java 和 StudentWsImpl.java. StudentWs是暴露的接口类,也是web service 服务接口, 实现类是服务的实现。
项目结构如下图
需要的jar包
我用的是apache-cxf-3.2.4 在lib里面拿过来的
基本代码如下:
Student.java 类
package com.myl.entity; /** * * @author maoyl * @date 2018.4.15 * 实体类 * */ public class Student { private String name; private String sex; private String brithday; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getBrithday() { return brithday; } public void setBrithday(String brithday) { this.brithday = brithday; } }
GetStudentUtil.java
package com.myl.entity; /** * * @author myl * @date 2018.4.15 * 单例获取Student * */ public class GetStudentUtil { private static Student student = new Student(); private GetStudentUtil(){ } public static Student getStudent(){ return student; } }
StudentDao.java
package com.myl.dao; import com.myl.entity.Student; /** * * @author myl * @date 2018.4.15 * Dao层接口 * */ public interface StudentDao { public boolean addStudentDao(String name, String sex, String brithday); public Student queryStudentDao(String name); }
StudentDaoImpl.java
package com.myl.dao.daoImpl; import com.myl.dao.StudentDao; import com.myl.entity.GetStudentUtil; import com.myl.entity.Student; /** * * @author myl * @date 2018.4.15 * Dao层实现类 * */ public class StudentDaoImpl implements StudentDao { public Student student; @Override public boolean addStudentDao(String name, String sex, String brithday) { student = GetStudentUtil.getStudent(); System.out.println("student是否为空--"+student); System.out.println(student.getName()); System.out.println(); student.setName(name); student.setSex(sex); student.setBrithday(brithday); return true; } @Override public Student queryStudentDao(String name) { student = GetStudentUtil.getStudent(); //代替DB // student.setName("mao"); // student.setSex("boy"); // student.setBrithday("22"); System.out.println("------查询学生-------"); if(name == null){ System.out.print("输入为学生名称为null"); return null; } if(!name.equals(student.getName())){ System.out.println("没有此人"); student =null; } System.out.println("返回student------------------"); return student; } }
StudentWs.java
package com.myl.service; import com.myl.entity.Student; /** * * @author myl * @date 2018.4.15 * service层接口 * */ public interface StudentWs { public boolean addStudentService(String name, String sex, String brithday); public Student queryStudentService(String name); }
StudentWsImpl.java
package com.myl.service.serviceImpl; import javax.jws.WebMethod; import javax.jws.WebService; import com.myl.dao.StudentDao; import com.myl.dao.daoImpl.StudentDaoImpl; import com.myl.entity.Student; import com.myl.service.StudentWs; /** * * @author myl * @date 2018.4.15 * service层实现类,也是暴露给客户端的接口 * exclude = true表示不暴露给客户端 * @WebMethod(operationName = "queryStudentService") 标注自定义方法 * @WebMethod 默认为该方法名 * */ @WebService public class StudentWsImpl implements StudentWs { public StudentDao studentDao; // @WebMethod(exclude = true) // public StudentDao getStudentDao() { // return studentDao; // } // // @WebMethod(exclude = true) // public void setStudentDao(StudentDao studentDao) { // this.studentDao = studentDao; // } public StudentWsImpl() { studentDao = new StudentDaoImpl(); } @WebMethod @Override public boolean addStudentService(String name, String sex, String brithday) { System.out.println("addStudent-------------"); boolean result = studentDao.addStudentDao(name, sex, brithday); return result; } @WebMethod(operationName = "queryStudentService") @Override public Student queryStudentService(String name) { System.out.println("queryStudent-----------"); Student student = studentDao.queryStudentDao(name); return student; } }
StudentTest.java
package com.myl.test.publish; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; import com.myl.service.serviceImpl.StudentWsImpl; /** * * @author myl * @date 2018年4月15日 下午11:26:50 * 服务端发布接口 */ public class StudentTest { public static void main(String[] args) { System.out.println("web service start"); //获取工厂对象 JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean(); //这里必须传入class,不能是接口,否则客户端会报异常 Could not instantiate service class ... because it is an interface factory.setServiceClass(StudentWsImpl.class); //传入接口url factory.setAddress("http://localhost:5555/studentws"); //创建接口 Server server = factory.create(); //启动接口 server.start(); System.out.println("web service started"); } }
测试发布如下图表示成功
访问http://localhost:5555/studentws?wsdl得到下图所示 ps:如果测试服务端和客户端不在同一个的机器上则localhost应该是本机的IP地址
2、使用CXF 进行 客户端开发
为客户端加上cxf需要的jar包,否则运行会报错误
这些是使用cxf 里面的工具wsdl2java 生成的java类。在命令行执行下面命令,就可以生成这些类
D:用户目录下载apache-cxf-3.1.15in>wsdl2java -p com.webservice http://localhost:8080/studentws?wsdl
如下图所示生成客户端代码成功:在本目录下 com.webservice中
wsdl2java用法: wsdl2java -p com -d src -all wsdl -p 指定其wsdl的命名空间,也就是要生成代码的包名 -d 指定要产生代码所在目录 -client 生成客户端测试web service的代码 -server 生成服务器启动web service的代码 -impl 生成web service的实现代码 -ant 生成build.xml文件 -all 生成所有开始端点代码:types,service proxy,,service interface, server mainline, client mainline, implementation object, and an Ant build.xml file.
把生成的代码放的客户端项目中
编写客户端代码
package com.myl.test.service; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import com.webservice.StudentWsImpl; /** * @author myl * @date 2018年4月15日 * 客户端调用服务端发布的接口 */ public class StudentSerivceTest { public static void main(String[] args) { //获取工厂对象 JaxWsProxyFactoryBean jwpfb = new JaxWsProxyFactoryBean(); //加载生成的StudentWsImpl类 jwpfb.setServiceClass(StudentWsImpl.class); //传入url接口地址 jwpfb.setAddress("http://localhost:5555/studentws?wsdl"); //创建接口对象 StudentWsImpl ws = (StudentWsImpl) jwpfb.create(); //调用接口中的方法 ws.addStudentService("mao", "11", "22"); ws.addStudentService("ya", "15", "23"); ws.queryStudentService("mao"); ws.queryStudentService("ya"); } }
运行客户端如图所示(每个方法中随便输出点东西)
以上即为cxf框架完成webservice的方法
-------------------------------------------------------------------------------------------
遇到问题:
1、开始我下载的apache-cxf-3.2.4版本的cxf,运行报错
解决方法:
应该是cxf版本太高,跟jdk1.8的版本有关,于是换了apache-cxf-3.1.15版本的既可以了
2、cxf(3.1.15) 客户端异常 请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。
原因是:使用wsdk2java生成客户端文件的时候根据源文件生成了客户端代码,方法名字重复
解决方法
生成代码的时候 使用 -p com.webservice重命名报名即可
---------
网上找的方法
(1)最佳方案包名createTask 改成 全部小写 createtask
(2)或者生成代码的时候 使用 -p com.service.createtask 重命名报名即可
(3)第三那种解决方案不建议,把createTask.java中的 @XmlType(name = "CreateTask", propOrder = { "arg0"}) 中的name 改成 createTask 即可