10-WebService

2021-02-20  本文已影响0人  XAbo

一、基础

webservice即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术。

1.1 WS协议

JAVA 中共有三种WebService 规范,分别是JAX-WS(JAX-RPC)、JAXM&SAAJ、JAX-RS

1.2 SOAP 协议

SOAP即简单对象访问协议(Simple Object Access Protocol),它是用于交换 XML(标准通用标记语言下的一个子集)编码信息的轻量级协议。它有三个主要方面: XML-envelope为描述信息内容和如何处理内容定义了框架,将程序对象编码成为XML对象的规则,执行远程过程调用(RPC)的约定。SOAP可以运行在任何其他传输协议上。SOAP是基于JAX-WS协议下的通信协议;SOAP = 在HTTP的基础上+XML数据。SOAP的组成如下:

SOAP 1.1和 SOAP 1.2的区别

1.3 WSDL

wsdl说明书是对SOAP协议的描述,通过wsdl说明书,就可以描述webservice服务端对外发布的服务;wsdl说明书是一个基于xml文件,通过xml语言描述整个服务;在wsdl说明中,描述了:对外发布的服务名称(类)接口方法名称(方法)接口参数(方法参数)服务返回的数据类型(方法返回值)。

1.4 UDDI

Web服务提供商又如何将自己开发的Web服务公布到因特网上,这就需要使用到UDDI了,UDDI的话,是一个跨产业,跨平台的开放性架构,可以帮助 Web 服务提供商在互联网上发布 Web 服务的信息。
UDDI 是一种目录服务,企业可以通过 UDDI 来注册和搜索Web服务。 简单来说的话,UDDI 就是一个目录,只不过在这个目录中存放的是一些关于Web服务的信息而已。并且UDDI通过SOAP进行通讯,构建于 . Net 之上。 UDDI 即 Universal Description,Discovery andIntegration,也就是通用的描述,发现以及整合。 UDDI的目的是为电子商务建立标准;UDDI是一套基于Web的、分布式的、为WebService提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。

ws调用流程

1.5 REST

REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如web应用程序。它首次出现在2000年Roy Fielding的博士论文中,他是HTTP规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。
GET用来获取资源, POST用来新建资源, PUT用来更新资源, DELETE用来删除资源。 访问服务器资源,通过不同的http请求方式,服务器就知道对CRUD的哪个操作!JAX-RS 发布服务就是使用RESTFUL风格。

二、 非框架的JAX-WS实现

2.1 服务端(JDK):

服务端通常使用CXF等框架发布,使用JDK的方式比较少。
关于发布WebService主要就是通过javax.xml.ws.Endpoint类提供的静态方法publish进行发布,如果是普通的java项目,那么可以专门写一个类用于发布WebService,如果是Web项目,那么可以使用ServletContextListener或者Servlet进行发布,框架与WEB项目集成较好。

1.定义接口和实现

package ws;
import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface WebServiceI {
    @WebMethod
    String sayHello(String name);
}
package ws;
import javax.jws.WebService;
@WebService
public class WebServiceImpl implements WebServiceI {
    @Override
    public String sayHello(String name) {
        System.out.println("WebService sayHello "+name);
        return "sayHello "+name;
    }
}

2.发布服务

package ws.test;
import ws.WebServiceImpl;
import javax.xml.ws.Endpoint;
public class WebServicePublish {
    public static void main(String[] args) {
        String address = "http://127.0.0.1:8989/myservice";
        Endpoint.publish(address , new WebServiceImpl());
        System.out.println("发布webservice成功!");
    }
}

2.2 客户端:

客户端只要符合SOAP协议即可;通常使用httpclient即可。

第一种方式:使用 JDK 的工具生成服务端代码,在本地调用即可。仅支持SOAP1.1。

wsimport -s . -p com.ws.transHello http://127.0.0.1:8081/hello?wsdl

该种方式,会分两次调用服务端,第一次是GET请求,获取WSDL文件说明书;第二次是POST请求,发送客户端请求。
第二和第三种方式,是直接发送请求。前提已知WSDL。
第二种方式:HttpURLConnection

