zoukankan      html  css  js  c++  java
  • Web Service(二):cxf 实现

    1. cxf简介

      Web Services 的一种实现方式。

      Apache CXF = Celtix + XFire,后更名为 Apache CXF ,简称为 CXF。

      CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。

    2. JAX-WS

      JAX-WS(Java API for XML Web Services)规范是一组XML web services的JAVA API

      在 JAX-WS中,一个远程调用可以转换为一个基于XML的协议例如SOAP,在使用JAX-WS过程中,*开发者不需要编写任何生成和处理SOAP消息的代码*。JAX-WS的运行时实现会将这些API的调用转换成为对应的SOAP消息。

      * 在服务器端,用户只需要通过Java语言定义远程调用所需要实现的接口SEI(service endpoint interface),并提供相关的实现,通过调用JAX-WS的服务发布接口就可以将其发布为WebService接口。(发布服务  详见5.1

      * 在客户端,用户可以通过JAX-WS的API创建一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。(创建代理  详见5.2

      JAX-WS 也提供了一组针对底层消息进行操作的API调用,你可以通过Dispatch 直接使用SOAP消息或XML消息发送请求或者使用Provider处理SOAP或XML消息。

    3. cxf特点

      部署灵活、支持多种编程语言、多种传输方式。

    4. 代码生成

      Java to WSDL;

      WSDL to Java;

      XSD to WSDL;

      WSDL to XML;

      WSDL to SOAP;

      WSDL to Service;

      

    5. 实践

      5.1 服务器端

      Spring配置文件 cxf.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:task="http://www.springframework.org/schema/task"
         xmlns:jaxws="http://cxf.apache.org/jaxws"
         xmlns:cxf="http://cxf.apache.org/core"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
              http://cxf.apache.org/jaxws
        http://cxf.apache.org/schemas/jaxws.xsd">
    
        <!-- cxf webservice -->
        <import resource="classpath:META-INF/cxf/cxf.xml"/>
        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
        <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
        <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
        <cxf:bus>
            <cxf:inInterceptors>
                <ref bean="loggingInInterceptor"/>
            </cxf:inInterceptors>
            <cxf:outInterceptors>
                <ref bean="loggingOutInterceptor"/>
            </cxf:outInterceptors>
            <cxf:outFaultInterceptors>
                <ref bean="loggingOutInterceptor"/>
            </cxf:outFaultInterceptors>
            <cxf:inFaultInterceptors>
                <ref bean="loggingInInterceptor"/>
            </cxf:inFaultInterceptors>
        </cxf:bus>
         <bean id="serverPasswordCallback" class="util.web.ServerPasswordCallback" />  
         <bean id="authentication_server" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">  
                    <constructor-arg>  
                        <map>  
                            <entry key="action" value="UsernameToken" />  
                            <entry key="passwordType" value="PasswordText" />  
                            <entry key="user" value="FHDServer" />  
                            <entry key="passwordCallbackRef">  
                                <ref bean="serverPasswordCallback" />  
                            </entry>  
                        </map>  
                    </constructor-arg>  
           </bean>   
    <!-- 注意下面的address,这里的address的名称就是访问的WebService的name --> <!-- 外协完工登记 --> <bean id="mesTaskServiceImpl" class="com.outsideasy.ws.mes.wxdata.MesTaskServiceImpl"> </bean> <jaxws:server id="mesTaskServiceInter" serviceClass="com.outsideasy.ws.mes.wxdata.MesTaskServiceInter" address="/wxdata/mesTask"> <!-- 这里是发布的地址 --> <jaxws:serviceBean> <ref bean="mesTaskServiceImpl"/> </jaxws:serviceBean> <jaxws:inInterceptors> <ref bean="authentication_server"></ref> </jaxws:inInterceptors> </jaxws:server> <cxf:bus> <cxf:features> <cxf:logging/> </cxf:features> </cxf:bus> </beans>

      ServerPasswordCallback.java (身份认证的callback,接收客户端的callback对象,获取认证信息进行验证)

    package util.web;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.cxf.message.Exchange;
    import org.apache.cxf.message.Message;
    import org.apache.cxf.staxutils.W3CDOMStreamWriter;
    import org.apache.log4j.Logger;
    import org.apache.ws.security.WSPasswordCallback;
    import org.apache.ws.security.handler.RequestData;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.w3c.dom.Document;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    
    
    import common.sysmodule.model.WsIdentity;
    import common.sysmodule.service.WsIdentityService;
    
    public class ServerPasswordCallback implements CallbackHandler {
        @Autowired
        private WsIdentityService wsIdentityService;
        protected static Logger logger = Logger.getLogger("service");
    
        public void handle(Callback[] callbacks) throws IOException,
                UnsupportedCallbackException {
            
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; //获取客户端Handler中传递过来的callback对象
            String identify = pc.getIdentifier(); //获取账户信息
            
            //身份验证
            List<WsIdentity> list=wsIdentityService.getEnabledIdentity(identify); //通过账户在服务端表中查询账户信息,进行认证
            if (list!=null && list.size()>0 && list.get(0).getIdentify().equals(identify)) {  
               pc.setPassword(list.get(0).getPsw());//验证用户名后,在设置密码就可以自动验证
            } else {
                throw new SecurityException("验证失败");
            }
            
        }
    
    }

      MesTaskServiceInter.java (服务端申明接口)

    package com.outsideasy.ws.mes.wxdata;
    
    import javax.jws.WebService;
    
    import com.outsideasy.ws.mes.wxdata.model.AttachedFileWithParams;
    import com.outsideasy.ws.mes.wxdata.model.TaskRandomCheckAndFileDetails;
    
    @WebService //这里的申明是必需的*
    public interface MesTaskServiceInter {
        
        /**
        * @Description: 新增 发送者的  平台任务单 以及关联的工段 工序 bom材料。
        * @param json格式的 信息主体 TaskAndGX,该对象包含了 任务单信息,工序 ,工段和bom材料信息
        * @return json格式的 CXFResponse<PfTask>
        * 如果success=true,新增成功,并返回PfTask对象;
        * 如果success=false,新增失败,并返回失败信息errorMessage;
        */
        public String addMesTaskAndTaskGx(String jsonobj);
        /**
        * @Description: 根据发送者的任务单号获取工段产量
        * @param rwdh
        * @return json格式的 CXFResponse<PfTaskOutput>
        * 如果success=true,新增成功,并返回List<PfTaskOutput>;
        * 如果success=false,新增失败,并返回失败信息errorMessage;
        */
        public String getPfTaskOutputList(String rwdh);
    }

       MesTaskServiceImpl.java

    package com.outsideasy.ws.mes.wxdata;
    
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.annotation.Resource;
    import javax.jws.WebService;
    import javax.jws.soap.SOAPBinding;
    import javax.jws.soap.SOAPBinding.Style;
    import javax.xml.ws.WebServiceContext;import com.outsideasy.ws.common.vo.CXFResponse;
    import com.outsideasy.ws.mes.wxdata.model.AttachedFileWithParams;
    import com.outsideasy.ws.mes.wxdata.model.TaskCheckAndUnquDetails;
    import com.outsideasy.ws.mes.wxdata.model.TaskRandomCheckAndFileDetails;
    import common.sysmodule.model.WsIdentity;
    import common.sysmodule.service.WsIdentityService;
    
    @WebService //必需申明*
    @SOAPBinding(style = Style.RPC) //必需申明*
    public class MesTaskServiceImpl implements MesTaskServiceInter {
        @Autowired
        private MesTaskService mesTaskService;
        @Resource
        private WebServiceContext context;
        @Autowired
        private WsIdentityService wsIdentityService;
        @Autowired
        private TaskAllCheckService taskAllCheckService;
        @Autowired
        private TaskAllcheckUnqudetailsService taskAllcheckUnqudetailsService;    
        @Autowired
        private TaskRandomCheckService taskRandomCheckService;
        
        public String getPfTaskOutputList(String rwdh){
            Map<String,Object> params2=new HashMap<String,Object>();
            params2.put("rwdh", rwdh);
            params2.put("send_company", getsendInfo().getCompany_id());
            List<PfTaskOutput> list=mesTaskService.getPfTaskOutputList(params2);
            CXFResponse<PfTaskOutput> res=new CXFResponse<PfTaskOutput>();
            if(list!=null && list.size()>0){
                res.setSuccess(Const.SOAP_TRUE);
                res.setList(list);
            }else{
                res.setSuccess(Const.SOAP_FALSE);
                res.setErrorMessage("同步失败,生产方未在平台中录入产量");
            }
            return MyJsonUtil.obj2string(res);
        }
        
        public String addMesTaskAndTaskGx(String jsonobj) {        
            int company_id=getsendInfo().getCompany_id();
            TaskAndGX mtAndGx=MyJsonUtil.str2obj(jsonobj, TaskAndGX.class);
            CXFResponse<PfTask> res=new CXFResponse<PfTask>();
            res.setSuccess(Const.SOAP_TRUE);
            if(mtAndGx.getTask()==null){
                res.setErroeResponseInfo("发送失败,发送的任务单为空");
            }else if(mtAndGx.getGxlist()==null || (mtAndGx.getGxlist()!=null && mtAndGx.getGxlist().size()==0)){
                res.setErroeResponseInfo("发送失败,发送的工序为空");
            }else if(mtAndGx.getBomlist()==null || (mtAndGx.getBomlist()!=null && mtAndGx.getBomlist().size()==0)){
                res.setErroeResponseInfo("发送失败,发送的bom材料为空");
            }else{
                mesTaskService.addMesTaskAndTaskGx(res,company_id,mtAndGx);
            }
            return MyJsonUtil.obj2string(res);
        }
    
    }

      5.2 客户端(创建代理)

        Spring 配置文件 cxf.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jaxws="http://cxf.apache.org/jaxws"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:cxf="http://cxf.apache.org/core"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
        http://cxf.apache.org/jaxws 
        http://cxf.apache.org/schemas/jaxws.xsd">
            
          <context:property-placeholder location="classpath:sysconfig/publishInfo.properties" />
            
        <import resource="classpath:META-INF/cxf/cxf.xml"/>
        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
        <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
        <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
        <cxf:bus>
            <cxf:inInterceptors>
                <ref bean="loggingInInterceptor"/>
            </cxf:inInterceptors>
            <cxf:outInterceptors>
                <ref bean="loggingOutInterceptor"/>
            </cxf:outInterceptors>
            <cxf:outFaultInterceptors>
                <ref bean="loggingOutInterceptor"/>
            </cxf:outFaultInterceptors>
            <cxf:inFaultInterceptors>
                <ref bean="loggingInInterceptor"/>
            </cxf:inFaultInterceptors>
        </cxf:bus>
        <bean id="clientPasswordCallback" class="erp.util.web.ClientPasswordCallback"/>
        <bean id="authentication_client" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">  
                    <constructor-arg>  
                        <map>  
                            <entry key="action" value="UsernameToken" />  
                            <entry key="passwordType" value="PasswordText" />  
                            <entry key="user" value="FHDClient" />  
                            <entry key="passwordCallbackRef">  
                                <ref bean="clientPasswordCallback" />  
                            </entry>  
                        </map>  
                    </constructor-arg>  
                </bean> 
        <jaxws:client id="supplierInter" serviceClass="com.outsideasy.ws.erp.supplier.SupplierInter" 
            address="http://${cxf_url}/ws/erp/supplier/supplierInter">
             <jaxws:handlers>
               <bean class="erp.util.web.SessionLogicalHandler"></bean>
             </jaxws:handlers>
             <jaxws:outInterceptors>  
                <!-- <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> -->  
                <!-- SAAJInInterceptor只在CXF是2.0.X版本时或之前版本时才是必须的 -->  
                <!-- <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/> -->  
                 <ref bean="authentication_client"></ref>
            </jaxws:outInterceptors> 
        </jaxws:client>
        <jaxws:client id="supplierAccessInter" serviceClass="com.outsideasy.ws.erp.supplier.SupplierAccessInter" 
            address="http://${cxf_url}/ws/erp/supplier/supplierAccessInter"> <!-- 访问地址 cxf_url = 192.168.1.101:8995 *-->
             <jaxws:handlers>
               <bean class="erp.util.web.SessionLogicalHandler"></bean>
             </jaxws:handlers>
             <jaxws:outInterceptors>  
                <!-- <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> -->  
                <!-- SAAJInInterceptor只在CXF是2.0.X版本时或之前版本时才是必须的 -->  
                <!-- <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/> -->  
                 <ref bean="authentication_client"></ref>
            </jaxws:outInterceptors> 
        </jaxws:client>
        <cxf:bus>
          <cxf:features>
            <cxf:logging/>
          </cxf:features>
        </cxf:bus>    
        </beans>

      客户端callback对象  ClientPasswordCallback.java

    package erp.util.web;
    
    import java.io.IOException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    import org.apache.ws.security.WSPasswordCallback;
    
    public class ClientPasswordCallback implements CallbackHandler {
    
        @Override
        public void handle(Callback[] callbacks) throws IOException,
                UnsupportedCallbackException {
    
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];  
            pc.setPassword("topsun");  // 验证密码
            pc.setIdentifier("admin"); // 验证账号
        }
    
    }

      SessionLogicalHandler.java 

    package erp.util.web;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.xml.ws.handler.LogicalHandler;
    import javax.xml.ws.handler.LogicalMessageContext;
    import javax.xml.ws.handler.MessageContext;
    
    import org.apache.cxf.jaxws.handler.logical.LogicalMessageContextImpl;
    
    public class SessionLogicalHandler implements LogicalHandler<LogicalMessageContext>{
    
             public SessionLogicalHandler() {
                 super();
             }
    
             public static List<String> http_headers_cookie=null;//静态  所有的  SessionLogicalHandler  共享 一个 cookie
             @SuppressWarnings({ "unchecked", "rawtypes" })
             @Override
             public boolean handleMessage(LogicalMessageContext context) {
              // TODO Auto-generated method stub
              // javax.xml.ws.handler.MessageContext.Scope s=
              // context.getScope(MessageContext.HTTP_REQUEST_HEADERS);
              // Set-Cookie=[JSESSIONID=48B10A68BB05F69F8ED82A33F566C5D8; Path=/myapp;
              // HttpOnly]
              
              LogicalMessageContextImpl c = (LogicalMessageContextImpl) context;
              
              if (c.get(MessageContext.HTTP_RESPONSE_HEADERS) != null) {//response 时  记录服务端返回的session信息
                  Map<String, List> header = (Map<String, List>) c.get(MessageContext.HTTP_RESPONSE_HEADERS);
                  List<String> ls = header.get("Set-Cookie");//获取header 中cookie的信息
                  if(ls!=null){
                      SessionLogicalHandler.SetHttp_headers_cookie(ls);
                  }
              }else if(c.get( MessageContext.HTTP_REQUEST_HEADERS)!=null && http_headers_cookie!=null){//request 请求的时候 把cookie信息设置进去
                  Map<String, List> header = (Map<String, List>) c.get( MessageContext.HTTP_REQUEST_HEADERS);
                  header.put("cookie", http_headers_cookie);
              }else if(c.get( MessageContext.HTTP_REQUEST_HEADERS)==null && http_headers_cookie!=null){//request 请求的时候 把cookie信息设置进去
                  Map<String, List> header = new HashMap<String, List>();
                  header.put("cookie", http_headers_cookie);
                  c.put(MessageContext.HTTP_REQUEST_HEADERS, header);
              }
              return true;
             }
             
    
             @Override
             public boolean handleFault(LogicalMessageContext context) {
              // TODO Auto-generated method stub
              return false;
             }
    
             @Override
             public void close(MessageContext context) {
              // TODO Auto-generated method stub
    
             }
             private synchronized static void  SetHttp_headers_cookie(List<String> ls){
                 if(http_headers_cookie==null){
                     http_headers_cookie=ls;
                 }
             }
    }

      SupplierAccessInter.java (客户端的代理接口,客户端直接调用此接口即可访问ws服务端)

    package com.outsideasy.ws.erp.supplier;
    
    import javax.jws.WebService;
    
    @WebService //必需申明 *
    public interface SupplierAccessInter {
        /**获取历史审核记录
         * 参数:json格式的map 
         * 包含 company_id 公司编号
         * 返回值:json 格式CXFResponse
         * 2016-5-19*/
        public String getPfAuthcationInfoList(String jsonmap);
        /**供应商变更  
         *参数:json格式的map
         *返回值:String 
         *2016-5-17
         **/
        String updateSupplierChangeStateByWS(String jsonmap);
    }

    6.总结

      6.1 cxf 是 WebService的实现方式,符合ws规范

      6.2 利用 jax-ws 可以轻松发布一个WebService服务

      6.3 此项目是利用 cxf + jax-ws 发布的一个WebService服务 

      6.4 主要使用的是 代理设计模式

     7. 项目支持(仅作为个人笔记使用)

      ws + erp

    参考资料:

      1. http://baike.baidu.com/link?url=WOTPK-J7UxJuXZ6hMr8OPYDMItaEHwva8wzOEUSM3wKXF5KgBBXRM8VfgA-kUE_RrAoNMYFipZY0VK_kCtpw8_

  • 相关阅读:
    markdown的使用说明
    iOS开发关于真机—App发布证书和调试证书配置
    iOS开发UI篇—屏幕适配autoResizing autoLayout和sizeClass图文详解
    iOS开发UI篇—模仿ipad版QQ空间登录界面
    iOS开发UI篇—iPad开发中得modal介绍
    iOS开发UI篇—popoverController使用注意
    iOS开发UI篇—popoverController简单介绍
    C语言:二十四 防止头文件被重复包含#ifndef #define #endif
    C语言:二十五 函数中的static例子
    C语言:C运算符优先级
  • 原文地址:https://www.cnblogs.com/springlight/p/6483318.html
Copyright © 2011-2022 走看看