文章16 | 阅读 8754 | 点赞0
Web service是一个pin独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。
更多理论知识请自行百度一下。
新建项目:springboot-webservice,pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--cxf依赖-->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
新建接口DemoService
@javax.jws.WebService(name="DemoService",targetNamespace = "http://service.springbootwebservice.example.com")
public interface DemoService {
@WebMethod
String say(@WebParam(name = "name") String name);
}
@WebService :该注解用于对接口,类进行注解,表示要发布的web服务
name :暴露服务名称
targetNamespace : 命名空间,一般为接口的包名的倒序
@WebMethod:该注解用于用@WebService注解的类或接口的方法上,表示要发布的方法:
@WebParam:该注解表示方法的参数
实现类DemoServiceImpl.java:
@javax.jws.WebService( serviceName = "DemoService"
,targetNamespace = "http://service.springbootwebservice.example.com"
,endpointInterface = "com.example.springbootwebservice.service.DemoService")
@Component
public class DemoServiceImpl implements DemoService {
@Override
public String say(String name) {
return "我是:" + name;
}
}
** @WebService** :该注解用于对接口,类进行注解,表示要发布的web服务
serviceName :服务名 与接口中指定的name一致
targetNamespace:接口包名倒叙,并且和接口定义保持一致
endpointInterface:接口地址
编写拦截器AuthInterceptor.java:用于访问用户验证
import java.util.List;
import javax.xml.soap.SOAPException;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
//默认登陆用户
private String USERNAME="admin";
//默认登陆用户密码
private String PASSWORD="123456";
public AuthInterceptor() {
// 定义在什么阶段进行拦截
super(Phase.PRE_PROTOCOL);
}
@Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
String username = null;
String password = null;
List<Header> headers = soapMessage.getHeaders();
if(headers == null) {
throw new Fault(new IllegalArgumentException("headers未取到,无法验证用户信息"));
}
// 获取客户端传递的用户名和密码
for (Header header : headers) {
SoapHeader soapHeader = (SoapHeader) header;
Element e = (Element) soapHeader.getObject();
NodeList usernameNode = e.getElementsByTagName("username");
NodeList passwordNode = e.getElementsByTagName("password");
username = usernameNode.item(0).getTextContent();
password = passwordNode.item(0).getTextContent();
if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
throw new Fault(new IllegalArgumentException("用户信息为空!"));
}
}
// 校验客户端用户名密码是否和服务端一致
if(!(username.equals(USERNAME) && password.equals(PASSWORD))) {
throw new Fault(new SOAPException("用户信息认证失败!"));
}
}
}
配置类CxfConfig.java:
@Configuration
public class CxfConfig {
/**
* 此方法作用是改变项目中服务名的前缀名
* wsdl的默认访问地址为http://127.0.0.1:8080/services/* 也就是/service/*
* 我们可以自己配置:wsdl访问地址为:http://127.0.0.1:8080/webservice/*
* 这里我们自定义服务名为/webservice/*
* 当然还可以直接在application.properties文件中加上cxf.path=/webservice
* @return
*/
@Bean
public ServletRegistrationBean servletRegistrationBean() {
ServletRegistrationBean bean = new ServletRegistrationBean(
new CXFServlet(), "/webservice/*");
bean.setLoadOnStartup(0);
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
//把实现类交给spring管理
@Bean
public DemoService webService() {
return new DemoServiceImpl();
}
//终端路径
@Bean
public Endpoint endpoint() {
//绑定要发布的服务
EndpointImpl endpoint = new EndpointImpl(springBus(), webService());
// 服务端添加自定义拦截器 不需要验证可以省略此方法
endpoint.getInInterceptors().add(new AuthInterceptor());
//绑定要发布的服务名称
endpoint.publish("/ws");
return endpoint;
}
}
编写拦截器ClientInterceptor.java:用于在请求头添加用户信息用于验证
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class ClientInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
//登陆用户
private String username;
//登陆密码
private String password;
public ClientInterceptor(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.createElement("authrity");
Element username = doc.createElement("username");
Element password = doc.createElement("password");
username.setTextContent(this.username);
password.setTextContent(this.password);
auth.appendChild(username);
auth.appendChild(password);
headers.add(0, new Header(new QName("tiamaes"), auth));
}
}
编写客户端CxfClient.java
public class Cxfclient {
// 服务端接口地址
private static String address = "http://localhost:8080/webservice/ws?wsdl";
public static void main(String[] args) {
method1();
method2();
}
/**
* 方式1.代理类工厂方式,需要拿到对方的接口
*/
public static void method1() {
try {
// 代理工厂
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
// 设置代理地址
jaxWsProxyFactoryBean.setAddress(address);
// 添加用户信息验证
jaxWsProxyFactoryBean.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));
// 设置接口类型
jaxWsProxyFactoryBean.setServiceClass(DemoService.class);
// 创建一个代理接口实现
DemoService ws = (DemoService) jaxWsProxyFactoryBean.create();
// 调用代理接口的方法调用并返回结果
String result = ws.say("lisi");
System.out.println("代理类工厂方式返回结果:" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 动态调用方式
*/
public static void method2() {
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(address);
// 添加用户信息验证
client.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));
Object[] objects = new Object[0];
try {
// invoke("方法名",参数1,参数2,参数3....);
objects = client.invoke("say", "zhangsan");
System.out.println("动态调用方式结果:" + objects[0]);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
}
注:如果不想要登陆验证请注释以下代码:
1.CxfConfig.java类中endpoint()方法中:endpoint.getInInterceptors().add(new AuthInterceptor());
2.Cxfclient.java类中动态调用方法中:client.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));
3.Cxfclient.java类中工厂调用方法中:jaxWsProxyFactoryBean.getOutInterceptors().add(new ClientInterceptor("admin", "123456"));
其实注释1就可以啦,2、3不注释也没啥影响的。个人习惯!
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/xu12387/article/details/88795540
内容来源于网络,如有侵权,请联系作者删除!