package ws;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class WebServiceClient {
    public static void main(String[] args)  throws Exception{
        String WSDL = "http://192.168.202.61:8989/myservice";
        String result = callWebService(WSDL);
        System.out.println("出参:"+result);
    }
    private static String callWebService(String wsdl)  throws Exception{
        System.setProperty("sun.net.client.defaultConnectTimeout","20000");
        System.setProperty("sun.net.client.defaultReadTimeout","20000");
        //设置代理后,该请求就能被Fiddle抓取到
        System.setProperty("http.proxyHost", "localhost");
        System.setProperty("http.proxyPort", "8888");
        System.setProperty("https.proxyHost", "localhost");
        System.setProperty("https.proxyPort", "8888");
        // URL连接
        URL url = new URL(wsdl);
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Length", String.valueOf(actionBySOAP().getBytes().length));
        conn.setRequestProperty("Content-Type","text/xml; charset=UTF-8");
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setConnectTimeout(20000);
        // 请求内容
        OutputStream output = conn.getOutputStream();
        output.write(actionBySOAP().getBytes());
        output.flush();
        output.close();
        System.out.println("入参:"+actionBySOAP());
        // 返回内容
        InputStreamReader isr = new InputStreamReader(conn.getInputStream());
        BufferedReader br = new BufferedReader(isr);
        StringBuilder sb = new StringBuilder();
        String str = null;
        while((str = br.readLine())!=null){
            sb.append(str + "\n");
        }
        br.close();
        isr.close();
        return sb.toString();
    }
 
    private static String actionBySOAP(){
        StringBuilder sb = new StringBuilder();
        sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas" +
                ".xmlsoap.org/soap/envelope/\" xmlns:ws=\"http://ws/\">");
        sb.append("<soapenv:Header/>");
        sb.append("<soapenv:Body>");
        sb.append("<ws:sayHello>");
        sb.append("<arg0>123</arg0>");
        sb.append("</ws:sayHello>");
        sb.append("</soapenv:Body>");
        sb.append("</soapenv:Envelope>");
        return sb.toString();
    }
}

以上方式是SOAP 1.1

第三种方式:HttpClient。建议采用soap1.1方式调用,经测试使用soap1.1方式能调用soap1.1和soap1.2的服务端。

import java.nio.charset.Charset;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
 
public class HttpClientCallSoapUtil {
    static int socketTimeout = 30000;// 请求超时时间
    static int connectTimeout = 30000;// 传输超时时间
    static Logger logger = Logger.getLogger(HttpClientCallSoapUtil.class);
 
    /**
     * 使用SOAP1.1发送消息
     * 
     * @param postUrl
     * @param soapXml
     * @param soapAction
     * @return
     */
    public static String doPostSoap1_1(String postUrl, String soapXml,String soapAction) {
        String retStr = "";
        // 创建HttpClientBuilder
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        // HttpClient
        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
        HttpPost httpPost = new HttpPost(postUrl);
                //  设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        httpPost.setConfig(requestConfig);
        try {
            httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
            httpPost.setHeader("SOAPAction", soapAction);
            StringEntity data = new StringEntity(soapXml,Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            CloseableHttpResponse response = closeableHttpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 打印响应内容
                retStr = EntityUtils.toString(httpEntity, "UTF-8");
                logger.info("response:" + retStr);
            }
            // 释放资源
            closeableHttpClient.close();
        } catch (Exception e) {
            logger.error("exception in doPostSoap1_1", e);
        }
        return retStr;
    }
 
    /**
     * 使用SOAP1.2发送消息
     * 
     * @param postUrl
     * @param soapXml
     * @param soapAction
     * @return
     */
    public static String doPostSoap1_2(String postUrl, String soapXml,
            String soapAction) {
        String retStr = "";
        // 创建HttpClientBuilder
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        // HttpClient
        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
        HttpPost httpPost = new HttpPost(postUrl);
                // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        httpPost.setConfig(requestConfig);
        try {
            httpPost.setHeader("Content-Type",
                    "application/soap+xml;charset=UTF-8");
            httpPost.setHeader("SOAPAction", soapAction);
            StringEntity data = new StringEntity(soapXml,Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            CloseableHttpResponse response = closeableHttpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 打印响应内容
                retStr = EntityUtils.toString(httpEntity, "UTF-8");
                logger.info("response:" + retStr);
            }
            // 释放资源
            closeableHttpClient.close();
        } catch (Exception e) {
            logger.error("exception in doPostSoap1_2", e);
        }
        return retStr;
    }
 
    public static void main(String[] args) {
        String orderSoapXml = "<?xml version = \"1.0\" ?>"
                + "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservices.b.com\">"
                + "   <soapenv:Header/>"
                + "   <soapenv:Body>"
                + "      <web:order soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                + "         <in0 xsi:type=\"web:OrderRequest\">"
                + "            <mobile xsi:type=\"soapenc:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">?</mobile>"
                + "            <orderStatus xsi:type=\"xsd:int\">?</orderStatus>"
                + "            <productCode xsi:type=\"soapenc:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">?</productCode>"
                + "         </in0>" + "      </web:order>"
                + "   </soapenv:Body>" + "</soapenv:Envelope>";
        String querySoapXml = "<?xml version = \"1.0\" ?>"
                + "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservices.b.com\">"
                + "   <soapenv:Header/>"
                + "   <soapenv:Body>"
                + "      <web:query soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                + "         <in0 xsi:type=\"web:QueryRequest\">"
                + "            <endTime xsi:type=\"xsd:dateTime\">?</endTime>"
                + "            <mobile xsi:type=\"soapenc:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">?</mobile>"
                + "            <startTime xsi:type=\"xsd:dateTime\">?</startTime>"
                + "         </in0>" + "      </web:query>"
                + "   </soapenv:Body>" + "</soapenv:Envelope>";
        String postUrl = "http://localhost:8080/services/WebServiceFromB";
        //采用SOAP1.1调用服务端,这种方式能调用服务端为soap1.1和soap1.2的服务
        doPostSoap1_1(postUrl, orderSoapXml, "");
        doPostSoap1_1(postUrl, querySoapXml, "");
 
        //采用SOAP1.2调用服务端,这种方式只能调用服务端为soap1.2的服务
        //doPostSoap1_2(postUrl, orderSoapXml, "order");
        //doPostSoap1_2(postUrl, querySoapXml, "query");
    }
}

