对接WSDL+SOAP服务:xFire替换方案

有一个老旧的服务,我需要远程调用它
技术是WSDL + SOAP + webService
.
看到很多同学用的都是xFire。然而,它有漏洞,不让用~。
于是参考了cxf,xFire的新版包。感觉不友好(重点是折腾半天没搞定)

技术岂是如此不便之物?于是从传统方案开始思考:即HTTP,可行~

一、错误的认知

  • webService不是什么别的协议,依旧用的HTTP。
  • 解析WSDL可以和解析json一样,但同理发送请求需要WSDL、SOAP格式。
    (也就是说服务侧,需要提供xml请求响应格式。)

惍!隔壁团队的问题居然没有说清楚!搞得我以为WSDL是一种与HTTP不同的协议

二、postman测试

由于之前就是信心满满的写代码,然后搞不定,浪费了很多时间。
注:请求体、响应体格式需要问对接团队

请求头

在这里插入图片描述

请求体

在这里插入图片描述

响应体

在这里插入图片描述

结论:请求成功(成功)

三:设计Rest远程调用模组

要求:
  1. 同事希望能像调用方法一样调用远程服务
  2. 小领导要求:扩展友好、能用
  3. 我的要求:简单、易维护
项目包结构

简单的远程调用,懒得画图

在这里插入图片描述

四、关键代码

pom文件引用
<dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.13.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.16</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.14</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>6.1.0</version>
        </dependency>
		
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>
        <!-- xml bean 转换相关包 -->
        <!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api -->
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>4.0.1</version>
        </dependency>
        <!-- aop 切面 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>3.1.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

调用外层

在这里插入图片描述

xml bean 数据结构

外围bean

@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "soap:Envelope")
public class AccountCertXmlResp {

    @XmlElement(name = "soap:Body")
    private Body body;

    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public static class Body {
        @XmlElement(name = "ns1:accountCertApplyResponse")
        private AccountCertApplyResponse accountCertApplyResponse;
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public static class AccountCertApplyResponse {

        @XmlElement(name = "ns1:out")
        private String out;
    }

}
JaxbUtil xml打包解析工具类
@Slf4j
public class JaxbUtils {

