Spring Boot整合CXF发布、调用WebService接口

WebService的概念

Web 是使应用程序可以与平台和编程语言无关的方式进行相互通信的一项技术。Web 服务是一个软件接口,它描述了一组可以在网络上通过标准化的 XML 消息传递访问的操作。它使用基于 XML 语言的协议来描述要执行的操作或者要与另一个 Web 服务交换的数据。一组以这种方式交互的 Web 服务在面向服务的体系结构(Service-Oriented Architecture,SOA)中定义了特殊的 Web 服务应用程序。

简单的说WebService是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言(通过 xml 描述)间的相互调用,通过Internet进行基于Http协议的网络应用间的交互。通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。

  • XML:(Extensible Markup Language)扩展型可标记语言。面向短期的临时数据处理、面向万维网络,是Soap的基础。
  • Soap:(Simple Object Access Protocol)简单对象存取协议。是XML Web Service 的通信协议。当用户通过UDDI找到你的WSDL描述文档后,他通过可以SOAP调用你建立的Web服务中的一个或多个操作。SOAP是XML文档形式的调用方法的规范,它可以支持不同的底层接口,像HTTP(S)或者SMTP。
  • WSDL:(Web Services Description Language) WSDL 文件是一个 XML 文档,用于说明一组 SOAP 消息以及如何交换这些消息。大多数情况下由软件自动生成和使用。
  • UDDI (Universal Description, Discovery, and Integration) 是一个主要针对Web服务供应商和使用者的新项目。在用户能够调用Web服务之前,必须确定这个服务内包含哪些商务方法,找到被调用的接口定义,还要在服务端来编制软件,UDDI是一种根据描述文档来引导系统查找相应服务的机制。UDDI利用SOAP消息机制(标准的XML/HTTP)来发布,编辑,浏览以及查找注册信息。它采用XML格式来封装各种不同类型的数据,并且发送到注册中心或者由注册中心来返回需要的数据。

整合

pom

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-spring-boot-starter-jaxws -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

yml

server:
  port: 80
  servlet:
    contest-path: /
spring:
  application:
    name: springboot-cxf
cxf:
  path: /user

接口

package com.dev.cxf.service;

import com.dev.cxf.model.DataResult;
import com.dev.cxf.model.MapAdapter;
import com.dev.cxf.model.MapListAdapter;
import com.dev.cxf.model.User;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Description :  webservice接口 //描述
 */
@WebService(
        //服务名
        name = "management",
        //命名空间,一般是接口的包名倒序
        targetNamespace = "http://service.cxf.dev.com"
)
public interface Management {

    @WebMethod
    public String getName(@WebParam(name = "ip") String ip);

    @WebMethod
    public User getUser(@WebParam(name = "name") String name);

    @WebMethod
    public ArrayList<User> getUserList(@WebParam(name = "name") String name);

    @WebMethod
    public DataResult getDataResult();

    @WebMethod
    @XmlJavaTypeAdapter(MapAdapter.class)
    public Map<String, User> getUserMap();

    @WebMethod
    @XmlJavaTypeAdapter(MapListAdapter.class)
    public Map<String, List<User>> getUserMapListUser();

    @WebMethod
    public Map<String, Object> getMap(@WebParam(name = "user") User user);
}

实现

package com.dev.cxf.service.impl;

import com.dev.cxf.model.DataResult;
import com.dev.cxf.model.User;
import com.dev.cxf.service.Management;
import org.springframework.stereotype.Component;

import javax.jws.WebService;
import java.util.*;

/**
 * @Description : webservice接口实现类  //描述
 */
@Component
@WebService(
        //与接口中的命名空间一致
        targetNamespace = "http://service.cxf.dev.com",
        //接口地址
        endpointInterface = "com.dev.cxf.service.Management"
)
public class ManagementImpl implements Management {

    @Override
    public String getName(String ip) {
        return "hello world!";
    }

    @Override
    public User getUser(String name) {
        System.out.println(name);
        User user = new User();
        user.setName("cxf demo");
        user.setIp("127.0.0.1");
        return user;
    }

    @Override
    public ArrayList<User> getUserList(String name) {
        System.out.println(name);
        ArrayList<User> list = new ArrayList<User>();
        list.add(new User("ip","127.0.0.1"));
        list.add(new User("ip","127.0.0.2"));
        list.add(new User("ip","127.0.0.3"));
        return list;
    }

    @Override
    public DataResult getDataResult() {
        DataResult dataResult = new DataResult();
        List<User> list = new ArrayList<User>();
        list.add(new User("ip","127.0.0.1"));
        list.add(new User("ip","127.0.0.2"));
        Map<String, User> s = new HashMap<String, User>();
        s.put("name", new User("ip","127.0.0.1"));
        dataResult.setUserMap(s);
        dataResult.setUserList(list);
        return dataResult;
    }