第四种方式:使用可视化工具,例如SOAPUI和POSTMAN。
备注:Web Service是HTTP+XML,底层还是HTTP协议,不管使用哪种客户端(SOAPUI/POSTMAN/JAVA)所以可以使用Fiddle抓包工具,抓取到请求和响应。前提是客户端设置的代理与Fiddle一样,系统默认的代理:localhost:8888。
第五、六、七、八种是JDK自带的不需要引入其他框架。
第五种方式:Payload

/**
 * dispatch Payload方式调用WebService
 * @param portName 端口名称
 * @param param 参数
 */
public static void dispatchPayload(String portName, String param) {
    try {
        StringBuffer source = new StringBuffer();
        source.append("<web:toTraditionalChinese xmlns:web=\"" + targetNamespace + "\">");
        source.append("<web:sText>").append(param).append("</web:sText>");
        source.append("</web:toTraditionalChinese>");
        StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
        
        URL wsdlURL = new URL(url);
        QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
        Service service = Service.create(wsdlURL, serviceQName);
        QName portQName = new QName(targetNamespace, portName);
        Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
        
        //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
        Map<String, Object> requestContext = dispatch.getRequestContext();
        requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
        requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
        
        Source orderSource = dispatch.invoke(xmlSource);
        StreamResult result = new StreamResult(new ByteArrayOutputStream());
        Transformer trans = TransformerFactory.newInstance().newTransformer();
        trans.transform(orderSource, result);
        ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
        String responseContent = new String(baos.toByteArray());
        System.out.println(responseContent);

        Reader file = new StringReader(responseContent);
        SAXReader reader = new SAXReader();
        Document dc = reader.read(file);
        Element root = dc.getRootElement();
        String r = root.elementText("toTraditionalChineseResult").trim();
        System.out.println(r);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

第六种:Message方式

package com.inspur.ws;

import java.io.ByteArrayOutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * JAX-WS Dispatch方式调用WebService样例
 * @author wuyy
 *
 */
public class JaxWsDispatch {
    private static String url = "http://www.webxml.com.cn/WebServices/TraditionalSimplifiedWebService.asmx?wsdl";
    private static String targetNamespace = "http://webxml.com.cn/";
    /**
     * dispatch Payload方式调用WebService
     * @param portName 端口名称
     * @param param 参数
     */
    public static void dispatchPayload(String portName, String param) {
        try {
            StringBuffer source = new StringBuffer();
            source.append("<web:toTraditionalChinese xmlns:web=\"" + targetNamespace + "\">");
            source.append("<web:sText>").append(param).append("</web:sText>");
            source.append("</web:toTraditionalChinese>");
            StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
            
            URL wsdlURL = new URL(url);
            QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
            Service service = Service.create(wsdlURL, serviceQName);
            QName portQName = new QName(targetNamespace, portName);
            Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
            
            //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
            Map<String, Object> requestContext = dispatch.getRequestContext();
            requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
            requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
            
            Source orderSource = dispatch.invoke(xmlSource);
            StreamResult result = new StreamResult(new ByteArrayOutputStream());
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(orderSource, result);
            ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
            String responseContent = new String(baos.toByteArray());
            System.out.println(responseContent);

            Reader file = new StringReader(responseContent);
            SAXReader reader = new SAXReader();
            Document dc = reader.read(file);
            Element root = dc.getRootElement();
            String r = root.elementText("toTraditionalChineseResult").trim();
            System.out.println(r);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * dispatch Payload方式调用WebService
     * @param soapNamespace soap消息整个消息体的命名空间,Soap1.1和Soap1.2不一样
     * @param portName 端口名称
     * @param param 参数
     */
    public static void dispatchMessage(String soapNamespace, String portName, String param) {
        try {
            StringBuffer source = new StringBuffer();
            source.append("<soapenv:Envelope xmlns:soapenv=\"" + soapNamespace + "\" xmlns:web=\"" + targetNamespace + "\">");
            source.append("<soapenv:Header/>");
            source.append("<soapenv:Body>");
            source.append("<web:toTraditionalChinese>");
            source.append("<web:sText>").append(param).append("</web:sText>");
            source.append("</web:toTraditionalChinese>");
            source.append("</soapenv:Body>");
            source.append("</soapenv:Envelope>");
            StreamSource xmlSource = new StreamSource(new StringReader(source.toString()));
            
            URL wsdlURL = new URL(url);
            QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService");
            Service service = Service.create(wsdlURL, serviceQName);
            QName portQName = new QName(targetNamespace, portName);
            Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE);
            
            //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值
            Map<String, Object> requestContext = dispatch.getRequestContext();
            requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
            requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese");
            
            Source orderSource = dispatch.invoke(xmlSource);
            StreamResult result = new StreamResult(new ByteArrayOutputStream());
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(orderSource, result);
            ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();
            String responseContent = new String(baos.toByteArray());
            System.out.println(responseContent);

            Reader file = new StringReader(responseContent);
            SAXReader reader = new SAXReader();
            Document dc = reader.read(file);
            //节点名称为toTraditionalChineseResult 命名空间为http://webxml.com.cn/
            String r = dc.selectSingleNode("//*[local-name()='toTraditionalChineseResult' and namespace-uri()='http://webxml.com.cn/']").getText().trim();
            System.out.println(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        //Soap1.1对应的portName为TraditionalSimplifiedWebServiceSoap,Soap1.2对应的portName为TraditionalSimplifiedWebServiceSoap12
        dispatchPayload("TraditionalSimplifiedWebServiceSoap", "小学");
        dispatchPayload("TraditionalSimplifiedWebServiceSoap12", "大学");
        
        //Soap1.1对应的soapNamespace为http://schemas.xmlsoap.org/soap/envelope/,Soap1.1对应的soapNamespace为http://www.w3.org/2003/05/soap-envelope
        dispatchMessage("http://schemas.xmlsoap.org/soap/envelope/", "TraditionalSimplifiedWebServiceSoap", "小学");
        dispatchMessage("http://www.w3.org/2003/05/soap-envelope", "TraditionalSimplifiedWebServiceSoap12", "大学");
    }

}

第七种:Proxy方式

package com.inspur.ws;

import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.inspur.zsyw.ws.ITestService;
/**
 * JAX-WS Proxy调用 ,需把接口类拷贝到客户端
 *
 */
public class JaxWsProxy {
    private static String url = "http://10.40.103.48:9006/zsywservice/TestService?wsdl";
    private static String targetNamespace = "http://ws.zsyw.inspur.com/";
    
    public static void proxy(String param) {
        try {
            QName qname = new QName(targetNamespace, "TestService");
            Service service = Service.create(new URL(url), qname);
            ITestService testService = service.getPort(ITestService.class);
            System.out.println(testService.hello(param));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        proxy("大学");
    }
}

第八种:RPC方式

package com.inspur.ws;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

import com.inspur.zsyw.ws.ITestService;

/**
 * JAX-WS RPC调用 ,需把接口类拷贝到客户端,接口类需继承java.rmi.Remote接口
 *
 */
public class JaxWsRpc {
    private static String url = "http://10.40.103.48:9006/zsywservice/TestService?wsdl";
    private static String targetNamespace = "http://ws.zsyw.inspur.com/";
    
    public static void rpc(String param) {
        try {
            ServiceFactory serviceFactory = ServiceFactory.newInstance();
            Service service = serviceFactory.createService(new URL(url), new QName(targetNamespace, "TestService"));
            ITestService testService = (ITestService) service.getPort(ITestService.class);
            String result = testService.hello(param);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        rpc("大学");
    }
}

三、ApacheCXF框架实现JAX-WS

Apache CXF = Celtix + XFire,ApacheCXF的前身叫Apache CeltiXfire,现在已经正式更名为 Apache CXF了,以下简称为CXF。CXF继承了Celtix和XFire两大开源项目的精华,提供了对JAX-WS全面的支持,并且提供了多种Binding DataBinding、Transport以及各种Format的支持,并且可以根据实际项目的需要,采用代码优先 (Code First)或者WSDL优先(WSDL First)来轻松地实现Web Services的发布和使用。目前它仍只是 Apache 的一个孵化项目。
Apache CXF是一个开源的Services框架,CXF帮助您利用Frontend编程API来构建和开发Services,像JAX-WS 。这些Services可以支持多种协议,比如:SOAP、XML/HTTP、RESTfulHTTP或者CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS或者JBI,CXF大大简化了Services的创建,同时它继承了XFire传统,一样可以天然地和Spring进行无缝集成。

3.1 JAVA项目的代码实现

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itheima</groupId>
    <artifactId>01_jaxws_server</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>../03_jaxws_spring_server</module>
    </modules>
    <name>01_jaxws_server</name>
    <dependencies>
        <!-- 要进行jaxws 服务开发 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!-- 内置jetty web服务器  -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!-- 日志实现 -->
     <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-simple</artifactId>
           <version>1.7.12</version>
     </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

log4j.properties:

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=info, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

服务端:

//对外发布服务的接口
@WebService
public interface HelloService {
   public String sayHello(String name);
}
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return name + ",Welcome to Itheima!";
    }
}

自定义拦截器:

    //InPhases
    Phase.RECEIVE->Phase.PRE_STREAM->Phase.USER_STREAM->Phase.POST_STREAM->Phase.READ->Phase.PRE_PROTOCOL->Phase.USER_PROTOCOL->Phase.POST_PROTOCOL
   ->Phase.UNMARSHAL->Phase.PRE_LOGICAL->Phase.USER_LOGICAL->Phase.POST_LOGICAL->Phase.PRE_INVOKE->Phase.INVOKE->Phase.POST_INVOKE
   //OutPhases
    Phase.SETUP->Phase.PRE_LOGICAL->Phase.USER_LOGICAL->Phase.POST_LOGICAL->Phase.PREPARE_SEND->Phase.PRE_STREAM
   ->Phase.PRE_PROTOCOL->Phase.WRITE->Phase.PRE_MARSHAL->Phase.MARSHAL->Phase.POST_MARSHAL->Phase.USER_PROTOCOL 
   ->Phase.POST_PROTOCOL->Phase.USER_STREAM->Phase.POST_STREAM->Phase.SEND->Phase.SEND_ENDING->Phase.POST_STREAM_ENDING 
   ->Phase.USER_STREAM_ENDING->Phase.POST_PROTOCOL_ENDING->Phase.USER_PROTOCOL_ENDING->Phase.MARSHAL_ENDING->Phase.WRITE_ENDING
   ->Phase.PRE_PROTOCOL_ENDING->Phase.PRE_STREAM_ENDING->Phase.PREPARE_SEND_ENDING->Phase.POST_LOGICAL_ENDING->Phase.USER_LOGICAL_ENDING 
   ->Phase.PRE_LOGICAL_ENDING->Phase.SETUP_ENDING 

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    public MyInterceptor() {
        super(Phase.PRE_INVOKE);  // 在调用方法之前调用自定拦截器    
    }
    @SuppressWarnings("null")
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headers=message.getHeaders();
        if(headers==null && headers.size()==0){
            throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"));
        }
        Header firstHeader=headers.get(0);
        Element ele=(Element) firstHeader.getObject();
        NodeList uList=ele.getElementsByTagName("userName");
        NodeList pList=ele.getElementsByTagName("password");
        if(uList.getLength()!=1){
            throw new Fault(new IllegalArgumentException("用户名格式不对"));
        }
        if(pList.getLength()!=1){
            throw new Fault(new IllegalArgumentException("密码格式不对"));
        }
        String userName=uList.item(0).getTextContent();
        String password=pList.item(0).getTextContent();
        if(!userName.equals("java1234")||!password.equals("123456")){
            throw new Fault(new IllegalArgumentException("用户名或者密码错误!"));
        }
    }
}

发布服务:

public class Server {
    public static void main(String[] args) {
        //  发布服务的工厂
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        //  设置服务地址
        factory.setAddress("http://localhost:8000/ws/hello");
        //  设置服务类
        factory.setServiceBean(new HelloServiceImpl());
        //  添加日志输入、输出拦截器,观察soap请求、soap响应内容
       //factoryBean.getInInterceptors().add(new MyInterceptor()); //自定义拦截器
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());
        //  发布服务
        factory.create();
        System.out.println("发布服务成功,端口8000.....");
    }
}

客户端:服务端的接口客户端也是需要的,正常使用工具即可生成。

CXF 获取客户端代码

自定义拦截器:

public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    private String userName;
    private String password;
    public AddHeaderInterceptor(String userName,String password) {
        super(Phase.PREPARE_SEND); // 准备发送SOAP消息的时候调用拦截器
        this.userName=userName;
        this.password=password;
    }
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headerList=message.getHeaders();
        Document doc=DOMUtils.createDocument();
        Element ele=doc.createElement("authHeader");
        Element uElement=doc.createElement("userName");
        uElement.setTextContent(userName);
        Element pElement=doc.createElement("password");
        pElement.setTextContent(password);
        ele.appendChild(uElement);
        ele.appendChild(pElement);
        headerList.add(new Header(new QName("java1234"),ele));
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        //  服务接口访问地址:http://localhost:8000/ws/hello
        // 创建cxf代理工厂
        JaxWsProxyFactoryBean factory = new  JaxWsProxyFactoryBean();
        //  设置远程访问服务端地址
        factory.setAddress("http://localhost:8000/ws/hello");
        //  设置接口类型
        factory.setServiceClass(HelloService.class);
        //  对接口生成代理对象
        HelloService helloService = factory.create(HelloService.class);
        //  代理对象对象  class com.sun.proxy.$Proxy34       [Java代理: 1. 静态代理;  2.动态代理(jdk接口代理、cglib子类代理)]    $CGLIB123
        System.out.println(helloService.getClass());
        // 客户端添加拦截器
       //client.getOutInterceptors().add(new AddHeaderInterceptor("java1234","123")); // 添加自定义拦截器
       //org.apache.cxf.endpoint.Client client=ClientProxy.getClient(helloService );
       //client.getInInterceptors().add(new LoggingInInterceptor()); // 添加In拦截器 日志拦截器
       //client.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加Out拦截器 日志拦截器

        // 远程访问服务端方法  
        //复杂类型的传递,CXF需要利用@XmlJavaAdapter适配器转换。
        //复杂类型的传递,CXF需要利用@XmlJavaAdapter适配器转换。
        //复杂类型的传递,CXF需要利用@XmlJavaAdapter适配器转换。
        String content = helloService.sayHello("Jet");
        System.out.println(content);
    }
}
SOAP通信内容