    /**
     * xml 转bean
     *
     * @param data        字符
     * @param targetClazz bean class
     * @param <T>         t
     * @return t
     */
    public static <T> T xmlStrToBean(String data, Class<T> targetClazz) {
        return xmlStrToBean(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)), targetClazz);
    }

    /**
     * xml 转bean
     *
     * @param is          输入流
     * @param targetClazz bean class
     * @param <T>         t
     * @return t
     */
    public static <T> T xmlStrToBean(InputStream is, Class<T> targetClazz) {
        try {
            JAXBContext jc = JAXBContext.newInstance(targetClazz);
            Unmarshaller uma = jc.createUnmarshaller();
            // 忽略命名空间
            SAXParserFactory sax = SAXParserFactory.newInstance();
            sax.setNamespaceAware(false);
            XMLReader xmlReader = sax.newSAXParser().getXMLReader();
            Source source = new SAXSource(xmlReader, new InputSource(is));
            return (T) uma.unmarshal(source);
        } catch (JAXBException e) {
            log.error("xmlutil ", e);
            throw new RuntimeException("Deserialization from xml to object error: " + e.getMessage());
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * bean 转字符
     *
     * @param t   bean
     * @param <T> t
     * @return 字符
     */
    public static <T> String beanToXml(T t) {
        StringWriter writer;
        try {
            //1、创建上下文
            JAXBContext context = JAXBContext.newInstance(t.getClass());
            //从上下文中获取Marshaller对象,用作将bean编组(转换)为xml
            Marshaller marshaller = context.createMarshaller();
            //3、设置marshaller的属性
            //以下是为生成xml做的一些配置
            //格式化输出,即按标签自动换行,否则就是一行输出
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            //是否省略xml头信息,默认不省略(false)
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            //4、实例化StringWriter
            writer = new StringWriter();
            //5、将实体类读取到writer中
            marshaller.marshal(t, writer);
            //6、输出结果
            return writer.toString();
        } catch (JAXBException e) {
            log.error("xmlUtil toString error :", e);
            throw new RuntimeException(e);
        }
    }

}
SoapUtil 工具类
@Slf4j
public class SoapUtil {

    /**
     * 打包为xml soap协议
     *
     * @param reqBean   请求对象
     * @return 打包后的数据
     */
    public static <T> String pkgXml(String operationName,T reqBean) {
        // 对象转xml
        String xml = XmlConst.XML_8 + JaxbUtils.beanToXml(reqBean);
        // 替换原格式中的:操作名、内容
        String xmlPkg = XmlConst.SOAP_PKG.replace(XmlConst.OPERATION_NAME, operationName)
                .replace(XmlConst.REQUEST_BODY, xml);
        log.info("xmlPkg : {}",xmlPkg);
        return xmlPkg;
    }

}

常量写法
在这里插入图片描述

HTTP请求工具
@Slf4j
public class HttpUtil {

    static SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();

    static HttpHeaders headers = new HttpHeaders();

    static {
        factory.setReadTimeout(6000);
        factory.setConnectTimeout(6000);
        headers.setContentType(MediaType.APPLICATION_XML);
    }

    private static final RestTemplate REST = new RestTemplate(factory);

    /**
     * 发送Post请求
     *
     * @param url 地址
     * @param body 内容
     * @return 请求结果
     */
    public static String postSoap(String url, Object body) {
        // 获取操作名
        String operationName = url.substring(url.lastIndexOf("/") + 1);
        // 首字母小写
        operationName = operationName.substring(0,1).toLowerCase() + operationName.substring(1);
        // 组装请求包
        String pkgXml = SoapUtil.pkgXml(operationName, body);
        return post(url, pkgXml);
    }

    /**
     * 发送Post请求
     *
     * @param url 地址
     * @param body 内容
     * @return 请求结果
     */
    public static String post(String url, String body) {
        return httpPost(url, headers, body);
    }

    /**
     * 发送Post请求
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param body    请求体
     * @return 返回消息体
     */
    public static String httpPost(String url, HttpHeaders headers, String body) {
        HttpEntity<String> request = new HttpEntity<>(body, headers);
        log.info("post url: {} headers: {} body:{}", url, headers, body);
        ResponseEntity<String> response;
        try {
            URI uri = new URI(url);
            response = REST.postForEntity(uri, request, String.class);
            if (HttpStatus.OK.value() != response.getStatusCode().value()){
                log.error("http post fail, response : {}",response);
                throw new CertRestRpcException();
            }
        } catch (Exception e) {
            log.error("http error : ",e);
            throw new CertRestRpcException();
        }
        return response.getBody();
    }


}

五、异常捕获器

  • 将模组的异常捕获,并只抛出规定的异常
@Aspect
@Component
@Slf4j
public class CertRestExceptionHandler {

    @Pointcut("execution(* com.pak.service.CertRestService.*(..))")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object catchException(ProceedingJoinPoint joinPoint) throws Throwable {
        //核心业务处理
        try {
            // 获取切点请求参数
            Object[] args = joinPoint.getArgs();
            // 处理
            return joinPoint.proceed(args);
        }catch (Exception e){
            log.error("CertRestExceptionHandler : ",e);
            throw new CertRestRpcException();
        }

    }

}

六、单元测试

@SpringBootApplication
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AccountCertTest.class)
public class AccountCertTest extends TestCase {

    @Resource
    CertRestService certRestService;
    @Resource
    CertPropsConfig propsConfig;

    public static void main(String[] args) {
        SpringApplication.run(AccountCertTest.class, args);
    }

    @Test
    public void rsaTest() {
        AccountCertParamDTO certParam = new AccountCertParamDTO();
        certParam.setIdType(propsConfig.getIdtype());
        certParam.setCertsort(propsConfig.getCertsort());
        certParam.setCertapptype(propsConfig.getCertapptype());
        certParam.setCertstoragetype(propsConfig.getCertstoragetype());
        // 填写参数
        certParam.setIdvalue("xxxx");
        String publicKey_RSA = "xxxx";
        certParam.setSubjectpubkey(publicKey_RSA);

        // 申请证书
        CertResponse response = certRestService.accountCertApply(certParam);
        // 下载证书
        CertDownloadParamDTO downloadParamDTO = new CertDownloadParamDTO();
        downloadParamDTO.setTransactioncode(response.getTransactioncode());
        CertResponse download = certRestService.certDownload(downloadParamDTO);
        // 加密证书
        String enccert = download.getEnccert();
        // 签名证书
        String signcert = download.getSigncert();

        System.out.println(download);

    }
}
  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*crzep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值