话不多说直接上代码:
准备工作:
创建springBoot项目webservice_server
创建springBoot项目webservice_client
分别添加CXF的依赖:
<!-- CXF webservice -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.1.11</version>
</dependency>
<!-- CXF webservice -->
一.定义要发布的接口和实现类
接口:
@WebService
public interface AppService {
@WebMethod
String getUserName(@WebParam(name = "id") String id) throws UnsupportedEncodingException;
@WebMethod
public User getUser(String id) throws UnsupportedEncodingException;
}
实现类:
//name暴露的服务名称, targetNamespace:命名空间,设置为接口的包名倒写(默认是本类包名倒写). endpointInterface接口地址
@WebService(name = "test" ,targetNamespace ="http://cxf.wolfcode.cn/" ,endpointInterface = "cn.wolfcode.cxf.AppService")
public class AppServiceImpl implements AppService {
JSONResult jsonResult = JSONResult.getJsonResult();
@Override
public String getUserName(String id) throws UnsupportedEncodingException {
System.out.println("==========================="+id);
JSONResult result= JSONResult.getJsonResult();
result.setSuccess(true);
result.setMessage("明哥");
return result.toJsonObject();
}
@Override
public User getUser(String id)throws UnsupportedEncodingException {
System.out.println("==========================="+id);
return new User(1L,"明哥");
}
}
二.发布服务
1.定义配置类
@Configuration
public class CxfConfig {
//默认servlet路径/*,如果覆写则按照自己定义的来
@Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
//把实现类交给spring管理
@Bean
public AppService appService() {
return new AppServiceImpl();
}
//终端路径
@Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), appService());
endpoint.getInInterceptors().add(new AuthInterceptor());//添加校验拦截器
endpoint.publish("/user");
return endpoint;
}
}
2.发布服务
@SpringBootApplication
public class WebserviceApplication {
public static void main(String[] args) {
SpringApplication.run(WebserviceApplication.class, args);
}
}
因为我添加了用户名和密码校验所以在发布之前还需要定义自己校验用户名和密码的Interceptor
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String USERNAME="root";
private static final String PASSWORD="admin";
public AuthInterceptor() {
//定义在哪个阶段进行拦截
super(Phase.PRE_PROTOCOL);
}
@Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
List<Header> headers = null;
String username=null;
String password=null;
try {
headers = soapMessage.getHeaders();
} catch (Exception e) {
logger.error("getSOAPHeader error: {}",e.getMessage(),e);
}
if (headers == null) {
throw new Fault(new IllegalArgumentException("找不到Header,无法验证用户信息"));
}
//获取用户名,密码
for (Header header : headers) {
SoapHeader soapHeader = (SoapHeader) header;
Element e = (Element) soapHeader.getObject();
NodeList usernameNode = e.getElementsByTagName("username");
NodeList pwdNode = e.getElementsByTagName("password");
username=usernameNode.item(0).getTextContent();
password=pwdNode.item(0).getTextContent();
if( StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
throw new Fault(new IllegalArgumentException("用户信息为空"));
}
}
//校验用户名密码
if(!(username.equals(USERNAME) && password.equals(PASSWORD))){
SOAPException soapExc = new SOAPException("认证失败");
logger.debug("用户认证信息错误");
throw new Fault(soapExc);
}
}
}
现在可以发布服务了.....
发布完成后访问http://localhost:8888/services/user?wsdl
能够出现以下界面就是发布OK
三.调用服务
1.新建调用端项目,添加依赖
2.因为示例演示了两种调用方式,其中一种需要用到接口,所以先把服务接口拷贝一份到调用端项目中(代码就是上面接口的代码)
3.因为服务端添加了用户名密码校验,所以调用的时候需要添加用户名密码信息, 所以需要使用下面的Interceptor完成添加用户名密码信息
/**
* Created by sky on 2018/2/27.
*/
public class LoginInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private String username="root";
private String password="admin";
public LoginInterceptor(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 = soapMessage.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElementNS("http://cxf.wolfcode.cn/","SecurityHeader");
Element UserName = doc.createElement("username");
Element UserPass = doc.createElement("password");
UserName.setTextContent(username);
UserPass.setTextContent(password);
auth.appendChild(UserName);
auth.appendChild(UserPass);
headers.add(0, new Header(new QName("SecurityHeader"),auth));
}
}
4.调用接口
/**
* Created by sky on 2018/2/27.
*/
public class Cxfclient {
//webservice接口地址
private static String address = "http://localhost:8888/services/user?wsdl";
//测试
public static void main(String[] args) {
test1();
test2();
}
/**
* 方式1:使用代理类工厂,需要拿到对方的接口
*/
public static void test1() {
try {
// 代理工厂
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
// 设置代理地址
jaxWsProxyFactoryBean.setAddress(address);
//添加用户名密码拦截器
jaxWsProxyFactoryBean.getOutInterceptors().add(new LoginInterceptor("root","admin"));;
// 设置接口类型
jaxWsProxyFactoryBean.setServiceClass(AppService.class);
// 创建一个代理接口实现
AppService cs = (AppService) jaxWsProxyFactoryBean.create();
// 数据准备
String LineId = "1";
// 调用代理接口的方法调用并返回结果
User result = (User)cs.getUser(LineId);
System.out.println("==============返回结果:" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 动态调用方式
*/
public static void test2() {
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(address);
// 需要密码的情况需要加上用户名和密码
client.getOutInterceptors().add(new LoginInterceptor("root","admin"));
Object[] objects = new Object[0];
try {
// invoke("方法名",参数1,参数2,参数3....);
System.out.println("======client"+client);
objects = client.invoke("getUserName", "1");
System.out.println("返回数据:" + objects[0]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
————————————————
版权声明:本文为CSDN博主「__sky__」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41138656/article/details/79393366