3.2 Web项目的CXF代码实现

1.省略配置pox.xml
2.定义接口服务

@WebService(name="MobileAddress"
            ,serviceName="MobileAddressService"
            ,portName="MobileAddressPort"
            ,targetNamespace="http://ws.esb.com/"
           )
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface MobileAddress {
    @WebMethod(operationName="getAddressbyMobileNo")
    public @WebResult(name="address")String getAddressByMobile(@WebParam(name="mobileNo")String mobile);
}

3.接口实现类

package com.esb.ws.server;
public class MobileAddressImpl implements MobileAddress {
    @Override
    public String getAddressByMobile(String mobile) {
        return "电话号码"+mobile+"属于上海电信";
    }
}

4.Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>WebService_CXF_Web</display-name>
  <servlet>
      <servlet-name>cxf</servlet-name>
     <!--默认会去类路径下找cxf-servlet.xml配置文件-->
      <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>cxf</servlet-name>
      <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>
</web-app>

5.cxf-servlet.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:jaxws="http://cxf.apache.org/jaxws"
    xmlns:soap="http://cxf.apache.org/bindings/soap" xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://cxf.apache.org/bindings/soap 
                        http://cxf.apache.org/schemas/configuration/soap.xsd
                        http://cxf.apache.org/jaxws 
                        http://cxf.apache.org/schemas/jaxws.xsd
                        http://cxf.apache.org/jaxrs 
                        http://cxf.apache.org/schemas/jaxrs.xsd
                        ">
    <!-- 
        jaxws:server代表org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean,服务实例工厂
        等价于JaxWsServiceFactoryBean jf = new JaxWsServiceFactoryBean();
        address:写服务的相对路径
        serviceClass:sei接口类
        jaxws:serviceBean:sei的实现类
     -->
    <jaxws:server address="/mobile" serviceClass="com.esb.ws.server.MobileAddress">
        <jaxws:serviceBean>
            <ref bean="mobileAddress"/>
        </jaxws:serviceBean>
    </jaxws:server>
    <bean id="mobileAddress" class="com.esb.ws.server.MobileAddressImpl"></bean>