    @Override
    public Map<String, User> getUserMap() {
        HashMap<String, User> s = new HashMap<String, User>();
        s.put("name",new User("ip","127.0.0.1"));
        s.put("name2",new User("ip","127.0.0.2"));
        s.put("name3",new User("ip","127.0.0.3"));
        return s;
    }

    @Override
    public Map<String, List<User>> getUserMapListUser() {
        Map<String, List<User>> s = new HashMap<String, List<User>>();
        List<User> list = new ArrayList<User>();
        list.add(new User("ip","127.0.0.1"));
        list.add(new User("ip","127.0.0.2"));
        s.put("name",list);
        s.put("name2",list);
        s.put("name3",list);
        return s;
    }

    @Override
    public HashMap<String, Object> getMap(User user) {
        System.out.println(user);
        HashMap<String, Object> s = new HashMap<String, Object>();
        s.put("ip1", "127.0.0.1");
        s.put("ip2", "127.0.0.1");
        return s;
    }
}

发布

package com.dev.cxf.config;

import com.dev.cxf.model.User;
import com.dev.cxf.service.Management;
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 javax.annotation.Resource;
import javax.xml.ws.Endpoint;

/**
 * @Description :  webservice发布配置 //描述
 * @Author :   //作者
 */
@Configuration
public class WebServiceConfig {

    @Resource
    private Management management;

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus(){
        return new SpringBus();
    }

    /**
     * JAX-WS
     */
    @Bean
    public Endpoint endpoint(){
        EndpointImpl endpoint = new EndpointImpl(springBus(), management);
        endpoint.publish("/test");
        return endpoint;
    }

    /**
     * 访问地址 http://127.0.0.1:80/user/test?wsdl
     *
     * 但cxf 2.0.4之后的版本不需再配置此项内容,只需在application中配置
     * cxf.path=/user
     * 或者
     * cxf:
     *   path: /user
     */
//    @Bean()
//    public ServletRegistrationBean registrationBean(){
//        return new ServletRegistrationBean(new CXFServlet(),"/user/*");
//    }
}

复杂参数解析

这里以Map<String,List<User>>为例介绍,剩下的大家可以去github上项目中查看

MapListUser

package com.dev.cxf.model;

import javax.xml.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName : MapListUser  //类名
 * @Description :   //描述
 */
@XmlType(name = "MapListUser")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
@XmlSeeAlso({User.class})
public class MapListUser {

    private List<ListEntry> listEntry;

    static class ListEntry{
        private String key;
        private List<User> userList = new ArrayList<User>();

        public ListEntry() {
        }

        public ListEntry(String key, List<User> userList) {
            this.key = key;
            this.userList = userList;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public List<User> getUserList() {
            return userList;
        }

        public void setUserList(List<User> value) {
            this.userList = value;
        }
    }

    public List<ListEntry> getListEntry() {
        return listEntry;
    }

    public void setListEntry(List<ListEntry> listEntry) {
        this.listEntry = listEntry;
    }
}

User

package com.dev.cxf.model;

import lombok.Data;

import java.io.Serializable;

/**
 * @ClassName : User  //类名
 * @Description :   //描述
 */
@Data
public class User implements Serializable {
    private String name;
    private String ip;

    public User() {
    }

    public User(String name, String ip) {
        this.name = name;
        this.ip = ip;
    }
}

MapListAdapter

package com.dev.cxf.model;

import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.util.*;

/**
 * @Description :   //描述
 */
public class MapListAdapter extends XmlAdapter<MapListUser, Map<String, List<User>>> {
    /**
     * Convert a value type to a bound type.
     *
     * @param v The value to be converted. Can be null.
     * @throws Exception if there's an error during the conversion. The caller is responsible for
     *                   reporting the error to the user through {@link ValidationEventHandler}.
     */
    @Override
    public Map<String, List<User>> unmarshal(MapListUser v) throws Exception {
        Map<String, List<User>> map = new HashMap<>();
        for (MapListUser.ListEntry listEntry : v.getListEntry()) {
            map.put(listEntry.getKey(), listEntry.getUserList());
        }
        return map;
    }

