WebService_疯狂java_02

本文介绍了WebService的调用过程及其实现原理,探讨了如何通过SOAP消息的Header部分进行权限控制,包括客户端和服务端的拦截器实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WebService的调用本质:
   
1)客户端把需要调用的参数,转换为XML文档片段(SOAP消息)
   
2)客户端通过网络把XML文档片段传给远程服务器。
   
3)服务器接受XML文档片段。
   
4)服务器解析XML文档片段,提取其中的数据,并把数据转换为调用所需的参数。
   
5)服务器执行方法。
   
6)得到方法返回值,服务器把方法返回值,转换为XML文档片段(SOAP消息)。
   
7)服务器通过网络把XML文档片段传给远程客户端。
   
8)客户端接收XML文档片段。
   
9)客户端解析XML文档片段,提取其中的数据,并把数据转换为调用返回值。

WebService的三个技术基础:
    - WSDL
         Web Service
接口
            1.types(
标准的Schema)
             2.2N
message
            3.portType  -  N
operation
        Web Service
实现
            1.binding
元素 -  N个更详细的operation
            2.service      - 
指定Web Service的服务器地址。
    - SOAP
         Header
             Header
是可选的。由程序员控制添加。
         Body
             Body
元素总是默认的。Body元素里可有两种情况,
             -
WebService交互正确时,Body元素里的内容由WSDL控制。
             -
WebService交互出错时,Body元素的内容将是Fault子元素。
       


Web Service
急需解决的问题,如何进行权限控制?
  

 解决思路是:服务器端要求input消息总是携带有用户名、密码消息,
--
如果没有用户名、密码信息,直接拒绝调用。

如果不用CXF等框架,SOAP消息的生成、解析都是由程序员负责的,
   
无论是添加用户名、密码信息,还是提取用户名、密码信息,都可有程序员的代码完成。

如果用CXF等框架,SOAP消息的生成、解析都是CXF等框架负责来完成度的。

==================
拦截器
  
为了让程序员能访问、并修改CXF框架所生成的SOAP消息,CXF提供了拦截器。

  服务器端添加拦截器
     
1)获取Endpointpublish方法返回值。
     
2)调用该方法的返回值的getInInterceptorgetOutInterceptor方法来
          
获取Inout拦截器列表,接下来就可以添加拦截器了。

  客户端添加拦截器:
     
1)调用ClientProxygetClient方法,调用该方法以远程WebService的代理为参数。
     
2)调用Client对象的getInInterceptorgetOutInterceptor方法来
          
获取InOut拦截器列表,接下来就可以添加拦截器了。

对于sayHi操作:
传入消息
<?xml version="1.0" ?>
<S:Envelopexmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
        <S:Body>
           <ns2:sayHixmlns:ns2="http://ws.cxf.fkjava.org/">
             <text>
孙悟空</text>
           </ns2:sayHi>
        </S:Body>
</S:Envelope>

传出消息
<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
               <ns2:sayHiResponse xmlns:ns2="http://ws.cxf.fkjava.org/">
                       <return>
孙悟空,您好现在时间是:Thu Jan03 17:58:39 CST 2013</return>
               </ns2:sayHiResponse>
        </soap:Body>
</soap:Envelope>

对于getAllCats操作:
传入消息
<?xml version="1.0" ?>
<S:Envelopexmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
        <S:Body>
            <ns2:getAllCats xmlns:ns2="http://ws.cxf.fkjava.org/"/>
        </S:Body>
</S:Envelope>

传出消息
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
               <ns2:getAllCatsResponse xmlns:ns2="http://ws.cxf.fkjava.org/">
                       <return>
                             <entries>
                                   <key>
4</key>
                                   <value>
                                       <color>
黑白色</color>
                                       <id>4</id>
                                       <name>
熊猫</name>
                                   </value>
                             </entries>
                             <entries>
                                   <key>
3</key>
                                   <value>
                                       <color>
白色</color>
                                       <id>3</id>
                                       <name>kitty</name>
                                  </value>
                            </entries>
                            <entries>
                                  <key>
1</key>
                                  <value>
                                      <color>
橙色</color>
                                      <id>1</id>
                                      <name>garfield</name>
                                  </value>
                            </entries>
                            <entries>
                                  <key>
2</key>
                                  <value>
                                      <color>
蓝色</color>
                                      <id>2</id>
                                      <name>
机器猫</name>
                                  </value>
                            </entries>
                      </return>
               </ns2:getAllCatsResponse>
        </soap:Body>
</soap:Envelope>