</beans>

6.启动TomCat。

3.3 Web项目的CXF与Spring集成

pox.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>03_jaxws_spring_server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>03_jaxws_spring_server Maven Webapp</name>
    <dependencies>
        <!-- CXF WS开发  -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
            <!-- 运行tomcat7方法:tomcat7:run -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 指定端口 -->
                    <port>8080</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

web.xml:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!--1. cxfsevlet配置-->
  <servlet>
    <servlet-name>cxfservlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  <!--1. cxfsevlet配置放在这里第一个访问WS服务会慢,所以放在listener-->
  <!--  <init-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath:applicationContext.xml</param-value>
     </init-param>
   -->
  </servlet>
  <servlet-mapping>
    <servlet-name>cxfservlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>
  <!--2.spring容器配置:-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

applicationContext.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:cxf="http://cxf.apache.org/core"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.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
        http://cxf.apache.org/jaxrs
        http://cxf.apache.org/schemas/jaxrs.xsd">
        <!--
        <!-- 引入cxf的一些核心配置 -->
        <!-- 
          cxf.xml配置cxf的一些核心处理器;
          cxf-extension-soap.xml配置cxf的一些扩展功能;
         cxf-servlet.xml用于自定义cxf的特性,默认为空
         <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" /> 
            Spring整合cxf发布服务,关键点:
            1. 服务地址
            2. 服务类
            服务完整访问地址: http://localhost:8080/ws/hello
        -->
   <jaxws:endpoint  id="userService" implementor="com.lzj.webservice.ws.UserServiceImpl" address="/hello">
     <!--配置服务器端的入拦截器 
     <jaxws:inInterceptors>
        <bean class="com.lzj.webservice.ws.interceptor.CheckUserInterceptor"></bean>
     </jaxws:inInterceptors>    
      -->
    </jaxws:endpoint>

