SpringBoot集成WebService(wsdl)
SDL
Simple Directmedia Layer
项目地址:https://gitcode.com/gh_mirrors/sd/SDL
免费下载资源
·
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调用工具
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 创建日期:2024-07-01
*/
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
//构造函数私有化,防止其它人实例化该对象
private ApplicationContextUtils() {
}
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtils.applicationContext = applicationContext;
}
//通过name获取 Bean.(推荐,因为bean的name是唯一的,出现重名的bean启动会报错。)
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
//通过class获取Bean.(确保bean的name不会重复。因为可能会出现在不同包的同名bean导致获取到2个实例)
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean(这个是最稳妥的)
public static <T> T getBean(String name, Class<T> clazz) {
return applicationContext.getBean(name, clazz);
}
public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
return applicationContext.getBeansOfType(clazz);
}
}
JacksonUtils.java
Jackson 工具类
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
/**
* jackson 工具类
*/
public abstract class JacksonUtils {
public static final ObjectMapper JSON = new ObjectMapper();
public static final ObjectMapper XML = new XmlMapper();
static {
// json 配置
JSON.setSerializationInclusion(JsonInclude.Include.NON_NULL);
JSON.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
JSON.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
JSON.registerModule(new JavaTimeModule());//处理java8新日期时间类型
// xml 配置
XML.setSerializationInclusion(JsonInclude.Include.NON_NULL);
XML.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
XML.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
XML.registerModule(new JavaTimeModule());//处理java8新日期时间类型
}
}
IWebService.java
统一入口
/**
* 统一 post 调用
* 创建日期:2024-07-01
*/
public interface IWebService<T> {
Object handle(T req);
}
WebServiceEntry.java
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* 创建日期:2024-07-01
*/
@Slf4j
@Service
@WebService
public class WebServiceEntry {
/**
* 通过实现了 IWebService 接口的 bean name 反射调用 handle 方法
*
* @param service bean name
* @param parameter XML 字符串请求参数
*/
@WebMethod
@SuppressWarnings("unchecked")
public <T> String invoke(@WebParam(name = "service") String service, @WebParam(name = "parameter") String parameter) throws JsonProcessingException {
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);
}
return JacksonUtils.XML.writeValueAsString(r);
}
}
WebServiceTypeCache.java
启动的时候把 IWebService实现类 handle函数的泛型入参写入缓存,在请求的时候直接通过缓存获取泛型入参的类型,减少每次请求的时候都使用反射获取泛型入参,提升程序性能。
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
/**
* 启动的时候把 IWebService实现类 handle函数的泛型入参写入缓存,在请求的时候直接通过缓存获取泛型入参的类型,
* 减少每次请求的时候都使用反射获取泛型入参,提升程序性能。
*
* @since 2024-08-09
*/
@Component
public class WebServiceTypeCache implements ApplicationRunner {
/**
* 只能在启动的时候 put,运行的时候 get。不能在运行的时候 put,因为 HashMap 不是线程安全的。
*/
private static final Map<String, Class<?>> typeCache = new HashMap<>();
@Override
public void run(ApplicationArguments args) throws Exception {
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 instanceof ParameterizedType) {
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
*/
public static Class<?> getParameterType(String serviceName) {
return typeCache.get(serviceName);
}
}
WebServiceConfig.java
配置类
有些依赖千万不要导错,所以我依赖都粘贴进来了。防止导错包。
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.xml.ws.Endpoint;
/**
* 创建日期:2024-07-01
*/
@Configuration
public class WebServiceConfig {
@Bean(name = "cxfServlet")
public ServletRegistrationBean<?> cxfServlet() {
//urlMappings默认是:services
return new ServletRegistrationBean<>(new CXFServlet(), "/services/*");
}
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
@Bean
public Endpoint helloServiceEndpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new WebServiceEntry());
//services后面的uri地址
endpoint.publish("/WebServiceEntry");
return endpoint;
}
}
WebMvcConfig.java
web的配置类,因为增加了xml依赖,springboot会默认把json放到xml后面,因此要手动改回默认json。
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
//引入 jackson-dataformat-xml 后,原本默认返回json变成了默认返回xml。因此这里要设置默认返回json
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
实现IWebService接口
如:WebServiceImpl
@Service("Hello")
public class Hello implements IWebService<HelloReq> {
@Override
public HelloRes handle(HelloReq req) {
String name = req.getName();
List<Work> works = req.getWorks();
if (!StringUtils.hasText(name)) {
throw new RuntimeException("Name 不能为空");
}
if (!CollectionUtils.isEmpty(works)) {
for (Work work : works) {
String workName = work.getWorkName();
log.info("workName={}", workName);
}
}
HelloRes res = new HelloRes();
res.setName(name);
res.setAge(18);
return res;
}
}
HelloReq.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@JacksonXmlRootElement(localName = "Params")
public class HelloReq {
@JacksonXmlProperty(localName = "Name")
private String name;
@JacksonXmlElementWrapper(localName = "Works")
@JacksonXmlProperty(localName = "Work")
private List<Work> works;
}
HelloRes.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.Data;
@Data
public class HelloRes {
@JacksonXmlProperty(localName = "Name")
private String name;
@JacksonXmlProperty(localName = "Age")
private Integer age;
}
Work.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
@Data
@JacksonXmlRootElement(localName = "Work")
public class Work {
@JacksonXmlProperty(localName = "WorkName")
private String workName;
}
统一返回类
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 统一返回类
* 创建日期:2024-07-01
*/
@Data
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
@AllArgsConstructor(access = lombok.AccessLevel.PRIVATE)
@JacksonXmlRootElement(localName = "R")
public class R<T> {
@JacksonXmlProperty(localName = "Code")
private Integer code;
@JacksonXmlProperty(localName = "Message")
private String message;
@JacksonXmlProperty(localName = "Data")
private T data;
public static <T> R<T> ok() {
return ok(null);
}
public static <T> R<T> ok(T data) {
return new R<>(200, "success", data);
}
public static <T> R<T> err(String message) {
return err(400, message);
}
public static <T> R<T> err(Integer code, String message) {
return new R<>(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:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:invokeResponse xmlns:ns2="http://ws.springbootwebservicedemo.fu.com/">
<return><R><Code>200</Code><Message>success</Message><Data><Name>哈哈</Name><Age>18</Age></Data></R></return>
</ns2:invokeResponse>
</soap:Body>
</soap:Envelope>
GitHub 加速计划 / sd / SDL
8.9 K
1.68 K
下载
Simple Directmedia Layer
最近提交(Master分支:2 个月前 )
a57c5669 - 2 个月前
20a6193e - 2 个月前
更多推荐
已为社区贡献9条内容
所有评论(0)