0


SpringBoot集成WebService(wsdl)

pom.xml

<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><!-- 对版本没要求,建议跟我一样 --><version>3.4.4</version></dependency>

创建入口

ApplicationContextUtils.java

bean调用工具

importorg.springframework.beans.BeansException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.stereotype.Component;/**
 * 创建日期:2024-07-01
 */@ComponentpublicclassApplicationContextUtilsimplementsApplicationContextAware{//构造函数私有化,防止其它人实例化该对象privateApplicationContextUtils(){}privatestaticApplicationContext applicationContext;@OverridepublicvoidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException{ApplicationContextUtils.applicationContext = applicationContext;}//通过name获取 Bean.(推荐,因为bean的name是唯一的,出现重名的bean启动会报错。)publicstaticObjectgetBean(String name){return applicationContext.getBean(name);}//通过class获取Bean.(确保bean的name不会重复。因为可能会出现在不同包的同名bean导致获取到2个实例)publicstatic<T>TgetBean(Class<T> clazz){return applicationContext.getBean(clazz);}//通过name,以及Clazz返回指定的Bean(这个是最稳妥的)publicstatic<T>TgetBean(String name,Class<T> clazz){return applicationContext.getBean(name, clazz);}publicstatic<T>Map<String,T>getBeansOfType(Class<T> clazz){return applicationContext.getBeansOfType(clazz);}}

JacksonUtils.java

Jackson 工具类

importcom.fasterxml.jackson.annotation.JsonInclude;importcom.fasterxml.jackson.databind.DeserializationFeature;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.SerializationFeature;importcom.fasterxml.jackson.dataformat.xml.XmlMapper;importcom.fasterxml.jackson.datatype.jsr310.JavaTimeModule;/**
 * jackson 工具类
 */publicabstractclassJacksonUtils{publicstaticfinalObjectMapperJSON=newObjectMapper();publicstaticfinalObjectMapperXML=newXmlMapper();static{// json 配置JSON.setSerializationInclusion(JsonInclude.Include.NON_NULL);JSON.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);JSON.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);JSON.registerModule(newJavaTimeModule());//处理java8新日期时间类型// xml 配置XML.setSerializationInclusion(JsonInclude.Include.NON_NULL);XML.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);XML.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);XML.registerModule(newJavaTimeModule());//处理java8新日期时间类型}}

IWebService.java

统一入口

/**
 * 统一 post 调用
 * 创建日期:2024-07-01
 */publicinterfaceIWebService<T>{Objecthandle(T req);}

WebServiceEntry.java

importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Service;importjavax.jws.WebMethod;importjavax.jws.WebParam;importjavax.jws.WebService;/**
 * 创建日期:2024-07-01
 */@Slf4j@Service@WebServicepublicclassWebServiceEntry{/**
     * 通过实现了 IWebService 接口的 bean name 反射调用 handle 方法
     *
     * @param service   bean name
     * @param parameter XML 字符串请求参数
     */@WebMethod@SuppressWarnings("unchecked")public<T>Stringinvoke(@WebParam(name ="service")String service,@WebParam(name ="parameter")String parameter)throwsJsonProcessingException{IWebService<T> webService =(IWebService<T>)ApplicationContextUtils.getBean(service);// 通过缓存获取 IWebService 实现类的 handle 函数泛型类型入参,这样就不用每次请求都通过反射去获取入参,提升了程序性能。Class<T> parameterType =(Class<T>)WebServiceTypeCache.getParameterType(service);// 使用 Jackson-XML 将 XML 字符串转换为 Java 对象T reqObject =JacksonUtils.XML.readValue(parameter, parameterType);R<?> r;try{
            r =R.ok(webService.handle(reqObject));}catch(Exception e){String message = e.getMessage();
            log.error(message, e);
            r =R.err(message);}returnJacksonUtils.XML.writeValueAsString(r);}}

WebServiceTypeCache.java

启动的时候把 IWebService实现类 handle函数的泛型入参写入缓存,在请求的时候直接通过缓存获取泛型入参的类型,减少每次请求的时候都使用反射获取泛型入参,提升程序性能。

importorg.springframework.boot.ApplicationArguments;importorg.springframework.boot.ApplicationRunner;importorg.springframework.stereotype.Component;importjava.lang.reflect.ParameterizedType;importjava.lang.reflect.Type;importjava.util.HashMap;importjava.util.Map;/**
 * 启动的时候把 IWebService实现类 handle函数的泛型入参写入缓存,在请求的时候直接通过缓存获取泛型入参的类型,
 * 减少每次请求的时候都使用反射获取泛型入参,提升程序性能。
 *
 * @since 2024-08-09
 */@ComponentpublicclassWebServiceTypeCacheimplementsApplicationRunner{/**
     * 只能在启动的时候 put,运行的时候 get。不能在运行的时候 put,因为 HashMap 不是线程安全的。
     */privatestaticfinalMap<String,Class<?>> typeCache =newHashMap<>();@Overridepublicvoidrun(ApplicationArguments args)throwsException{Map<String,IWebService> beans =ApplicationContextUtils.getBeansOfType(IWebService.class);//循环map,forEach(key,value) 是最现代的方式,使用起来简洁明了。也可以用 for (Map.Entry<String, IWebService> entry : beans.entrySet()){}。
        beans.forEach((bean, type)->{// AopProxyUtils.ultimateTargetClass 解决Spring Boot 使用 @Transactional 事务注解的问题。Class<?> beanClass =AopProxyUtils.ultimateTargetClass(type);// 获取 IWebService 实现类的泛型类型Type[] genericInterfaces = beanClass.getGenericInterfaces();for(Type genericInterface : genericInterfaces){if(genericInterface instanceofParameterizedType){ParameterizedType parameterizedType =(ParameterizedType) genericInterface;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();if(actualTypeArguments.length >0){Class<?> parameterType =(Class<?>) actualTypeArguments[0];//把泛型入参放入缓存。防止每次请求都通过反射获取入参,影响程序性能。
                        typeCache.put(bean, parameterType);}}}});}/**
     * 通过缓存获取 IWebService 实现类 handle 函数的 泛型入参
     *
     * @param serviceName IWebService实现类的 bean name
     */publicstaticClass<?>getParameterType(String serviceName){return typeCache.get(serviceName);}}

