当前位置: 首页 > article >正文

使用CXF调用WSDL

简介

时隔多年,再次遇到需要调用WebService的业务,对方给予的wsdl说明文档还是内网的链接,并且设有基础访问权限,即在浏览器打开wsdl链接时需要输入【用户名+密码】登录后方可查看wsdl文档,这需要设置代理(我使用putty完成了代理),本文只记录使用org.apache.cxf调用wsdl的过程

附一张putty的下载链接:

https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

步骤一 :添加org.apache.cxf的maven引用

        <!-- cxf JaxWsDynamicClientFactory 开始 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!-- cxf JaxWsDynamicClientFactory 结束 -->

步骤二:访问WSDL

/**
     * 打开WSDL文件
     * @return
     */
    private static Bus openWSDL(){
        Bus bus = BusFactory.getThreadDefaultBus();
        bus.setExtension((name, address, httpConduit) -> {
            //设置访问wsdl所需的用户名和密码
            final AuthorizationPolicy authorization = new AuthorizationPolicy();
            authorization.setUserName("username");
            authorization.setPassword("password");
            httpConduit.setAuthorization(authorization);
            final HttpAuthSupplier supplier = new DefaultBasicAuthSupplier();
            httpConduit.setAuthSupplier(supplier);
            //设置service中location的映射代理IP和端口 
            final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
            httpClientPolicy.setProxyServer("127.0.0.1");
            httpClientPolicy.setProxyServerPort(50000);
            httpClientPolicy.setAllowChunking(false);
            httpClientPolicy.setConnectionTimeout(50000);
            httpClientPolicy.setReceiveTimeout(50000);
            httpConduit.setClient(httpClientPolicy);
        }, HTTPConduitConfigurer.class);
        return bus;
    }

步骤三:获取WSDL文档内容

/**
     * 获取WSDL内容
     * @return
     */
    private static Map<String,Object> getWSDLContent() {
        Map<String,Object> wsdl = new HashMap<>();
        try {
            Bus bus = openWSDL();
            ClassLoader loader = Gmm1020Server.class.getClassLoader();
            // 创建动态客户端
            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(bus);
            Client client = dcf.createClient("你的wsdl地址",
                    new QName("wsdl中的targetNamespace", "wsdl:service的name"),
                    loader,
                    new QName("wsdl中的targetNamespace", "HTTP_Port"));
            QName qName = new QName("wsdl中的targetNamespace", "wsdl:operation的name");
            List<MessagePartInfo> partInfos = client.getEndpoint()
                    .getService().getServiceInfos().get(0)
                    .getBinding(new QName("wsdl中的targetNamespace", "wsdl:binding的name"))
                    .getOperation(qName)
                    .getInput().getMessageParts();
            wsdl.put("client",client);
            wsdl.put("qname",qName);
            wsdl.put("messagePartInfo",partInfos);
        } catch (Exception e) {
            throw new WebServiceException(e);
        }
        return wsdl;
    }

注意:Bus引用的是上一个方法

Bus bus = openWSDL();

步骤四:调用远程接口(远程过程调用)

