---------==========--服务端发布webservice-=============--------
1.需要的jar包:
2.包结构
3.代码
1.实体类
package cn.qlq.domain; public class User { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User [username=" + username + ", password=" + password + "]"; } }
2.dao代码:
package cn.qlq.dao; import java.sql.SQLException; import cn.qlq.domain.User; public interface UserDao { /** * 保存用户 * * @param user * @return * @throws SQLException */ public int saveUser(User user) throws SQLException; /** * 根据userId获取user * * @param userId * @return */ public User getUserById(int userId); }
package cn.qlq.dao.impl; import java.sql.SQLException; import org.springframework.stereotype.Repository; import cn.qlq.dao.UserDao; import cn.qlq.domain.User; @Repository public class UserDaoImpl implements UserDao { public UserDaoImpl(){ System.out.println("=====生成userDao====="); } @Override public int saveUser(User user) throws SQLException { System.out.println("保存用户"); return 0; } @Override public User getUserById(int userId) { // 模拟从数据库取数据 User u = new User(); u.setUsername("qlq"); u.setPassword("123456"); return u; } }
3.service代码:
package cn.qlq.service; import java.sql.SQLException; import javax.jws.WebMethod; import javax.jws.WebService; import cn.qlq.domain.User; @WebService public interface UserService { /** * 保存用户 * * @param user * @return * @throws SQLException */ public int saveUser(User user) throws SQLException; /** * 根据userId获取user * * @param userId * @return */ @WebMethod public User getUserById(int userId); }
package cn.qlq.service.impl; import java.sql.SQLException; import javax.jws.WebService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.qlq.dao.UserDao; import cn.qlq.domain.User; import cn.qlq.service.UserService; @Service @WebService public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public int saveUser(User user) throws SQLException { System.out.println("----------------保存user----------"); return 0; } @Override public User getUserById(int userId) { return userDao.getUserById(userId); } }
4.配置文件
application.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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/jaxws http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 引cxf的一些核心配置 --> <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" /> <!-- 自动扫描dao和service包(自动注入) --> <context:component-scan base-package="cn.qlq" /> <jaxws:endpoint id="userWS" implementor="cn.qlq.service.impl.UserServiceImpl" address="/userws"> </jaxws:endpoint> </beans>
经测试:上面的import不需要也是可以的。 (而且最好不写上面三个)
web.xml
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>CXFTest</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.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> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/WS/*</url-pattern> </servlet-mapping> </web-app>
5.启动服务进行测试:
查看有哪些发布的webservice:
查看WSDL描述:
6.第二种xml配置发布webservice的配置可以
这种方式配置可以查看日志,也就是传的参数与返回值(XML格式的数据)都可以在日志中查看:
例如修改上面的application的配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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/jaxws http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 自动扫描dao和service包(自动注入) --> <context:component-scan base-package="cn.qlq" /> <!-- 配置cxf 地址: http://192.168.114.10:8080/CXF_Server/ws/employeeManager 组成 : http://192.168.114.10:8080 +CXF_Server( 项目名)+ws(过滤的路径)+/employeeManager(自定义部分) 服务类 : 服务的实现类: 拦截器 --> <jaxws:server address="/userws" serviceClass="cn.qlq.service.UserService"> <jaxws:serviceBean> <ref bean="userServiceImpl" /> </jaxws:serviceBean> <!-- 配置输入显示日志信息的拦截器 --> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:server> </beans>
启动服务查看有哪些发布的服务:
测试访问一个服务:
import javax.xml.namespace.QName; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class TestWS { public static void main(String[] args) throws Exception { JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); org.apache.cxf.endpoint.Client client = dcf.createClient("http://localhost/CXFTest/WS/userws?wsdl"); // url为调用webService的wsdl地址 QName name = new QName("http://service.qlq.cn/", "getAllUsers");// namespace是命名空间,methodName是方法名 Object[] objects; try { objects = client.invoke(name);// 第一个参数是上面的QName,第二个开始为参数,可变数组 System.out.println(objects[0].toString()); } catch (Exception e) { e.printStackTrace(); } } }
查看服务端日志(控制台):
---------------------------- ID: 1 Address: http://localhost/CXFTest/WS/userws?wsdl Http-Method: GET Content-Type: text/xml Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], content-type=[text/xml], host=[localhost], pragma=[no-cache], user-agent=[Apache CXF 2.7.4]} -------------------------------------- 九月 15, 2018 2:31:32 下午 org.apache.cxf.staxutils.StaxUtils createXMLInputFactory 警告: Could not create a secure Stax XMLInputFactory. Found class com.ctc.wstx.stax.WstxInputFactory. Suggest Woodstox 4.2.0 or newer. 九月 15, 2018 2:31:41 下午 org.apache.cxf.services.userService.UserServicePort.UserService 信息: Inbound Message ---------------------------- ID: 2 Address: http://localhost/CXFTest/WS/userws Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], Content-Length=[162], content-type=[text/xml; charset=UTF-8], host=[localhost], pragma=[no-cache], SOAPAction=[""], user-agent=[Apache CXF 2.7.4]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getAllUsers xmlns:ns2="http://service.qlq.cn/"/></soap:Body></soap:Envelope> -------------------------------------- 九月 15, 2018 2:31:42 下午 org.apache.cxf.services.userService.UserServicePort.UserService 信息: 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:getAllUsersResponse xmlns:ns2="http://service.qlq.cn/"><allUsers><password>0</password><username>0</username></allUsers><allUsers><password>1</password><username>1</username></allUsers><allUsers><password>2</password><username>2</username></allUsers></ns2:getAllUsersResponse></soap:Body></soap:Envelope> --------------------------------------
=========客户端使用webservice:============
无论哪种方式调用都会调用到发布的webservice的实现类的代码(项目中的代码)。也就是必须依赖tomcat服务器启动才能访问webservice的实现代码,如果tomcat没启动将访问不到wsdl。并且会报访问不到wsdl与连接拒绝的错误。
访问方式基本上有三种,生成本地代码、静态代理、动态代理。
1.利用JDK自带的工具生成代码到本地的方式进行(不依赖于CXF框架)
C:\Users\liqiang\Desktop>cd webservice C:\Users\liqiang\Desktop\webservice>wsimport http://localhost/CXFTest/WS/userws?wsdl parsing WSDL... Generating code... Compiling code...
会将代码生成到本地,如下:
打成jar包后使用:
C:\Users\liqiang\Desktop\webservice>jar cvf wstest.jar ./ 已添加清单 正在添加: cn/(输入 = 0) (输出 = 0)(存储了 0%) 正在添加: cn/qlq/(输入 = 0) (输出 = 0)(存储了 0%) 正在添加: cn/qlq/service/(输入 = 0) (输出 = 0)(存储了 0%) 正在添加: cn/qlq/service/GetUserById.class(输入 = 605) (输出 = 376)(压缩了 37%) 正在添加: cn/qlq/service/GetUserByIdResponse.class(输入 = 763) (输出 = 424)(压缩了 44%) 正在添加: cn/qlq/service/impl/(输入 = 0) (输出 = 0)(存储了 0%) 正在添加: cn/qlq/service/impl/SQLException.class(输入 = 788) (输出 = 422)(压缩了 46%) 正在添加: cn/qlq/service/impl/UserService.class(输入 = 1050) (输出 = 507)(压缩了 51%) 正在添加: cn/qlq/service/impl/UserServiceImplService.class(输入 = 2369) (输出 = 1050)(压缩了 正在添加: cn/qlq/service/ObjectFactory.class(输入 = 3124) (输出 = 1009)(压缩了 67%) 正在添加: cn/qlq/service/package-info.class(输入 = 242) (输出 = 195)(压缩了 19%) 正在添加: cn/qlq/service/SaveUser.class(输入 = 656) (输出 = 384)(压缩了 41%) 正在添加: cn/qlq/service/SaveUserResponse.class(输入 = 694) (输出 = 411)(压缩了 40%) 正在添加: cn/qlq/service/SQLException.class(输入 = 1036) (输出 = 525)(压缩了 49%) 正在添加: cn/qlq/service/User.class(输入 = 798) (输出 = 434)(压缩了 45%)
导入eclipse中测试:
测试代码:
import cn.qlq.service.User; import cn.qlq.service.impl.UserService; import cn.qlq.service.impl.UserServiceImplService; public class TestWS { public static void main(String[] args) { UserServiceImplService us = new UserServiceImplService(); UserService userService = us.getUserServiceImplPort(); User user = userService.getUserById(0); System.out.println(user.getUsername()+"\t"+user.getPassword()); } }
结果:
qlq 123456
2.第二种方式:静态代理:(依赖于CXF框架,而且需要将接口写在对应包下---与webservice保持一致)
目录结构:
jar包:
测试类:
import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import cn.qlq.domain.User; import cn.qlq.service.UserService; public class TestWS { public static void main(String[] args) throws Exception { // 创建WebService客户端代理工厂 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); // 判断是否抛出异常 factory.getOutInterceptors().add(new LoggingInInterceptor()); // 注册webservice接口 factory.setServiceClass(UserService.class); // 配置webservice地址 factory.setAddress("http://localhost/CXFTest/WS/userws?wsdl"); // 获得接口对象 UserService service = (UserService) factory.create(); // 调用接口方法 User user = service.getUserById(5); // 关闭接口连接 System.out.println(user.getUsername() + "\t" + user.getPassword()); } }
结果:
qlq 123456
3.动态调用:(推荐这种)
import javax.xml.namespace.QName; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class TestWS { public static void main(String[] args) throws Exception { JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); org.apache.cxf.endpoint.Client client = dcf.createClient("http://localhost/CXFTest/WS/userws?wsdl"); // url为调用webService的wsdl地址 QName name = new QName("http://service.qlq.cn/", "getUserById");// namespace是命名空间,methodName是方法名 int userId = 1; Object[] objects; try { objects = client.invoke(name, userId);// 第一个参数是上面的QName,第二个开始为参数,可变数组 System.out.println(objects[0].toString()); } catch (Exception e) { e.printStackTrace(); } } }
参数解释:
注意:如果上面报错:
org.apache.cxf.common.i18n.UncheckedException: No operation was found with the name
我们需要将targetNamespace和namespace保持一致,如下:
我们需要将实现类和接口放在同一个包下,或者对服务端的接口实现类中的@WebService添加targetNamespace,其值为接口包名的倒置,例如上面我的配置为:(只用包名)
package cn.qlq.service.impl; import java.sql.SQLException; import javax.jws.WebService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.qlq.dao.UserDao; import cn.qlq.domain.User; import cn.qlq.service.UserService; @Service @WebService(targetNamespace = "http://service.qlq.cn") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public int saveUser(User user) throws SQLException { System.out.println("----------------保存user----------"); return 0; } @Override public User getUserById(int userId) { System.out.println("----------------获取user----------" + userId); return userDao.getUserById(userId); } }
结果:
至此webservice的发布与使用基本完成,明天还会在项目中实际发布webservice,以及测试webservice类改变运用上面三种方式访问webservice的结果。
参考:http://cxf.apache.org/docs/index.html