Webservice 是一种传统的soa技术架构, 它不依赖于任何的编程语言,也不依赖于任何的技术平台, 可以直接基于http协议实现网络应用间的数据交互
Webservice 服务端是以接口远程接口为主的, 在java实现的webservice技术里面主要依靠的是CXF开发框架,而这个CXF框架可以直接将接口发布成webservice,同时还需要考虑到整个项目之中的安全性问题
[ws-common] 子模块中 ?定义接口
package com.ly.service; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; @WebService(name="MessageService",targetNamespace = "http://service.ly.com") //与包名相反 public interface IMessageService { ??? @WebMethod??? //进行webservice 方法标注 ??? public String echo(@WebParam String msg); } |
[ws-server] 中 定义接口的实现
package com.ly.service.impl; import com.ly.service.IMessageService; import org.springframework.stereotype.Service; import javax.jws.WebService; @WebService(serviceName = "MessageService", ??????????? targetNamespace = "http://service.ly.com",?? //接口命名空间 ??????????? endpointInterface = "com.ly.service.IMessageService")? //接口名称 @Service public class MessageService implements IMessageService { ??? @Override ??? public String echo(String msg) { ??????? return "[Echo]"+msg; ??? } } |
此时webservice 接口开发完成了, 但最终想要使用 还需要一些安全上的配置,
这个安全配置是基于拦截器完成的
[ws-server 中 ]
package com.ly.interceptor; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.springframework.stereotype.Component; import org.w3c.dom.NodeList; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import java.util.Locale; @Component public class WebServiceInterceptorLy extends AbstractPhaseInterceptor<SoapMessage> { ??? private SAAJInInterceptor saaj = new SAAJInInterceptor();//创建拦截器 ??? private static final String USER_NAME="liu"; //用户名 ??? private static final String USER_PASS="ly.com";//密码 ??? public WebServiceInterceptorLy() { ??????? super(Phase.PRE_PROTOCOL); ??????? super.getAfter().add(SAAJInInterceptor.class.getName());//添加拦截 ??? } ??? @Override ??? public void handleMessage(SoapMessage soapMessage) throws Fault { ??????? SOAPMessage content = soapMessage.getContent(SOAPMessage.class); ??????? if(content ==null){ //没有消息内容 ??????????? this.saaj.handleMessage(soapMessage); // 直接走默认处理 ??????????? content = soapMessage.getContent(SOAPMessage.class);//尝试获取消息 ??????? } ??????? SOAPHeader header = null; //soa 头信息 ??????? try { ??????????? header = content.getSOAPHeader(); //通过消息获取头 ??????? } catch (SOAPException e) { ??????????? e.printStackTrace(); ??????? } ??????? if(header==null){? //没有头信息 ????????? throw new Fault(new IllegalAccessException("找不到头信息,无法实现用户认证")); ??????? } ??????? //SOAP 是就xml文件结构进行传输的,所以如果要想获取认证信息必须进行相关的结构约定 ??????? NodeList usernameList = header.getElementsByTagName("username"); ??????? NodeList passwordList = header.getElementsByTagName("password"); ??????? if (usernameList.getLength()<1 || passwordList.getLength()<1){ ??????????? throw new Fault(new IllegalAccessException("找不到头信息,无法实现用户认证")); ??????? } ??????? String username = usernameList.item(0).getTextContent().trim(); ??????? String passsword = passwordList.item(0).getTextContent().trim(); ??????? if(USER_NAME.equals(username) && USER_PASS.equals(passsword)){ //认证合法 ??????????? System.out.println("认证成功-------------"); ??????? }else{ ??????????? SOAPException soapException = new SOAPException("用户认证失败"); ??????????? System.out.println("用户认证失败--------------------"); ??????????? throw new Fault(soapException); ??????? } ??? } } |
[ws-server]
package com.ly.config; import com.ly.interceptor.WebServiceInterceptorLy; import com.ly.service.IMessageService; import org.apache.cxf.Bus; import org.apache.cxf.jaxws.EndpointImpl; import org.apache.cxf.transport.servlet.CXFServlet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.xml.ws.Endpoint; @Configuration public class CXFConfig { ??? @Autowired ??? private Bus bus;? //注入bug接口实例 ??? @Autowired ??? private IMessageService messageService;//注入业务实例 ??? @Autowired ??? private WebServiceInterceptorLy interceptor;//认证拦截器 ??? @Bean ??? public ServletRegistrationBean getRegistrationBean(){ ??????? return new ServletRegistrationBean(new CXFServlet(),"/services/*");? //webservice 访问的父路径 ??? } @Bean ??? public Endpoint messagePoint(){ ??????? EndpointImpl endpoint = new EndpointImpl(this.bus,this.messageService); ??????? endpoint.publish("/MessageService"); ??????? endpoint.getInInterceptors().add(this.interceptor); ??????? return endpoint; ??? } } |
[ws-server]? 创键 启动类
package com.ly; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class WSServer { ??? public static void main(String[] args) { ??????? SpringApplication.run(WSServer.class,args); ??? } } |
启动 ,? 地址栏输入 http://localhost:8080/services
Wsdl 描述文件
[ws-client] 创建一个拦截器 ,来实现认证数据的传递
package com.ly.interceptor; 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.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.xml.namespace.QName; import java.util.List; 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 soap) throws Fault { ??????? List<Header> headers = soap.getHeaders();//获取全部头信息 ??????? Document document = DOMUtils.createDocument();//创建文档 ??????? Element auth = document.createElement("authority");//认证数据信息 ??????? Element username = document.createElement("username");//认证数据信息 ??????? Element password = document.createElement("password");//认证数据信息 ??????? username.setTextContent(this.username); ??????? password.setTextContent(this.password); ??????? auth.appendChild(username); ??????? auth.appendChild(password); ??????? headers.add(0,new Header(new QName("authority"),auth)); ??? } } |
[ws-client]? 基于代理的方式 实现WebService服务调用
package com.ly.client; import com.ly.interceptor.ClientInterceptor; import com.ly.service.IMessageService; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; public class CXFClientProxy { ??? public static void main(String[] args) throws Exception{ ??????? String address = "http://localhost:8080/services/MessageService?wsdl"; ??????? JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean(); ??????? jaxWsProxyFactoryBean.setAddress(address); ??????? jaxWsProxyFactoryBean.setServiceClass(IMessageService.class);// 映射的接口 ??????? jaxWsProxyFactoryBean.getOutInterceptors().add(new ClientInterceptor("liu","ly.com")); ??????? IMessageService service = (IMessageService) jaxWsProxyFactoryBean.create();//远程接口映射 ??????? String message = "hello webservice"; ??????? String result = service.echo(message); ??????? System.out.println("客户端输出----"+result); ??? } } |
启动 ws-server , 启动成功后, 在ws-client中 运行CXFClientProxy的main
控制台 输出
[ws-client]? 通过动态代理方式实现
package com.ly.client; import com.ly.interceptor.ClientInterceptor; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class CXFClientDyn { ??? public static void main(String[] args) throws Exception{ ??????? String address = "http://localhost:8080/services/MessageService?wsdl"; ??????? JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); ??????? Client client = dcf.createClient(address); //创建一个客户端类 ??????? client.getOutInterceptors().add(new ClientInterceptor("liu","ly.com")); ??????? String message = "hello webservice"; ??????? Object[] result = client.invoke("echo",message); ??????? System.out.println("客户端输出333333----"+result[0]); ??? } } 启动 server? 运行 , |