WebServiceConfig.java

配置类
有些依赖千万不要导错,所以我依赖都粘贴进来了。防止导错包。

importorg.apache.cxf.Bus;importorg.apache.cxf.bus.spring.SpringBus;importorg.apache.cxf.jaxws.EndpointImpl;importorg.apache.cxf.transport.servlet.CXFServlet;importorg.springframework.boot.web.servlet.ServletRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.xml.ws.Endpoint;/**
 * 创建日期:2024-07-01
 */@ConfigurationpublicclassWebServiceConfig{@Bean(name ="cxfServlet")publicServletRegistrationBean<?>cxfServlet(){//urlMappings默认是:servicesreturnnewServletRegistrationBean<>(newCXFServlet(),"/services/*");}@Bean(name =Bus.DEFAULT_BUS_ID)publicSpringBusspringBus(){returnnewSpringBus();}@BeanpublicEndpointhelloServiceEndpoint(){EndpointImpl endpoint =newEndpointImpl(springBus(),newWebServiceEntry());//services后面的uri地址
        endpoint.publish("/WebServiceEntry");return endpoint;}}

WebMvcConfig.java

web的配置类,因为增加了xml依赖,springboot会默认把json放到xml后面,因此要手动改回默认json。

importorg.springframework.context.annotation.Configuration;importorg.springframework.http.MediaType;importorg.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{@OverridepublicvoidconfigureContentNegotiation(ContentNegotiationConfigurer configurer){//引入 jackson-dataformat-xml 后,原本默认返回json变成了默认返回xml。因此这里要设置默认返回json
        configurer.defaultContentType(MediaType.APPLICATION_JSON);}}

实现IWebService接口

如:WebServiceImpl

@Service("Hello")publicclassHelloimplementsIWebService<HelloReq>{@OverridepublicHelloReshandle(HelloReq req){String name = req.getName();List<Work> works = req.getWorks();if(!StringUtils.hasText(name)){thrownewRuntimeException("Name 不能为空");}if(!CollectionUtils.isEmpty(works)){for(Work work : works){String workName = work.getWorkName();
                log.info("workName={}", workName);}}HelloRes res =newHelloRes();
        res.setName(name);
        res.setAge(18);return res;}}

HelloReq.java

importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;importlombok.Data;importjava.util.List;@Data@JacksonXmlRootElement(localName ="Params")publicclassHelloReq{@JacksonXmlProperty(localName ="Name")privateString name;@JacksonXmlElementWrapper(localName ="Works")@JacksonXmlProperty(localName ="Work")privateList<Work> works;}

HelloRes.java

importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;importlombok.Data;@DatapublicclassHelloRes{@JacksonXmlProperty(localName ="Name")privateString name;@JacksonXmlProperty(localName ="Age")privateInteger age;}

Work.java

importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;importlombok.Data;@Data@JacksonXmlRootElement(localName ="Work")publicclassWork{@JacksonXmlProperty(localName ="WorkName")privateString workName;}

统一返回类

importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;importcom.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;/**
 * 统一返回类
 * 创建日期:2024-07-01
 */@Data@NoArgsConstructor(access =lombok.AccessLevel.PRIVATE)@AllArgsConstructor(access =lombok.AccessLevel.PRIVATE)@JacksonXmlRootElement(localName ="R")publicclassR<T>{@JacksonXmlProperty(localName ="Code")privateInteger code;@JacksonXmlProperty(localName ="Message")privateString message;@JacksonXmlProperty(localName ="Data")privateT data;publicstatic<T>R<T>ok(){returnok(null);}publicstatic<T>R<T>ok(T data){returnnewR<>(200,"success", data);}publicstatic<T>R<T>err(String message){returnerr(400, message);}publicstatic<T>R<T>err(Integer code,String message){returnnewR<>(code, message,null);}}

启动SpringBoot

访问

http://localhost:8080/services/WebServiceEntry?wsdl

会出现如下所示界面
在这里插入图片描述

用soapUI去调用接口

ws = "http://ws.bsjkt.bsoft.com/"这里每个人可能不一样
service = bean name
parameter = XML 请求参数

入参

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.springbootwebservicedemo.fu.com/"><soapenv:Header/><soapenv:Body><ws:invoke><service>Hello</service><parameter><![CDATA[<Params><Name>哈哈</Name><Works><Work><WorkName>Java</WorkName></Work></Works></Params>]]></parameter></ws:invoke></soapenv:Body></soapenv:Envelope>

出参

<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:invokeResponsexmlns:ns2="http://ws.springbootwebservicedemo.fu.com/"><return>&lt;R&gt;&lt;Code&gt;200&lt;/Code&gt;&lt;Message&gt;success&lt;/Message&gt;&lt;Data&gt;&lt;Name&gt;哈哈&lt;/Name&gt;&lt;Age&gt;18&lt;/Age&gt;&lt;/Data&gt;&lt;/R&gt;</return></ns2:invokeResponse></soap:Body></soap:Envelope>
标签: spring boot java 后端

本文转载自: https://blog.csdn.net/weixin_43933728/article/details/140109357
版权归原作者 Meta39 所有, 如有侵权,请联系我们删除。

“SpringBoot集成WebService(wsdl)”的评论:

还没有评论