SpringBoot2.3整合WebService实现远程调⽤
1. 概述
最近接⼿了⼀个⽼项⽬,项⽬中⽤到了WebService技术,WebService试⼀种传统的SOA技术架构,它不依赖于任何编程语⾔,也不依赖于任何技术平台,可以直接基于HTTP协议实现⽹络应⽤之间的数据交互。WebService组成架构采⽤传统的"C/S"模型,如果某个平台需要对外暴露操作接⼝,这个时候就可以直接通过WSDL(Web Services Description Language)Web服务描述语⾔对要公布的接⼝进⾏描述。
WebService服务端是以远程接⼝为主的,在Java实现的WebService技术⾥主要依靠CXF开发框架,⽽这个CXF开发框架可以直接将接⼝发布成WebService。
CXF⼜分为JAX-WS和JAX-RS,JAX-WS是基于xml协议,⽽JAX-RS是基于Restful风格,两者的区别如下:RS基于Restful风格,WS基于SOAP的XML协议
RS⽐WS传输的数据更少,效率更⾼
WS只能传输XML数据,RS可以传输XML,也可以传输JSON
2. JAX-WS开发
2.1. 接⼝开发
新建⼀个⼯程,引⼊核⼼依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>f</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.4.5</version>
</dependency>
新建实体类
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
@XmlRootElement
public class UserInfo implements Serializable {
private static final long serialVersionUID =-5352429333001227976L;
private Long id;
private String username;
private String password;
}
新建接⼝
@WebService(name ="userInfoService", targetNamespace ="service.api.ws.webservice.boot.xlhj/")
public interface UserInfoService {
@WebMethod(operationName ="saveUserInfo")
void saveUserInfo(@WebParam(name ="userInfo") UserInfo userInfo);
@WebMethod
UserInfo getUserInfoById(@WebParam(name ="id") Long id);
}
2.2. 服务端开发
新建接⼝实现类
@Service
@WebService(serviceName ="userInfoService", targetNamespace ="service.api.ws.webservice.boot.xlhj/", endpointInterface ="com.xlhj.boot.w ebservice.ws.api.service.UserInfoService")
public class UserInfoServiceImpl implements UserInfoService {
@Override
public void saveUserInfo(UserInfo userInfo){
System.out.println("保存⽤户信息成功"+ String());
}
@Override
public UserInfo getUserInfoById(Long id){
return UserInfo.builder().id(1L).username("zhangsan").password("123456").build();
}
}
新建配置类
@Configuration
public class CXFConfig {
@Autowired
private Bus bus;
@Autowired
private UserInfoService userInfoService;
@Autowired
private WebServiceAuthInterceptor interceptor;
/**
* 设置WebService访问⽗路径
* @return
*/
@Bean
public ServletRegistrationBean getRegistrationBean(){
return new ServletRegistrationBean(new CXFServlet(),"/services/*");
}
@Bean
public Endpoint messageEndPoint(){
EndpointImpl endpoint =new EndpointImpl(this.bus,this.userInfoService);
endpoint.publish("/userInfoService");
return endpoint;
}
}
新建类
@Component
public class WebServiceAuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
/**⽤户名*/
private static final String USER_NAME ="xxxx";
/
**密码*/
private static final String USER_PASSWORD ="xlhj";
private static final String NAME_SPACE_URI ="service.api.ws.webservice.boot.xlhj/";
/**创建*/
private SAAJInInterceptor interceptor =new SAAJInInterceptor();
private static final Logger logger = Logger(WebServiceAuthInterceptor.class);
public WebServiceAuthInterceptor(){
super(Phase.PRE_PROTOCOL);
//添加拦截
}
@Override
public void handleMessage(SoapMessage message)throws Fault {
//获取指定消息
SOAPMessage soapMessage = Content(SOAPMessage.class);
if(null== soapMessage){
this.interceptor.handleMessage(message);
soapMessage = Content(SOAPMessage.class);
}
//SOAP头信息
SOAPHeader header =null;
try{
header = SOAPHeader();
}catch(SOAPException e){
e.printStackTrace();
}
if(null== header){
throw new Fault(new IllegalAccessException("没有Header信息,⽆法实现⽤户认证处理!"));
}
//SOAP是基于XML⽂件结构进⾏传输的,所以如果要想获取认证信息就必须进⾏相关的结构约定
NodeList usernameNodeList = ElementsByTagNameNS(NAME_SPACE_URI,"username");        NodeList passwordNodeList = ElementsByTagNameNS(NAME_SPACE_URI,"password");
Length()<1){
throw new Fault(new IllegalAccessException("没有⽤户信息,⽆法实现⽤户认证处理!"));
}
Length()<1){
throw new Fault(new IllegalAccessException("没有密码信息,⽆法实现⽤户认证处理!"));
}
String username = usernameNodeList.item(0).getTextContent().trim();
String password = passwordNodeList.item(0).getTextContent().trim();
if(USER_NAME.equals(username)&& USER_PASSWORD.equals(password)){
logger.debug("⽤户访问认证成功!");
}else{
SOAPException soapException =new SOAPException("⽤户认证失败!");
logger.debug("⽤户认证失败!");
throw new Fault(soapException);
}
}
}
新建主启动类后启动项⽬,在浏览器输⼊地址localhost:8235/services/
点击WSDL链接可以查看到具体的接⼝信息
2.3. 客户端开发
新建客户端类
public class ClientLoginInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
private String username;
private String password;
private static final String NAME_SPACE_URI ="service.api.ws.webservice.boot.xlhj/";
public ClientLoginInterceptor(String username, String password){
super(Phase.PREPARE_SEND);
this.username = username;
this.password = password;
}
@Override
public void handleMessage(SoapMessage soapMessage)throws Fault {
List<Header> headers = Headers();
Document document = ateDocument();
Element authority = ateElementNS(NAME_SPACE_URI,"authority");
Element username = ateElementNS(NAME_SPACE_URI,"username");
Element password = ateElementNS(NAME_SPACE_URI,"password");
username.setTextContent(this.username);
password.setTextContent(this.password);
authority.appendChild(username);
authority.appendChild(password);
headers.add(0,new Header(new QName("authority"), authority));
}
}
新建客户端接⼝
@Component
public class UserInfoApiClient {
private static final String USERNAME ="xxxx";
private static final String PASSWORD ="xlhj";
private static final String ADDRESS ="localhost:8235/services/userInfoService?wsdl";
/**
* 使⽤代理⽅法
* @param userInfo
调用webservice服务
*/
public void saveUserInfoWithProxy(UserInfo userInfo){
JaxWsProxyFactoryBean jaxWsProxyFactoryBean =new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setAddress(ADDRESS);
jaxWsProxyFactoryBean.setServiceClass(UserInfoService.class);
new ClientLoginInterceptor(USERNAME, PASSWORD)
);
UserInfoService userInfoService =(UserInfoService) ate();
userInfoService.saveUserInfo(userInfo);
}
/**
* 使⽤动态代理
* @param id
* @throws Exception
*/
public void getUserInfoByIdWithDynamic(Long id)throws Exception {
JaxWsDynamicClientFactory clientFactory = wInstance();
Client client = ateClient(ADDRESS);
Object[] userInfos = client.invoke("getUserInfoById", id);
String userInfo = userInfos[0].toString();
System.out.println(userInfo);
}
}
2.4. 测试验证
@SpringBootTest
class WebServiceWSClientApplicationTest {
@Autowired
private UserInfoApiClient userInfoApiClient;
@Test
void saveUserInfoWithProxy(){
UserInfo userInfo =new UserInfo();
userInfo.setId(1L);
userInfo.setUsername("张三");
userInfo.setPassword("123456");
userInfoApiClient.saveUserInfoWithProxy(userInfo);
}
@Test
void getUserInfoByIdWithDynamic()throws Exception {
}
}
注意:客户端使⽤动态代理访问时,参数中有bean对象时会提⽰类型转换错误异常,有解决办法的⼩伙伴欢迎在评论区留⾔3. JAX-RS开发

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。