-------------------------------------------
SOAP
消息--个人小补充:

根元素是Envelope

  Header
     
默认情况,Header元素不是强制出现的。
      Header
元素有程序员控制添加,主要用于
     
携带一些额外的信息,比如用户名、密码
     
信息

  Body
     1.
如果调用正确。Body元素的内容应该
    
遵守WSDL所要求的格式。
     2.
如果调用错误。Body元素的内容就是
     Fault
子元素。

Soap消息格式:


sop

-------------------------------------------

 

自定义拦截器:
   

   需要实现Interceptor接口。实际上,我们一般会继承AbstractPhaseInterceptor.

给添加权限拦截器

 

客户端

Client.java

 

public class Client

{

         publicstatic void main(String[] args)

         {

                   UserServiceWsfactory = new UserServiceWs();

 

                   UserServiceus = factory.getUserServiceImplPort();

 

                   //为客户端添加拦截器

                   org.apache.cxf.endpoint.Clientclient = ClientProxy.getClient(us);

                   client.getOutInterceptors().add(newAddHeaderInterceptor("crazyit.org"

                            ,"leegang"));

                  

                   List<User>users = us.getUsers();

                   System.out.println(users);

 

                   StringMapmap = (StringMap)us.proUsers(users);

 

                   List<Entry>entries = map.getEntries();

 

                   for(int i = 0 ; i < entries.size() ; i++ )

                   {

                            System.out.println(entries.get(i).getKey()

                                     +"--->" + entries.get(i).getValue());

                   }

 

         }

}

 

客户端拦截器

AddHeaderInterceptor.java

 

public class AddHeaderInterceptor

         extendsAbstractPhaseInterceptor<SoapMessage>

{

         privateString name;

         privateString pass;

         publicAddHeaderInterceptor(String name, String pass)

         {

                   //子类总会调用父类的构造器,

                   //使用super显式调用父类指定的构造器。

                   //指定该拦截器在哪个阶段被激发

                   super(Phase.PREPARE_SEND);

                   this.name= name;

                   this.pass= pass;

         }

 

         //处理消息

         publicvoid handleMessage(SoapMessage message)

         {

                   //获取SOAP消息的全部头(即soap:Header元素全部子元素)

                   List<Header>headers = message.getHeaders();

                   //创建Document对象。

                   Documentdoc = DOMUtils.createDocument();

                   //创建了两个元素

                   ElementuserId = doc.createElement("userId");

                   ElementuserPass = doc.createElement("userPass");

                   userId.setTextContent(name);

                   userPass.setTextContent(pass);

                   //创建AuthHeader元素

                   Elementauth = doc.createElement("AuthHeader");

                   auth.appendChild(userId);

                   auth.appendChild(userPass);

                   QNameqname = new QName("crazyit");

                   SoapHeaderauthHeader = new SoapHeader(qname , auth);

                   //添加了Header

                   headers.add(authHeader);

                   /**

                            也就是向<soap:Header.../>元素中添加了如下元素:

                            <AuthHeader>

                                     <userId>crazyit</userId>

                                     <userPass>crazyit.org</userPass>

                            </AuthHeader>

                   */

         }

}

 

服务器端

Servlet.java

 

public class Server

{

         publicstatic void main(String[] args)

         {

                   /*

                    用Java EE规范提供的方式来暴露服务

                   */

                   UserServiceus = new UserServiceImpl();

                   Stringaddress = "http://localhost:9999/crazyit";

                   EndpointImplep = (EndpointImpl)Endpoint.publish(address , us);

 

                   //下面方法就可以添加拦截器(CXF提供的拦截器)

                   ep.getOutInterceptors()

                            .add(newLoggingOutInterceptor());

                   ep.getInInterceptors()

                            .add(newLoggingInInterceptor());

                   //添加授权拦截器

                   ep.getInInterceptors()

                            .add(newAuthIntercetpr());

         }

}

 

服务端拦截器

AuthIntercetpr.java

 

public class AuthIntercetpr

         extendsAbstractPhaseInterceptor<SoapMessage>