</beans>

服务端:

@WebService
public interface HelloService {
    public String sayHello(String name);
}
public class HelloServiceImpl implements HelloService {
    public String sayHello(String name) {
        return name + ",Welcome to Itheima!";
    }
}

客户端:服务端的接口客户端也是需要的,正常使用工具即可生成。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Client {
    // 注入对象
    @Resource
    private HelloService helloService;
    @Test
    public void remote(){
        // 查看接口的代理对象类型
        // class com.sun.proxy.$Proxy45
        System.out.println(helloService.getClass());
        // 远程访问服务端方法
        System.out.println(helloService.sayHello("Jerry"));
    }
}

applicationContext.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:cxf="http://cxf.apache.org/core"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.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
        http://cxf.apache.org/jaxrs
        http://cxf.apache.org/schemas/jaxrs.xsd">
        <!--
            Spring整合cxf客户端配置:
            1. 服务地址     http://localhost:8080/ws/hello
            2. 服务接口类型
        -->
    <jaxws:client
            id="helloService"
            serviceClass="com.itheima.service.HelloService"
            address="http://localhost:8080/ws/hello"></jaxws:client>
</beans>

四、 ApacheCXF框架实现JAX-RS

基于restful风格的webservice,请求使用的是http协议,可以传递xml/json数据