/**
     * 调用远程过程
     */
    public static void call(Map map) {
        Map<String,Object> wsdl = getWSDLContent();
        Client client = (Client) wsdl.get("client");
        List<MessagePartInfo> partInfos = (List<MessagePartInfo>) wsdl.get("messagePartInfo");
        QName qName = (QName) wsdl.get("qname");

        String clazzName = partInfos.get(0).getTypeClass().getName();
        try {
            Object requestParamObject = Thread.currentThread().getContextClassLoader().loadClass(clazzName).newInstance();
            Field[] fields = requestParamObject.getClass().getDeclaredFields();
            for (Field field : fields) {
                //如果是泛型
                boolean b = field.getGenericType() instanceof ParameterizedType;
                if(b && field.getType() == List.class){
                    Type[] types = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();
                    for (Type type : types) {
                        Class aClass = (Class) type;
                        Object obj = aClass.newInstance();
                        List<Object> curElementList = new ArrayList<>();
                        List<Map> params = (List<Map>) map.get(field.getName().toLowerCase());
                        if(!CollectionUtils.isEmpty(params)){
                            for (Map param : params) {
                                writeFiledVal(obj,param);
                                curElementList.add(obj);
                            }
                        }
                        //writeCustomValue(obj);
                        field.setAccessible(true);
                        field.set(requestParamObject,curElementList);
                    }
                }else if(field.getType().getName().equals("java.lang.String")){
                    //字符串则直接赋值
                    Field f = requestParamObject.getClass().getDeclaredField(field.getName());
                    f.setAccessible(true);
                    f.set(requestParamObject,map.get(f.getName()));
                }else {
                    //对象类型
                    Class clazz = field.getType();
                    Object obj = clazz.newInstance();
                    Map param = (Map) map.get(field.getName().toLowerCase());
                    writeFiledVal(obj,param);
                    //writeCustomValue(obj);
                    Field f = requestParamObject.getClass().getDeclaredField(field.getName());
                    f.setAccessible(true);
                    f.set(requestParamObject,obj);
                }
            }
            log.info("请求参数:{}",JSON.toJSON(requestParamObject));
            Object result = client.invoke(qName, requestParamObject);
            log.info("响应结果:{}",JSON.toJSONString(result,true));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

注意:该代码的入参是一个Map对象,该对象中包含了三种类型的属性和一层属性对象的嵌套(java.util.List、java.lang.String、POJO对象)因此该代码只针对三种类型做了解析处理,并不具备所有类型的通用性。

比如:你的入参对象中有java.lang.Integer类型,或者Set ...,那就需要编写相应的解析方式,这是类型解析。

属性对象的嵌套的意思是:如果你的入参对象Map中有个List<POJO>或者直接就是POJO,这就是一层属性嵌套,而如果这个List中的POJO对象又嵌套了其他的POJO对象,这就属于二层解析,即:

List<User> userList = new ArrayLIst();

class User {

private String userName;

private UserDetails userDetails;

}

而或许UserDetails对象中还存着Enterprise对象... 以此嵌套,想要全面解析你就需要使用递归算法。(我想我应该把问题说清楚了)

代码层面:ParameterizedType

Type[] types = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();

这个对象是一个接口,表示参数化类型,这句代码意思是返回这个field的实际类型参数

步骤五:字段赋值

    /**
     * 字段写值
     * @param obj
     */
    private static void writeFiledVal(Object obj,Map param) {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                field.set(obj,param.get(field.getName()));
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 测试使用
     * 给字段写入自定义值
     * @param obj
     */
    private void writeCustomValue(Object obj) {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if(!field.getType().isPrimitive()){
                field.getType().getConstructors();
            }
            try {
                field.set(obj,"1");
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

说明:writeCustomValue是测试方式,而writeFiledVal多了一个入参Map,主要用来赋值的。

使用的时候,只需要讲你的入参对象转换成map,放入 'call()' 方法即可完成调用

响应结果虽然是服务器告诉我有问题(因为我的数据是乱写的),但是可以看得出来,调用是通了 


http://www.kler.cn/a/15834.html

相关文章:

  • 动态规划-完全背包问题——518.零钱兑换II
  • Servlet⽣生命周期超级细(笔记)
  • 使用 Web Search 插件扩展 GitHub Copilot 问答
  • 微信小程序 === 使用腾讯地图选点
  • 使用Redis的一些经验总结
  • LlamaFactory介绍
  • 如何高效的学习接口自动化测试?从零开始学习接口自动化测试:选择合适的学习资源和编程语言
  • 电脑硬盘检测怎么操作?如何检查硬盘的健康情况?
  • Dockerfile样例
  • d3.js学习笔记①创建html文档
  • 【网络】网络基础协议概念IPMAC地址
  • Blender 插件UvSquares
  • 电子数据取证之网站分析和重构基础
  • 【tippecanoe】Linux环境tippecanoe部署
  • 2022 gdcpc题解(10/13)
  • Battle Symphony
  • Terraform
  • autosar软件分层架构组成--汽车电子
  • java中设计模式
  • dpdk安装在虚拟机上如何安装
  • 数字化转型导师坚鹏:数字化转型背景下的保险公司人力资源管理
  • 【SpringBoot系列】接收前端参数的几种方式
  • 音视频 FFmpeg
  • SpringBoot事务管理-5个面试核心类源码刨析
  • 【源码解析】SpringBoot日志系统源码分析
  • 【高危】MySQL Server拒绝服务漏洞(CVE-2023-21912)