{

         publicAuthIntercetpr()

         {

                   //子类总会调用父类的构造器,

                   //使用super显式调用父类指定的构造器。

                   //指定该拦截器在哪个阶段被激发

                   super(Phase.PRE_INVOKE);

         }

 

         //重写父类的方法,用于处理消息

         publicvoid handleMessage(SoapMessage message)

         {

                   //获取SOAP消息的全部头(即soap:Header元素全部子元素)

                   List<Header>headers = message.getHeaders();

                   //如果soap:Header元素不包含子元素

                   if(headers== null || headers.size() < 1)

                   {

                            thrownew Fault(new SOAPException("SOAP消息头格式不对哦!"));

                   }                

 

                   for(Headerheader : headers)

                   {

                            SoapHeadersoapHeader = (SoapHeader)header;

                            //取出SOAP头对应的Element对象

                            Elementelement = (Element)soapHeader.getObject();

                            //只处理AuthHeader元素(其他元素可能是与授权无关的SOAP头)

                            if(element.getTagName().equals("AuthHeader"))

                            {

                                     if(checkSOAPHeader(element))

                                     {

                                               return;

                                     }

                            }

                   }

                   //遍历了所有SOAP头都找不到AuthHeader元素

                   thrownew Fault(new SOAPException("SOAP消息头格式不对哦!"));

         }

 

         //此处就是用JAXP的XML解析

         publicboolean checkSOAPHeader(Element element)

         {

                   NodeListuserIdList = element.getElementsByTagName("userId");

                   NodeListuserPassList = element.getElementsByTagName("userPass");

                   if(userIdList == null

                            ||userPassList == null

                            ||userIdList.getLength() != 1

                            ||userPassList.getLength() != 1 )

                   {

                            thrownew Fault(new SOAPException("SOAP消息头格式不对哦!"));

                   }

                   else

                   {

                            StringuserId = userIdList.item(0).getTextContent();

                            StringuserPass = userPassList.item(0).getTextContent();

                           

                            //正常情况下,此处应该查询数据库

                            //,判断该用户名、密码是否被授权调用该服务。

                            if(userId.equals("crazyit.org")

                                     &&userPass.equals("leegang"))

                            {

                                     returntrue;

                            }

                            else

                            {

                                     thrownew Fault(new SOAPException("您没有被授权调用该服务!"));

                            }

                   }

         }

}

 

 

CXF需要的jar包(如果是javaWeb应用的话,不需要前7个):

 

CXFSpring的整合

    可以在传统的Java EE应用的基础上添加一层Web Service层。

    我们的Java EE应用就可以对外暴露成Web Service ,这样就可以允许任何平台、任何语言编写的程序来调用这个J2EE应用。

在传统SSH项目基础上增加WS的步骤:

   1.复制CXFjar包。

   2.web.xml配置CXF核心控制器 :org.apache.cxf.transport.servlet.CXFServlet

   3.spring配置文件中导入CXF提供的Schema XML配置。在spring配置文件中导入

cxf.xml,

cxf-extension-soap.xml,

cxf-servlet.xml

 

   4.Spring配置文件中使用jaxwsendpoint元素来暴露WS

  5.如果要添加拦截器。在jaxws:endpoint元素里添加

inInterceptors,outInterceptors子元素。

 

 

CXF与Spring另一种整合:

1.      让Action依赖远程的Web Service的接口。

2.      复制CXF的JAR包。(最核心的6个)

3.      在Spring配置文件中导入CXF提供的Schema,XML配置文件。

4.      在Spring配置文件中使用jaxws:client元素来配置远程Web Service代理。

5.   如果要添加拦截器。在jaxws:client元素里添加inInterceptors,outInterceptors子元素。

 

WebService接口和实现类示例:

接口

FirstWs.java

 

@WebService

public interface FirstWs

{

         //定义几个方法,每个方法将被暴露成一个Web Service操作

         StringsayHi(String text);

         StringsayHiToUser(User user);

         List<User>getUserList();

}

 

 

实现类

 

FirstWsImpl.java

 

@WebService(endpointInterface ="org.crazyit.cxfapp.service.FirstWs"

         ,serviceName= "FirstWsService")

public class FirstWsImpl implements FirstWs

{

         //以一个HashMap来模拟数据库(只要该WebService不关闭,该Map里的数据一直存在)

         Map<Integer,User> users = new HashMap<Integer, User>();

         //实现Web Service的3个操作(方法)

         publicString sayHi(String name)

         {

                   System.out.println("调用sayHi方法");

                   return"Hello," + name;

         }

 

         publicString sayHiToUser(User user)

         {

                   System.out.println("调用sayHiToUser方法");

                   users.put(user.getId(),user);

                   returnuser.getName() + ",欢迎使用CXF";

         }

 

         publicList<User> getUserList()

         {

                   System.out.println("调用getUserList方法" +users);

                   List<User>result = new ArrayList<User>();

                   for(Object obj : users.values() )

                   {

                            result.add((User)obj);

                   }

                   returnresult;

         }

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值