4.1 代码实现

服务端:
pom.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itheima</groupId>
    <artifactId>05_jaxrs_server</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>../07_jaxrs_spring_server</module>
    </modules>
    <name>05_jaxrs_server</name>
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-client</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-extension-providers</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jettison</groupId>
            <artifactId>jettison</artifactId>
            <version>1.3.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

实体类:

@XmlRootElement(name = "Car")
public class Car {
    private Integer id;
    private String carName;
    private Double price;
    //省略get/set
}
/**
 *  基于restful风格的webservice,客户端与服务端之间通讯可以传递xml数据、json数据
 *  @XmlRootElement 指定对象序列化为xml或json数据时根节点的名称
 *  xml:
 *       <User>
 *           <id></id>
 *           <username></username>
 *           <city></city>
 *       </User>
 *   json:
 *   {"User":  {"id":100,  "username":"jack","city":"广州" }}
 *
 */
@XmlRootElement(name = "User")
public class User {
    private Integer id;
    private String username;
    private String city;
    private List<Car> cars = new ArrayList<Car>();
}

接口:

//  访问当前服务接口对应的路径
@Path("/userService")
@Produces("*/*")  // 服务器支持的返回的数据格式类型
public interface IUserService {

    // 表示处理的请求的类型,post 对应的是insert新增操作
    @POST
    // 访问当前服务接口方法对应的路径。 【.../userService/user】
    @Path("/user")
    //  服务器支持的请求的数据格式类型
    @Consumes({ "application/xml", "application/json" })
    public void saveUser(User user);

    // 表示处理的请求的类型,put 对应的是update修改操作
    @PUT
    @Path("/user")
    @Consumes({ "application/xml", "application/json" })
    public void updateUser(User user);

    // 表示处理的请求的类型,get 对应的是查询修改操作
    @GET
    @Path("/user")
    // 服务器支持的返回的数据格式类型
    @Produces({ "application/xml", "application/json" })
    public List<User> findAllUsers();

    @GET
    @Path("/user/{id}")
    @Consumes("application/xml")
    @Produces({ "application/xml", "application/json" })
    public User finUserById(@PathParam("id") Integer id);

    // 表示处理的请求的类型,delete 对应的是删除操作
    @DELETE
    @Path("/user/{id}")
    @Consumes({"application/xml", "application/json"})
    public void deleteUser(@PathParam("id") Integer id);
}

接口实现类:

public class UserServiceImpl implements IUserService {

    public void saveUser(User user) {
        System.out.println("save user:" + user);
    }

    public void updateUser(User user) {
        System.out.println("update user:" + user);
    }

    public List<User> findAllUsers() {
        List<User> users = new ArrayList<User>();
        User user1 = new User();
        user1.setId(1);
        user1.setUsername("小明");
        user1.setCity("北京");

        List<Car> carList1 = new ArrayList<Car>();
        Car car1 = new Car();
        car1.setId(101);
        car1.setCarName("保时捷");
        car1.setPrice(1000000d);
        carList1.add(car1);
        Car car2 = new Car();
        car2.setId(102);
        car2.setCarName("宝马");
        car2.setPrice(400000d);
        carList1.add(car2);
        user1.setCars(carList1);

        users.add(user1);

        User user2 = new User();
        user2.setId(2);
        user2.setUsername("小丽");
        user2.setCity("上海");
        users.add(user2);

        return users;
    }

    public User finUserById(Integer id) {
        if (id == 1) {
            User user1 = new User();
            user1.setId(1);
            user1.setUsername("小明");
            user1.setCity("北京");
            return user1;
        }
        return null;
    }

    public void deleteUser(Integer id) {
        System.out.println("delete user id :" + id);
    }
}

发布服务

public class Server {
    public static void main(String[] args) {
        // 创建发布服务的工厂
        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
        // 设置服务地址
        factory.setAddress("http://localhost:8001/ws/");
        // 设置服务类
        factory.setServiceBean(new UserServiceImpl());
        // 添加日志输入输出拦截器,需要log4j配置文件
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());
        // 发布服务
        factory.create();
        System.out.println("发布服务成功,端口8001");
    }
}

客户端:

public class Client {
    @Test
    public void testSave(){
        User user = new User();
        user.setId(100);
        user.setUsername("Jerry");
        user.setCity("gz");
        // 通过WebClient对象远程调用服务端
        WebClient
                    .create("http://localhost:8001/ws/userService/user")
                    .type(MediaType.APPLICATION_JSON)  // 指定请求的数据格式为json
                    .post(user);
    }
    @Test
    public void testGet(){
        // 查询一个
        User user =
            WebClient
                    .create("http://localhost:8001/ws/userService/user/1")
                   .accept(MediaType.APPLICATION_JSON)
                    .get(User.class);
        System.out.println(user);
    }
}

4.2 Spring集成