    /**
     * Convert a bound type to a value type.
     *
     * @param v The value to be convereted. Can be null.
     * @throws Exception if there's an error during the conversion. The caller is responsible for
     *                   reporting the error to the user through {@link ValidationEventHandler}.
     */
    @Override
    public MapListUser marshal(Map<String, List<User>> v) throws Exception {
        MapListUser mapListUser = new MapListUser();
        List<MapListUser.ListEntry> listEntries = new ArrayList<>();
        for (String s : v.keySet()) {
            MapListUser.ListEntry listEntry= new MapListUser.ListEntry();
            listEntry.setKey(s);
            listEntry.setUserList(v.get(s));
            listEntries.add(listEntry);
        }
        mapListUser.setListEntry(listEntries);
        return mapListUser;
    }
}

配置完成启动项目

启动浏览器输入:http://127.0.0.1:80/user/test?wsdl或者http://localhost/user/test?wsdl

 client

客户端使用JaxWsDynamicClientFactory动态调用

CxfClientUtil

package com.dev.cxf.client;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.dev.cxf.model.DataResult;
import com.dev.cxf.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.Key;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description :  cxf操作类 //描述
 */
@Slf4j
public class CxfClientUtil {

    private static Client client = null;

    /**
     * 获取yml中配置
     * @param name 配置文件名 如:application.yml
     * @param key 配置文件名 如:cxf
     */
    public static Hashtable getYml(String name,String key){
        //"application.yml"
        ClassPathResource resource = new ClassPathResource(File.separator + name);
        try {
            Hashtable props = PropertiesLoaderUtils.loadProperties(resource);
            return props;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 创建client
     * @param wsdlUrl webservice地址
     */
    public static boolean create(String wsdlUrl){
        try {
            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
            client = dcf.createClient(wsdlUrl);
            // 如果返回的address不是远程服务地址,重新制定地址
            client.getEndpoint().getEndpointInfo().setAddress(wsdlUrl);
            // 策略
            HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
            // 连接超时
            httpClientPolicy.setConnectionTimeout(6000000);
            httpClientPolicy.setAllowChunking(false);
            // 接收超时
            httpClientPolicy.setReceiveTimeout(6000000);
            HTTPConduit http = (HTTPConduit) client.getConduit();
            http.getClient().setReceiveTimeout(0);
            http.setClient(httpClientPolicy);
            if (null != client) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.toString());
            return false;
        }
        return false;
    }

    /**
     * 返回String
     * @param wsdlUrl 地址
     * @param method 方法名
     * @param parm 入参
     *
     * @return String 字符串
     */
    public static String transferToString(String wsdlUrl, String method, String parm) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            try {
                objects = client.invoke(method, parm);
                if (objects.length > 0){
                    return objects[0].toString();
                } else {
                    return "";
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "调用失败!";
    }

    /**
     * 返回实体类
     * @param wsdlUrl 地址
     * @param method 方法名
     * @param parm 入参
     *
     * @return User 实体类
     */
    public static User transferToEntity(String wsdlUrl, String method, String parm) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            User user = null;
            try {
                objects = client.invoke(method, parm);
                if (objects.length > 0){
                    user = JSON.parseObject(JSON.toJSONString(objects[0]), User.class);
                    return user;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return user;
            }
        }
        return new User();
    }

    /**
     * 返回List<User>
     * @param wsdlUrl 地址
     * @param method 方法名
     * @param parm 入参
     *
     * @return List<User> 实体类
     */
    public static ArrayList<User> transferToList(String wsdlUrl, String method, String parm) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            ArrayList<User> list = null;
            try {
                objects = client.invoke(method, parm);
                if (objects.length > 0){
                    list = (ArrayList<User>) JSON.parseArray(JSON.toJSONString(objects[0]), User.class);
                    return list;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return list;
            }
        }
        return new ArrayList<User>();
    }

    /**
     * 返回List<User>与Map<String,User>
     *
     * @param wsdlUrl 地址
     * @param method 方法名
     * @param parm 入参
     *
     * @return DataResult 实体类
     */
    public static DataResult transferToDataResult(String wsdlUrl, String method) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            DataResult dataResult = null;
            try {
                objects = client.invoke(method);
                if (objects.length > 0){
                    // https://www.cnblogs.com/tfxz/p/12621560.html
                    Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
                    classMap.put("userList",User.class);
                    dataResult = (DataResult) net.sf.json.JSONObject.toBean(net.sf.json.JSONObject.fromObject(JSONObject.toJSONString(objects[0])), DataResult.class, classMap);
                    return dataResult;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return dataResult;
            }
        }
        return new DataResult();
    }

