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 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 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 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 运行 , |