服务端:
web.xml:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>cxfservlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxfservlet</servlet-name>
        <url-pattern>/ws/*</url-pattern>
    </servlet-mapping>
    <!--2.spring容器配置-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itheima</groupId>
    <artifactId>07_jaxrs_spring_server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>../08_jaxrs_spring_client</module>
    </modules>
    <packaging>pom</packaging>

    <name>07_jaxrs_spring_server Maven Webapp</name>
    <dependencies>
        <!-- cxf 进行rs开发 必须导入  -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!-- 日志引入  -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <!-- 客户端 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-client</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!-- 扩展json提供者 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-extension-providers</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!-- 转换json工具包,被extension providers 依赖 -->
        <dependency>
            <groupId>org.codehaus.jettison</groupId>
            <artifactId>jettison</artifactId>
            <version>1.3.7</version>
        </dependency>
        <!-- spring 核心 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <!-- spring web集成 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <!-- spring 整合junit  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <!-- junit 开发包 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
            <!-- 运行tomcat7方法:tomcat7:run -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 指定端口 -->
                    <port>8080</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

applicationContext.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:cxf="http://cxf.apache.org/core"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.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
        http://cxf.apache.org/jaxrs
        http://cxf.apache.org/schemas/jaxrs.xsd">
        <!--
            Spring整合cxf发布基于restful风格的服务,关键点:
            1. 服务地址
            2. 服务类
            服务完整访问地址:
                http://localhost:8080/ws/hello
        -->
        <jaxrs:server address="/userService">
                <jaxrs:serviceBeans>
                    <bean class="com.itheima.service.UserServiceImpl"></bean>
                </jaxrs:serviceBeans>
        </jaxrs:server>
</beans>

沿用上面的User和Car实体类
IUserService:

//  访问当前服务接口对应的路径
@Path("/userService")
@Produces("*/*")  // 服务器支持的返回的数据格式类型
public interface IUserService {
    // 表示处理的请求的类型,post 对应的是insert新增操作
    @POST
    // 访问当前服务接口方法对应的路径。 【.../userService/user】
    @Path("/user")
    //  服务器支持的请求的数据格式类型
    @Consumes({ "application/xml", "application/json" })
    public void saveUser(User user);

    // 表示处理的请求的类型,put 对应的是update修改操作
    @PUT
    @Path("/user")
    @Consumes({ "application/xml", "application/json" })
    public void updateUser(User user);

    // 表示处理的请求的类型,get 对应的是查询修改操作
    @GET
    @Path("/user")
    // 服务器支持的返回的数据格式类型
    @Produces({ "application/xml", "application/json" })
    public List<User> findAllUsers();

    @GET
    @Path("/user/{id}")
    @Consumes("application/xml")
    @Produces({ "application/xml", "application/json" })
    public User finUserById(@PathParam("id") Integer id);

    // 表示处理的请求的类型,delete 对应的是删除操作
    @DELETE
    @Path("/user/{id}")
    @Consumes({"application/xml", "application/json"})
    public void deleteUser(@PathParam("id") Integer id);
}

UserServiceImpl :

public class UserServiceImpl implements IUserService {
    public void saveUser(User user) {
        System.out.println("save user:" + user);
    }
    public void updateUser(User user) {
        System.out.println("update user:" + user);
    }
    public List<User> findAllUsers() {
        List<User> users = new ArrayList<User>();
        User user1 = new User();
        user1.setId(1);
        user1.setUsername("小明");
        user1.setCity("北京");

        List<Car> carList1 = new ArrayList<Car>();
        Car car1 = new Car();
        car1.setId(101);
        car1.setCarName("保时捷");
        car1.setPrice(1000000d);
        carList1.add(car1);
        Car car2 = new Car();
        car2.setId(102);
        car2.setCarName("宝马");
        car2.setPrice(400000d);
        carList1.add(car2);
        user1.setCars(carList1);

        users.add(user1);

        User user2 = new User();
        user2.setId(2);
        user2.setUsername("小丽");
        user2.setCity("上海");
        users.add(user2);

        return users;
    }
    public User finUserById(Integer id) {
        if (id == 1) {
            User user1 = new User();
            user1.setId(1);
            user1.setUsername("小明");
            user1.setCity("北京");
            return user1;
        }
        return null;
    }
    public void deleteUser(Integer id) {
        System.out.println("delete user id :" + id);
    }
}

客户端:

public class Client {
    @Test
    public void testSave(){
        User user = new User();
        user.setId(100);
        user.setUsername("Jerry");
        user.setCity("gz");
        // 通过WebClient对象远程调用服务端
        WebClient
                    .create("http://localhost:8080/ws/userService/userService/user")
                    .type(MediaType.APPLICATION_JSON)  // 指定请求的数据格式为json
                    .post(user);
    }
    @Test
    public void testGet(){
        // 查询一个
        User user =
            WebClient
                    .create("http://localhost:8080/ws/userService/userService/user/1")
                   .accept(MediaType.APPLICATION_JSON)
                    .get(User.class);
        System.out.println(user);
    }
}
上一篇 下一篇

猜你喜欢

热点阅读