    public static Map<String, User> transferToUserMap(String wsdlUrl, String method) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            Map<String, User> map = new HashMap<>();
            try {
                objects = client.invoke(method);
                if (objects.length > 0) {
                    JSONArray entries = JSON.parseObject(JSON.toJSONString(objects[0])).getJSONArray("entries");
                    //https://www.cnblogs.com/tfxz/p/12621560.html
                    Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
                    for (Object object : entries) {
                        net.sf.json.JSONObject jsonObject1 = net.sf.json.JSONObject.fromObject(object);
                        User table = (User) net.sf.json.JSONObject.toBean(net.sf.json.JSONObject.fromObject(jsonObject1.getString("value")), User.class, classMap);
                        map.put(jsonObject1.getString("key"), table);
                    }
                    return map;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return map;
            }
        }
        return new HashMap<String, User>();
    }

    public static Map<String, Object> transferToMap(String wsdlUrl, String method,Map<String, Object> m) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            Map<String, Object> map = new HashMap<>();
            try {
                //CXF传入复杂参数:调用服务器端实体类->调用set方法->提交参数
                Object ajjySjth = Thread.currentThread().getContextClassLoader().loadClass("com.dev.cxf.service.User").getDeclaredConstructor().newInstance();// 加载类为服务端自定义对象命名空间
                Method setIp = ajjySjth.getClass().getMethod("setIp", String.class);// 调用set方法设置参数
                Method setName = ajjySjth.getClass().getMethod("setName", String.class);// 调用set方法设置参数
                setIp.invoke(ajjySjth, m.get("ip"));
                setName.invoke(ajjySjth, m.get("name"));
                objects = client.invoke(method, ajjySjth);
                if (objects.length > 0){
                    net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(objects[0]);
                    net.sf.json.JSONArray entry = jsonObject.getJSONArray("entry");
                    for (Object o : entry) {
                        JSONObject object = JSON.parseObject(JSON.toJSONString(o));
                        map.put(object.getString("key"), object.getString("value"));
                    }
                    return map;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return map;
            }
        }
        return new HashMap<String, Object>();
    }

    public static Map<String, List<User>> transferToUserMapListUser(String wsdlUrl, String method) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            Map<String, List<User>> map = new HashMap<>();
            try {
                objects = client.invoke(method);
                if (objects.length > 0) {
                    JSONArray listEntry = JSON.parseObject(JSON.toJSONString(objects[0])).getJSONArray("listEntry");
                    for (Object o : listEntry) {
                        JSONObject object = JSON.parseObject(JSON.toJSONString(o));
                        map.put(object.getString("key"), JSON.parseObject(JSON.toJSONString(object.getJSONArray("userList")), List.class));
                    }
                    return map;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return map;
            }
        }
        return new HashMap<String, List<User>>();
    }
}

Test

package com.dev.cxf.client;

import lombok.extern.slf4j.Slf4j;
import java.util.*;

/**
 * @Description : client端测试  //描述
 */
@Slf4j
public class Test {
    private static final String wsdlUrl = "http://127.0.0.1:80/user/test?wsdl";
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name","zhansgan");
        map.put("ip","127.0.0.1");
        //string
//        System.out.println(CxfClientUtil.transferToString(wsdlUrl, "getName", map.get("ip").toString()));
        //entity
//        System.out.println(CxfClientUtil.transferToEntity(wsdlUrl,"getUser",map.get("name").toString()));
        //list
//        System.out.println(CxfClientUtil.transferToList(wsdlUrl,"getUserList",map.get("name").toString()));
        //list + map
//        System.out.println(CxfClientUtil.transferToDataResult(wsdlUrl,"getDataResult"));
        //map<String,User>
//        System.out.println(CxfClientUtil.transferToUserMap(wsdlUrl, "getUserMap"));
        //map<String,Object>
        System.out.println(CxfClientUtil.transferToMap(wsdlUrl, "getMap", map));
        //map<String,List<User>>
//        System.out.println(CxfClientUtil.transferToUserMapListUser(wsdlUrl, "getUserMapListUser"));
    }
}

运行Test这里调用的是"getMap"接口,实现类中传入参数User对象,返回是HashMap<String,Object>类型数据ip1和ip2

getMap打印

 Test打印

项目中写的例子有:

  • String
  • List<User>
  • User
  • DataResult(List + Map)
  • Map<String,Object>
  • Map<String,List<User>>
  • Map<String,User>

问题

java.lang.IllegalStateException: Unable to create schema compiler

这个问题相信不少人都遇到过,动态编译时找不到tools.jar报错导致

 

解决方式: 将引用的jre换为jdk,或者将tools.jar复制到你引用jre目录下

 


参考链接:

https://www.cnblogs.com/tfxz/p/12621560.html

https://www.cnblogs.com/zhengyuanyuan/p/9277059.html

GitHub:传送门


链接另一篇传递复杂类型参数:传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值