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

        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            org.apache.cxf
            cxf-spring-boot-starter-jaxws
            3.4.0
        

        
            org.springframework.boot
            spring-boot-starter-web-services
        

        
        
            net.sf.json-lib
            json-lib
            2.4
            jdk15
        

        
            org.projectlombok
            lombok
            true
        

        
            com.alibaba
            fastjson
            1.2.73
        

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 getUserList(@WebParam(name = "name") String name);

    @WebMethod
    public DataResult getDataResult();

    @WebMethod
    @XmlJavaTypeAdapter(MapAdapter.class)
    public Map getUserMap();

    @WebMethod
    @XmlJavaTypeAdapter(MapListAdapter.class)
    public Map> getUserMapListUser();

    @WebMethod
    public Map 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 getUserList(String name) {
        System.out.println(name);
        ArrayList list = new ArrayList();
        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 list = new ArrayList();
        list.add(new User("ip","127.0.0.1"));
        list.add(new User("ip","127.0.0.2"));
        Map s = new HashMap();
        s.put("name", new User("ip","127.0.0.1"));
        dataResult.setUserMap(s);
        dataResult.setUserList(list);
        return dataResult;
    }

    @Override
    public Map getUserMap() {
        HashMap s = new HashMap();
        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> getUserMapListUser() {
        Map> s = new HashMap>();
        List list = new ArrayList();
        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 getMap(User user) {
        System.out.println(user);
        HashMap s = new HashMap();
        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>为例介绍,剩下的大家可以去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;

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

        public ListEntry() {
        }

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

        public String getKey() {
            return key;
        }

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

        public List getUserList() {
            return userList;
        }

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

    public List getListEntry() {
        return listEntry;
    }

    public void setListEntry(List 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>> {
    /**
     * 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> unmarshal(MapListUser v) throws Exception {
        Map> 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> v) throws Exception {
        MapListUser mapListUser = new MapListUser();
        List 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;
    }
}

配置完成启动项目

Spring Boot整合CXF发布、调用WebService接口_第1张图片

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

Spring Boot整合CXF发布、调用WebService接口_第2张图片

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

    /**
     * 返回List与Map
     *
     * @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> classMap = new HashMap>();
                    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 transferToUserMap(String wsdlUrl, String method) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            Map 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> classMap = new HashMap>();
                    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();
    }

    public static Map transferToMap(String wsdlUrl, String method,Map m) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            Map 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();
    }

    public static Map> transferToUserMapListUser(String wsdlUrl, String method) {
        if (create(wsdlUrl)) {
            Object[] objects = null;
            Map> 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>();
    }
}

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 map = new HashMap();
        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
//        System.out.println(CxfClientUtil.transferToUserMap(wsdlUrl, "getUserMap"));
        //map
        System.out.println(CxfClientUtil.transferToMap(wsdlUrl, "getMap", map));
        //map>
//        System.out.println(CxfClientUtil.transferToUserMapListUser(wsdlUrl, "getUserMapListUser"));
    }
}

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

getMap打印

Spring Boot整合CXF发布、调用WebService接口_第3张图片

 Test打印

项目中写的例子有:

  • String
  • List
  • User
  • DataResult(List + Map)
  • Map
  • Map>
  • Map

问题

java.lang.IllegalStateException: Unable to create schema compiler

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

Spring Boot整合CXF发布、调用WebService接口_第4张图片

 

Spring Boot整合CXF发布、调用WebService接口_第5张图片

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

Spring Boot整合CXF发布、调用WebService接口_第6张图片

Spring Boot整合CXF发布、调用WebService接口_第7张图片

 


参考链接:

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

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

GitHub:传送门


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

你可能感兴趣的:(#,Spring,Boot,java,spring,boot,cxf,webservice,soap)