这篇文章主要介绍了详解 Spring boot+CXF 开发 webService Demo, 非常具有实用价值, 需要的朋友可以参考下
最近工作中需要用到 webservice, 而且结合 spring boot 进行开发, 参照了一些网上的资料, 配置过程中出现的了一些问题, 于是写了这篇博客, 记录一下我这次 spring boot+cxf 开发的 webservice 的配置过程, 仅供参考
一本次开发除了用到 spring boot 基础 jar 包外, 还用到了 cxf 相关 jar 包:
- <!-- cxf 支持 -->
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-frontend-jaxws</artifactId>
- <version>3.1.6</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-transports-http</artifactId>
- <version>3.1.6</version>
- </dependency>
二首先我们创建一个实体类, 内容是关于用户信息的查询和记录:
- import java.io.Serializable;
- import java.util.Date;
- public class User implements Serializable {
- private static final long serialVersionUID = -5939599230753662529L;
- private String userId;
- private String username;
- private String age;
- private Date updateTime;
- //getter setter ......
- public void setUserId(String userId) {
- this.userId=userId;
- }
- public void setUsername(String username) {
- this.username=username;
- }
- public void setAge(String age) {
- this.age=age;
- }
- public void setUpdateTime(Date updateTime) {
- this.updateTime=updateTime;
- }
- public String getUserId() {
- return userId;
- }
- public String getUserName() {
- return username;
- }
- public String getAge() {
- return age;
- }
- public Date getUpdateTime() {
- return updateTime;
- }
- }
三接下来我们创建接口类:
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebService;
- import cn.paybay.demo.entity.User;
- @WebService
- public interface UserService {
- @WebMethod
- String getName(@WebParam(name = "userId") String userId);
- @WebMethod
- User getUser(String userId);
- }
四有了接口类, 那么接下来我们对接口进行实现, 也就是接口实现类 (也就是业务类) 代码:
- package cn.paybay.demo.service.impl;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
- import javax.jws.WebService;
- import cn.paybay.demo.entity.User;
- import cn.paybay.demo.service.UserService;
- @WebService(targetNamespace="http://service.demo.paybay.cn/",endpointInterface = "cn.paybay.demo.service.UserService")
- public class UserServiceImpl implements UserService{
- private Map<String, User> userMap = new HashMap<String, User>();
- public UserServiceImpl() {
- System.out.println("向实体类插入数据");
- User user = new User();
- user.setUserId("411001");
- user.setUsername("zhansan");
- user.setAge("20");
- user.setUpdateTime(new Date());
- userMap.put(user.getUserId(), user);
- user = new User();
- user.setUserId("411002");
- user.setUsername("lisi");
- user.setAge("30");
- user.setUpdateTime(new Date());
- userMap.put(user.getUserId(), user);
- user = new User();
- user.setUserId("411003");
- user.setUsername("wangwu");
- user.setAge("40");
- user.setUpdateTime(new Date());
- userMap.put(user.getUserId(), user);
- }
- @Override
- public String getName(String userId) {
- return "liyd-" + userId;
- }
- @Override
- public User getUser(String userId) {
- System.out.println("userMap 是:"+userMap);
- return userMap.get(userId);
- }
- }
注释(PS): 在发布服务之前, 我们要在这里对业务实现类进行一下说明, 请大家看下图箭头指向的方框部分
下面我来解释一下加上图方框箭头所指代码的目的:
http://impl.service.demo.paybay.cn/: 这是我的业务类所在路径;
http://service.demo.paybay.cn/: 这是我的接口类所在路径;
在不加上图方框箭头所指代码的情况下, 你最后发服务的结果是这样的(如下图):
并且会在你进行客户端调用的时候回报错: No operation was found with the name {http://impl.service.demo.paybay.cn/}getUser. 那么原因就是: 在 CXF 发布服务的时候, 发布的是业务类(UserServiceImpl.java), 那么默认的命名空间就会是业务类所在包(路径), 而对外界暴露的则是接口类(UserService.java), 那么对于客户端调用的时侯, 需要按照接口类所在路径进行命名空间的定义
所以在发布之前我们要在业务类 (UserServiceImpl.java) 上增加注解, 指定命名空间, 然后再进行发布,
那么我们最终在加上 (图一) 方框箭头所指代码情况下, 发布服务的结果为下图(请看图三):
五 (发布服务) 接口类, 业务类代码都已经准备好, 那么我接下来我就要对 webservice 服务进行发布:
代码如下:
- import javax.xml.ws.Endpoint;
- import org.apache.cxf.Bus;
- import org.apache.cxf.bus.spring.SpringBus;
- import org.apache.cxf.jaxws.EndpointImpl;
- import org.apache.cxf.transport.servlet.CXFServlet;
- import org.springframework.boot.web.servlet.ServletRegistrationBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import cn.paybay.demo.service.UserService;
- import cn.paybay.demo.service.impl.UserServiceImpl;
- @Configuration
- public class TestConfig {
- @Bean
- public ServletRegistrationBean dispatcherServlet() {
- return new ServletRegistrationBean(new CXFServlet(), "/test/*");
- }
- @Bean(name = Bus.DEFAULT_BUS_ID)
- public SpringBus springBus() {
- return new SpringBus();
- }
- @Bean
- public UserService userService() {
- return new UserServiceImpl();
- }
- @Bean
- public Endpoint endpoint() {
- EndpointImpl endpoint = new EndpointImpl(springBus(), userService());
- endpoint.publish("/user");
- return endpoint;
- }
- }
那么到这里呢, 我们的所有的步骤基本完成了, 启动 spring boot 然后再浏览器中输入 url:http://localhost:8080/webservice/test/user?wsdl
可以看到有相关的 wsdl 描述信息输出了, 说明服务已经发布了
那么这里我又要增加注释了, 请大家注意, 我在最初查询资料, 配置 demo 的时候, 启动以后, 发布时候总是报 404, 网上有很多关于什么端口冲突等说法, 我试过后, 根本不是那一回事, 然后我无意中尝试了一下, 在 url 地址处加入工程名, 结果, 问题解决了
因此请大家注意: 在测试发布服务的时候, 你在浏览器中输入的 url 地址应该是: http://localhost:8080 / 你的工程名 / test/user?wsdl;
然后就是发布结果如下图(见图四):
到此为止, 我们的服务发布成功了
六调用服务
- import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
- public class Client {
- public static void main(String args[]) throws Exception{
- JaxWsDynamicClientFactory dcf =JaxWsDynamicClientFactory.newInstance();
- org.apache.cxf.endpoint.Client client =dcf.createClient("http://localhost:8080/webservice/test/user?wsdl");
- //getUser 为接口中定义的方法名称 张三为传递的参数 返回一个 Object 数组
- Object[] objects=client.invoke("getUser","411001");
- // 输出调用结果
- System.out.println("*****"+objects[0].toString());
- }
- }
七最后附上我的工程结构图(见图五):
来源: http://www.phperz.com/article/18/0319/357042.html