Springboot publishes the WebService service and invokes (hutool yyds)
preface
Recently, the company's projects need to connect with third-party services. This service provider uses the interface opened by WebService to provide calls
Because it is an intranet project, the server for mapping the intranet to the extranet has not been provided. Therefore, in order not to work overtime in the future (is this true? Self consolation BA), I wrote a springboot service, published the WS service and put it on the server to practice
The last blog (pringboot packaged into docker (idea + traditional way)) is actually after this blog
I had to write yesterday. However, my computer can only play games. I wanted to write yesterday and found that I didn't even have typora Don't talk about the picture bed, GIT, write a hook~
In addition, the steam plant is on sale. Don't you buy it yet
Open dry
1. Technical points involved
Springboot + WebService + hutool (mainly a SoapClient calling WS)
Previous radio chart
It is said that the earlier hutool is used, the earlier I get off work, but I can't rule out the overtime caused by not using it
2. Overall project structure
3. Provider publishes WS server
First, be sure to modify the POM file
Dependency plus
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 小辣椒,简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--发布ws需要用到的依赖-->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.4.5</version>
</dependency>
<!-- hutool 的包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.14</version>
</dependency>
</dependencies>
3.0 because the parameter is reversed in the form of an object, an object is created
UserLoginVO
package com.jinsc.provider.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 用户登录VO
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @since Created in 2021/10/21 23:28
*/
@Data
public class UserLoginVO implements Serializable {
private static final long serialVersionUID = 2673128718180426817L;
private Integer errorCode;
private String errMsg;
private String name;
public UserLoginVO() {
}
public UserLoginVO(Integer errorCode,String errMsg,String name) {
this.errorCode = errorCode;
this.errMsg = errMsg;
this.name = name;
}
}
3.1 first write a service. The only difference is that the annotation uses WS annotation
LoginService
package com.jinsc.provider.service;
import com.jinsc.provider.vo.UserLoginVO;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* ws的登录接口
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @since Created in 2021/10/21 11:01
*/
@WebService(name = "LoginService",//暴露服务名称
targetNamespace = "http://jinsc.com" //空间名称
)
public interface LoginService {
UserLoginVO userLogin(@WebParam(name = "name") String name);
}
3.2 write his implementation class
LoginServiceImpl
package com.jinsc.provider.service.impl;
import com.jinsc.provider.service.LoginService;
import com.jinsc.provider.vo.UserLoginVO;
import org.springframework.stereotype.Service;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* ws的登录接口实现类
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @since Created in 2021/10/21 11:05
*/
@WebService(serviceName = "LoginService",// 与接口中的name保持一致
targetNamespace = "http://jinsc.com",// 与接口中的name保持一致
endpointInterface = "com.jinsc.provider.service.LoginService" // 接口包路径
)
// 用于配置类自动注入
@Service
public class LoginServiceImpl implements LoginService {
@Override
public UserLoginVO userLogin(@WebParam(name = "name") String name) {
return new UserLoginVO(500,"登录失败~~",name);
}
}
3.3 write CXF configuration class of WS
CxfConfig
package com.jinsc.provider.config;
import com.jinsc.provider.service.LoginService;
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.annotation.Resource;
import javax.xml.ws.Endpoint;
/**
* ws的配置类
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @since Created in 2021/10/21 11:14
*/
@Configuration
public class CxfConfig {
@Resource
private LoginService loginService;
/**
* 用于注册CXFServlet的
* 地址/webservice/*
* * 通配符 更上接口地址
*
* @return org.springframework.boot.web.servlet.ServletRegistrationBean<org.apache.cxf.transport.servlet.CXFServlet>
* @author 金聖聰
* @email jinshengcong@163.com
* Modification History:
* Date Author Description version
* --------------------------------------------------------*
* 2021/10/21 11:25 金聖聰 修改原因 1.0
*/
@Bean
public ServletRegistrationBean<CXFServlet> dispatcherServlet2() {
// 这里就是发布服务的跟路径,后面 * 是通配符,表示跟什么都行
return new ServletRegistrationBean<>(new CXFServlet(),"/webservice/*");
}
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
@Bean
public Endpoint endpoint() {
// 建立一个端点,第一个参数是 springBus 对象,第二个参数是刚才的接口实现类(因为在实现类中用了@service,所以这里可以自动注入)
// PS: 要是有多个service,这个方法对象多写几个就行
EndpointImpl endpoint = new EndpointImpl(springBus(),loginService);
// 这里就是发布的这个接口的地址
endpoint.publish("/loginApi");
return endpoint;
}
}
In this way, the WS can be published
the address is
IP: port / WebService / loginapi? wsdl
Local startup is
http://localhost:8080/webservice/loginApi?wsdl
Above, published successfully
4. The consumer calls the WS side, so I call it the consumer side
Similarly, give POM dependency
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 小辣椒简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- hutool的包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.14</version>
</dependency>
</dependencies>
4.0 because parameters are parsed as objects, objects are created
UserLoginDto
package com.jinsc.consumer.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 用户登录Dto
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @since Created in 2021/10/21 23:36
*/
@Data
public class UserLoginDto implements Serializable {
private static final long serialVersionUID = 1292974846576856351L;
private String errMsg;
private String name;
private String errorCode;
}
4.1 creating a client to call WS service is ojbk enough
But before that, we use soapUI to resolve the WS address just now
From above, we can get
Namespace: http://jinsc.com
Method name: Jin: Userlogin
Input parameter: name
So we can create SoapClient
TestWsConnect
package com.jinsc.consumer.client;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.webservice.soapClient;
import com.jinsc.consumer.dto.UserLoginDto;
import org.w3c.dom.Document;
import javax.xml.xpath.XPathConstants;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* 测试ws连接
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @since Created in 2021/10/21 23:35
*/
public class TestWsConnect {
public static void main(String[] args) {
// 新建客户端
SoapClient client = SoapClient.create("http://localhost:8080/webservice/loginApi?wsdl")
// SoapClient client = SoapClient.create("http://服务器端口地址/webservice/loginApi?wsdl")
// 设置要请求的方法,此接口方法前缀为web,传入对应的命名空间
.setMethod("jin:userLogin","http://jinsc.com")
// 设置参数,此处自动添加方法的前缀:jin
// false的意思就是没有前缀
.setParam("name","jinshengcong3080ti",false);
// 发送请求,参数true表示返回一个格式化后的XML内容
// 返回内容为XML字符串,可以配合XmlUtil解析这个响应
String send = client.send(true);
Console.log(send);
// 把send返回的xml内容转换成document对象
Document document = XmlUtil.parseXml(send);
List<String> nameList = Arrays.asList("errMsg","errorCode","name");
HashMap<String,String> resultMap = new HashMap<>();
nameList.forEach(e -> {
// 循环上面的nameList列表,每个元素都是return后面的标签,得标签里面的值
String result = (String) XmlUtil.getByXPath("//return/" + e,document,XPathConstants.STRING);
// 然后给结果map赋值,key是name,value是标签中的值
resultMap.put(e,result);
});
// 得到结果map
Console.log(resultMap);
// map转Dto,其中属性要一致
UserLoginDto convert = Convert.convert(UserLoginDto.class,resultMap);
Console.log(convert);
}
}
That's it
Run Kangkang~
All right, ojbk