WebService知识汇总

来源:互联网 发布:新闻网页源码 编辑:程序博客网 时间:2024/05/20 06:06

一、简介

      1、简述:Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)来描述、发布、

                       发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序,为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制;

      2、趋势:

           1)、内容更加动态:必须能合并从多个不同来源的内容,可以包括股票,天气等,在传统环境中的内容,如存货水平,购物订单等,都从后台来;

           2)、带宽更加便宜:可以分发各种类型的内容(音频,视频流等);

           3)、存储更便宜:必须能聪明地处理大量数据,意味着要使用数据库,LDAP目录,缓冲,和负载平衡软件等技术保持可扩展能力;

           4)、普遍式计算更重要:不能要求客户使用某一版本的windows的传统浏览器,必须支持各种设备,平台,浏览器类型,各种内容类型;

           要达到这样的目标,Web services要使用两种技术:

                  1)、XML:XML是在web上传送结构化数据的伟大方式,Web services要以一种可靠的自动的方式操作数据,XML可以使web services十分方便的处理数据,它的

                                    内容与表示的分离十分理想,而HTML满足不了需求;

                  2)、SOAP:SOAP使用XML消息调用远程方法,这样web services可通过HTTP协议的post和get方法与远程机器交互,而且SOAP更加健壮和灵活易用;

                  其他像UDDI和WSDL技术与XML和SOAP技术紧密结合用于服务发现;

      3、技术支持:

           1)、XML和XSD:Web Service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,Web Service必须提

                                        供一套标准的类型系统,用于沟通不同平台。XML是Web Service平台中表示数据的基本格式。除了易于建立和易于分析外,XML主要的优点在于它

                                        既与平台无关,又与厂商无关。XML是由W3C,W3C制定的XML SchemaXSD 定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类

                                        型。Web Service平台是用XSD来作为数据类型系统的。当你用某种语言构造一个Web Service时,为了符合Web Service标准,所有使用的数据类

                                        型都须转换为XSD类型,XSD在不同平台和传递,还需要用协议将它包装起来;

            2)、SOAP:简单对象访问协议(Simple Object Access Protocol),它是用于交换XML编码信息的轻量级协议。它有三个主要方面:XML-envelope为描述信息内容和

                                 如何处理内容定义了框架、将程序对象编码成为XML对象的规则、执行远程过程调用(RPC)的约定。SOAP可以运行在任何其他传输协议上。例如,你

                                 可以使用 SMTP(因特网电子邮件协议)来传递SOAP消息,在传输层之间的头是不同的,但XML有效负载保持相同;

            3)、WSDL:Web Service描述语言,就是用机器能阅读的方式提供的一个正式描述文档而基于XML的语言,用于描述Web Service及其函数、参数和返回值;

            4)、UDDI:目的是为电子商务建立标准;UDDI是一套基于Web的、分布式的、为Web Service提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将

                               自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准;

            5)、调用RPC与消息传递:Web Service本身其实是在实现应用程序间的通信。我们有两种应用程序通信的方法:RPC远程过程调用、消息传递。使用RPC时,客户

                                                       端的概念是调用服务器上的远程过程,通常方式是实例化一个远程对象并调用其方法和属性。RPC系统试图达到一种位置上的透明性,即

                                                       服务器暴露出远程对象的接口,而客户端就好像在本地使用的这些对象的接口一样,这样就隐藏了底层的信息,客户端也就根本不需要知

                                                       道对象是在哪台机器上; 

      4、java中webService实现框架:Apache Axis1、Apache Axis2、Codehaus XFire、Apache CXF、Apache Wink、Jboss  RESTEasyd

      5、WS两种规范风格: 

           1)、JAX-WS:全称 Java API for XML-Based Web Services,Oracle 公司提供了 JAX-WS 的实现 JAX-WS RI;

           2)、JAX-RS:JAX-WS 是基于 SOAP 的,而 SOAP 的全称是 Simple Object Access Protocol(简单对象访问协议),其实SOAP并比较复杂,为了让 WS 的开发与使

                                  用变得更加简单、更加轻量级,于是出现了JAX-RS,全称 Java API for RESTful Web Services,其实现:

                                          Jersey:https://jersey.java.net/

                                          Restlet:http://restlet.com/

                                          RESTEasy:http://resteasy.jboss.org/

                                          CXF:http://cxf.apache.org/

二、使用JDK开发WS

      1、服务器端发布WS

           1)、编写服务接口及其实现类

                  HelloWorld

import javax.jws.WebService;@WebServicepublic interface HelloService {    String say(String name);}

                  HelloWoldImp

import javax.jws.WebService;@WebService(    serviceName = "HelloService",    portName = "HelloServicePort",    endpointInterface = "demo.ws.soap_jdk.HelloService")public class HelloServiceImpl implements HelloService {    public String say(String name) {        return "hello " + name;    }}

           2)、编写Server类,发布WS

import javax.xml.ws.Endpoint;public class Server {    public static void main(String[] args) {        String address = "http://localhost:8080/ws/soap/hello";        HelloService helloService = new HelloServiceImpl();        Endpoint.publish(address, helloService);        System.out.println("ws is published");    }}
      2、客户端调用WS

           1)、使用 JDK 提供的命令行工具生成 WS 客户端 jar 包

//通过 WSDL 地址生成 class 文件wsimport http://localhost:8080/ws/soap/hello?wsdl //通过 jar 命令将若干 class 文件压缩为一个 jar 包   jar -cf client.jar .   //删除生成的 class 文件(删除根目录即可)     mdir /s/q demo                                       
                  最终您将会得到一份名为 client.jar 的 jar 包,将这个 jar 包配置到您的 classpath 中,方便在下面的代码中使用其中的类;

           2)、编写一个Client类,调用WS,依赖上面生成jar包中的类

public class Client {    public static void main(String[] args) {        HelloService_Service service = new HelloService_Service();        HelloService helloService = service.getHelloServicePort();        String result = helloService.say("world");        System.out.println(result);    }}

           3)、JDK也提供了动态代理,无需client.jar,在本地提供一个 HelloService 的接口,直接面向WSDL编程

import java.net.URL;import javax.xml.namespace.QName;import javax.xml.ws.Service;public class DynamicClient {    public static void main(String[] args) {        try {            URL wsdl = new URL("http://localhost:8080/ws/soap/hello?wsdl");            //需要分别定义出 serviceName 与 portName             QName serviceName = new QName("http://soap_jdk.ws.demo/", "HelloService");            QName portName = new QName("http://soap_jdk.ws.demo/", "HelloServicePort");            //调用 JDK 提供的 javax.xml.ws.Service 类生成 service 对象            Service service = Service.create(wsdl, serviceName);            HelloService helloService = service.getPort(portName, HelloService.class);            String result = helloService.say("world");            System.out.println(result);        } catch (Exception e) {            e.printStackTrace();        }    }}
三、使用CXF开发WS

       1、项目环境:用JDK1.7,1.7有webservice的默认实现,使用1.5需要另外加jar包;

       2、服务器端发布WS

            1)、使用 RI 发布 WS

                   a)、整合 Tomcat 与 RI

                          下载一份 RI 的程序包:https://jax-ws.java.net/2.2.8/,解压,对 Tomcat 的 config/catalina.properties 文件进行配置

common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,D:/Tool/jaxws-ri/lib/*.jar

                          也可以直接将jar包放到WEB-INF/lib种;                   

                   b)、编写服务接口及其实现类(参考上面的代码);

                   c)、在 WEB-INF 下添加 sun-jaxws.xml 文件,配置需要发布的WS

<!-- lang: xml --><?xml version="1.0" encoding="UTF-8"?><endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">    <endpoint name="HelloService"              implementation="demo.ws.soap_jaxws.HelloServiceImpl"              url-pattern="/ws/soap/hello"/></endpoints>
                         仅发布一个 endpoint,并配置三个属性:WS 的名称、实现类、URL 模式。正是通过这个“URL 模式”来访问 WSDL 的;

                   d)、部署应用并启动 Tomcat,访问http://localhost:8080/ws/soap/hello

            2)、使用 CXF 内置的 Jetty 发布 WS(CXF 不仅可以将 WS 发布在任何的 Web 容器中,而且还提供了一个便于测试的 Web 环境,实际上它内置了一个 Jetty)

                   a)、配置 Maven 依赖

<!-- lang: 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>demo.ws</groupId>    <artifactId>soap_cxf</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <cxf.version>3.0.0</cxf.version>    </properties>    <dependencies>        <!-- CXF -->        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-frontend-jaxws</artifactId>            <version>${cxf.version}</version>        </dependency>        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-transports-http-jetty</artifactId>            <version>${cxf.version}</version>        </dependency>    </dependencies></project>

                   b)、编写服务接口及其实现类(参考上面的代码)

                   c)、编写一个 JaxWsServer 类来发布 WS 

                         基于JAX-WS

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;public class JaxWsServer {    public static void main(String[] args) {        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();        factory.setAddress("http://localhost:8080/ws/soap/hello");        factory.setServiceClass(HelloService.class);        factory.setServiceBean(new HelloServiceImpl());        factory.create();        System.out.println("soap ws is published");    }}

                         基于Simple方式(以 simple 方式发布的 WS,不能通过 JAX-WS 方式来调用,只能通过 simple 方式的客户端来调用)

import org.apache.cxf.frontend.ServerFactoryBean;public class SimpleServer {    public static void main(String[] args) {        ServerFactoryBean factory = new ServerFactoryBean();        factory.setAddress("http://localhost:8080/ws/soap/hello");        factory.setServiceClass(HelloService.class);        factory.setServiceBean(new HelloServiceImpl());        factory.create();        System.out.println("soap ws is published");    }}

                   d)、运行 JaxWsServer

            3)、Web 容器中使用 Spring + CXF 发布 WS

                   a)、配置Maven依赖

<!-- lang: 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>demo.ws</groupId>    <artifactId>soap_spring_cxf</artifactId>    <version>1.0-SNAPSHOT</version>    <packaging>war</packaging>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <spring.version>4.0.5.RELEASE</spring.version>        <cxf.version>3.0.0</cxf.version>    </properties>    <dependencies>        <!-- Spring -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-web</artifactId>            <version>${spring.version}</version>        </dependency>        <!-- CXF -->        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-frontend-jaxws</artifactId>            <version>${cxf.version}</version>        </dependency>        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-transports-http</artifactId>            <version>${cxf.version}</version>        </dependency>    </dependencies></project>

                   b)、编写服务接口及其实现类(参考上面的代码,实现类添加@Component注解

                   c)、配置web.xml(拦截所有/ws开头的请求)

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"         version="3.0">    <!-- Spring -->    <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>classpath:spring.xml</param-value>    </context-param>    <listener>        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>    <!-- CXF -->    <servlet>        <servlet-name>cxf</servlet-name>        <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>
                   d)、配置spring.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:context="http://www.springframework.org/schema/context"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd">    <context:component-scan base-package="demo.ws"/>    <!-- 引入 spring-cxf.xml 文件,用于编写 CXF 相关配置。将配置文件分离 -->    <import resource="spring-cxf.xml"/></beans>

                   e)、配置spring-cxf.xml

                          方式一( CXF 提供的 Spring 命名空间,即 jaxws:server,来发布 WS):

<?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"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://cxf.apache.org/jaxws       http://cxf.apache.org/schemas/jaxws.xsd">    <jaxws:server id="helloService" address="/soap/hello">        <jaxws:serviceBean>            <ref bean="helloServiceImpl"/>        </jaxws:serviceBean>    </jaxws:server></beans>

                          方式二(CXF 提供的 endpoint 方式):

<!-- lang: 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"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://cxf.apache.org/jaxws       http://cxf.apache.org/schemas/jaxws.xsd">    <!-- #helloServiceImpl,这是 CXF 特有的简写方式,并非是 Spring 的规范,意思是通过 Spring 的 Bean ID 获取 Bean 实例  -->    <jaxws:endpoint id="helloService" implementor="#helloServiceImpl" address="/soap/hello"/></beans>

                          方式三( simple 方式):

<!-- lang: 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:simple="http://cxf.apache.org/simple"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://cxf.apache.org/simple       http://cxf.apache.org/schemas/simple.xsd">    <simple:server id="helloService" serviceClass="#helloService" address="/soap/hello">        <simple:serviceBean>            <ref bean="#helloServiceImpl"/>        </simple:serviceBean>    </simple:server></beans>

                   f)、启动 Tomcat,访问http://localhost:8080/ws    

       3、CXF 提供的 WS 客户端调用WS

            1)、静态客户端

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;public class JaxWsClient {    public static void main(String[] args) {        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();        factory.setAddress("http://localhost:8080/ws/soap/hello");        factory.setServiceClass(HelloService.class);        HelloService helloService = factory.create(HelloService.class);        String result = helloService.say("world");        System.out.println(result);    }}
                    需要自行通过 WSDL 打客户端 jar 包,通过静态代理的方式来调用 WS,这种方案比较原始

            2)、动态代理客户端

import org.apache.cxf.endpoint.Client;import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;public class JaxWsDynamicClient {    public static void main(String[] args) {        JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();        Client client = factory.createClient("http://localhost:8080/ws/soap/hello?wsdl");        try {            Object[] results = client.invoke("say", "world");            System.out.println(results[0]);        } catch (Exception e) {            e.printStackTrace();        }    }}

                    无需通过 WSDL 打客户端 jar 包,底层实际上通过 JDK 的动态代理特性完成的,CXF 实际上做了一个简单的封装。与 JDK 动态客户端不一样的是,此时无需使用

                    HelloService 接口,可以说是货真价实的 WS 动态客户端

            3)、通用动态代理客户端

import org.apache.cxf.endpoint.Client;import org.apache.cxf.endpoint.dynamic.DynamicClientFactory;public class DynamicClient {    public static void main(String[] args) {        DynamicClientFactory factory = DynamicClientFactory.newInstance();        Client client = factory.createClient("http://localhost:8080/ws/soap/hello?wsdl");        try {            Object[] results = client.invoke("say", "world");            System.out.println(results[0]);        } catch (Exception e) {            e.printStackTrace();        }    }}

                   这种方案与“方案三”类似,但不同的是,它不仅用于调用 JAX-WS 方式发布的 WS,也用于使用 simple 方式发布的 WS,更加智能了

            4)、基于 CXF simple 方式的客户端

import org.apache.cxf.frontend.ClientProxyFactoryBean;public class SimpleClient {    public static void main(String[] args) {        ClientProxyFactoryBean factory = new ClientProxyFactoryBean();        factory.setAddress("http://localhost:8080/ws/soap/hello");        factory.setServiceClass(HelloService.class);        HelloService helloService = factory.create(HelloService.class);        String result = helloService.say("world");        System.out.println(result);    }}          

                   仅用于调用 simple 方式发布的 WS,不能调用 JAX-WS 方式发布的 WS

            5)、基于 Spring 的客户端

                   方式一:使用 JaxWsProxyFactoryBean

<!-- lang: 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"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">    <bean id="factoryBean" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">        <property name="serviceClass" value="demo.ws.soap_spring_cxf.HelloService"/>        <property name="address" value="http://localhost:8080/ws/soap/hello"/>    </bean>    <bean id="helloService" factory-bean="factoryBean" factory-method="create"/></beans>
                   方式二:使用 jaxws:client(推荐)
<!-- lang: 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"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://cxf.apache.org/jaxws       http://cxf.apache.org/schemas/jaxws.xsd">    <jaxws:client id="helloService"                  serviceClass="demo.ws.soap_spring_cxf.HelloService"                  address="http://localhost:8080/ws/soap/hello"/></beans>

                     客户端代码

import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Client {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("spring-client.xml");        HelloService helloService = context.getBean("helloService", HelloService.class);        String result = helloService.say("world");        System.out.println(result);    }}
四、SOAP 及其安全控制

       1、什么是WSDL

             WSDL 的全称是 Web Services Description Language(Web 服务描述语言),用于描述 WS 的具体内容

           

                1)、definitions :WSDL 的根节点,有两个重要属性:

                          a)、name:WS 名称,默认为“WS 实现类 + Service”,例如:HelloServiceImplService

                          b)、targetNamespace:WS 目标命名空间,默认为“WS 实现类对应包名倒排后构成的地址”,例如:http://soap_spring_cxf.ws.demo/

                          可以在 @WebService 注解中配置以上两个属性值,但这个配置一定要在 WS 实现类上进行,WS 接口类只需标注一个 WebService 注解即可

                 2)、definitions下有5个子节点

                        a)、type:描述了 WS 中所涉及的数据类型

                        b)、portType:定义了 WS 接口名称(endpointInterface)及其操作名称,以及每个操作的输入与输出消息

                        c)、message:对相关消息进行了定义(供 types 与 portType 使用)

                        d)、binding:提供了对 WS 的数据绑定方式

                        e)、service:WS 名称及其端口名称(portName),以及对应的 WSDL 地址

                        其中包含了两个重要信息

                              portName:WS 的端口名称,默认为“WS 实现类 + Port”,例如:HelloServiceImplPort

                              endpointInterface:WS 的接口名称,默认为“WS 实现类所实现的接口”,例如:HelloService

                              可以在@WebService注解在配置这两个属性,通用需在WS实现类上进行

       2、什么是SOAP

            SOAP 是用于封装 WS 请求与响应的,包括两个部分:Header、Body,用于传输的数据都放在 Body 中了,一些特殊的属性需要放在 Header 中

           

       3、Spring + CXF + WSS4J实现安全的WS调用框架——基于用户令牌的身份认证

             1)、服务端

                    a)、添加maven依赖

<!-- 底层实现是 WSS4J,CXF 只是对其做了一个封装而已 --><dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-ws-security</artifactId>    <version>${cxf.version}</version></dependency>

                    b)、完成服务端 CXF 相关配置

<?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"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.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">    <bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">        <constructor-arg>            <map>                <!-- 表示使用基于“用户名令牌”的方式进行身份认证 -->                <entry key="action" value="UsernameToken"/>                <!-- 表示密码以明文方式出现 -->                <entry key="passwordType" value="PasswordText"/>                <!-- 提供一个用于密码验证的回调处理器(CallbackHandler) -->                <entry key="passwordCallbackRef" value-ref="serverPasswordCallback"/>            </map>        </constructor-arg>    </bean>    <jaxws:endpoint id="helloService" implementor="#helloServiceImpl" address="/soap/hello">        <jaxws:inInterceptors>            <ref bean="wss4jInInterceptor"/>        </jaxws:inInterceptors>    </jaxws:endpoint>    <!-- 只需要在 Bus 上配置一个 logging feature,就可以监控每次 WS 请求与响应的日志 -->    <cxf:bus>        <cxf:features>            <cxf:logging/>        </cxf:features>    </cxf:bus></beans>

                    c)、ServerPasswordCallback具体实现

import java.io.IOException;import java.util.HashMap;import java.util.Map;import javax.security.auth.callback.Callback;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.callback.UnsupportedCallbackException;import org.apache.wss4j.common.ext.WSPasswordCallback;import org.springframework.stereotype.Component;@Componentpublic class ServerPasswordCallback implements CallbackHandler {    private static final Map<String, String> userMap = new HashMap<String, String>();    static {        userMap.put("client", "clientpass");        userMap.put("server", "serverpass");    }    @Override    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {        WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];        String clientUsername = callback.getIdentifier();        String serverPassword = userMap.get(clientUsername);        if (serverPassword != null) {            callback.setPassword(serverPassword);        }    }}

             2)、客户端

                    a)、完成客户端 CXF 相关配置

<?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:context="http://www.springframework.org/schema/context"       xmlns:jaxws="http://cxf.apache.org/jaxws"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd       http://cxf.apache.org/jaxws       http://cxf.apache.org/schemas/jaxws.xsd">    <context:component-scan base-package="demo.ws"/>    <bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">        <constructor-arg>            <map>                <entry key="action" value="UsernameToken"/>                <!-- 提供客户端的用户名(user = client) -->                <entry key="user" value="client"/>                <entry key="passwordType" value="PasswordText"/>                <entry key="passwordCallbackRef" value-ref="clientPasswordCallback"/>            </map>        </constructor-arg>    </bean>    <jaxws:client id="helloService"                  serviceClass="demo.ws.soap_spring_cxf_wss4j.HelloService"                  address="http://localhost:8080/ws/soap/hello">        <jaxws:outInterceptors>            <ref bean="wss4jOutInterceptor"/>        </jaxws:outInterceptors>    </jaxws:client></beans>

                    b)、ClientPasswordCallback 实现

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.wss4j.common.ext.WSPasswordCallback;import org.springframework.stereotype.Component;@Componentpublic class ClientPasswordCallback implements CallbackHandler {    @Override    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {        WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];        callback.setPassword("clientpass");    }}

             3)、调用 WS 并观察控制台日志

                    部署应用并启动 Tomcat,再次调用 WS,此时会在 Tomcat 控制台里的 Inbound Message 中看到如下

                    

                    可见,在 SOAP Header 中提供了 UsernameToken 的相关信息,但 Username 与 Password 都是明文的,SOAP Body 也是明文的,将passwordType 中

                    PasswordText 改为 PasswordDigest(服务端与客户端都需要做同样的修改) ,即修改为密文

                   

       4、Spring + CXF + WSS4J实现安全的WS调用框架——基于数字签名的身份认证

             数字签名从字面上理解就是一种基于数字的签名方式,当客户端发送 SOAP 消息时,需要对其进行“签名”,来证实自己的身份,当服务端接收 SOAP 消息时,需要对

             其签名进行验证(简称“验签”)。在客户端与服务端上都有各自的“密钥库”,这个密钥库里存放了“密钥对”,而密钥对实际上是由“公钥”与“私钥”组成的。

             当客户端发送SOAP 消息时,需要使用自己的私钥进行签名,当客户端接收 SOAP 消息时,需要使用客户端提供的公钥进行验签。客户端与服务端的消息调用实际

            上是双向的,就是说,客户端与服务端的密钥库里所存放的信息是这样的:

                        客户端密钥库:客户端的私钥(用于签名)、服务端的公钥(用于验签)

                        服务端密钥库:服务端的私钥(用于签名)、客户端的公钥(用于验签)

             1)、生成密钥库

                    创建keystore.bat,运行生成server_store.jks、client_store.jks,将 server_store.jks 放入服务端classpath中,client_store.jks 放入客户端classpath中

@echo offkeytool -genkeypair -alias server -keyalg RSA -dname "cn=server" -keypass serverpass -keystore server_store.jks -storepass storepasskeytool -exportcert -alias server -file server_key.rsa -keystore server_store.jks -storepass storepasskeytool -importcert -alias server -file server_key.rsa -keystore client_store.jks -storepass storepass -nopromptdel server_key.rsakeytool -genkeypair -alias client -dname "cn=client" -keyalg RSA -keypass clientpass -keystore client_store.jks -storepass storepasskeytool -exportcert -alias client -file client_key.rsa -keystore client_store.jks -storepass storepasskeytool -importcert -alias client -file client_key.rsa -keystore server_store.jks -storepass storepass -nopromptdel client_key.rsa

             2)、完成服务端 CXF 相关配置

<bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">    <constructor-arg>        <map>            <!-- 验签(使用对方的公钥) -->            <entry key="action" value="Signature"/>            <entry key="signaturePropFile" value="server.properties"/>        </map>    </constructor-arg></bean>
                   其中action 为 Signature,server.properties为:

org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlinorg.apache.ws.security.crypto.merlin.file=server_store.jksorg.apache.ws.security.crypto.merlin.keystore.type=jksorg.apache.ws.security.crypto.merlin.keystore.password=storepass

             3)、完成客户端 CXF 相关配置

<bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">    <constructor-arg>        <map>            <!-- 签名(使用自己的私钥) -->            <entry key="action" value="Signature"/>            <entry key="signaturePropFile" value="client.properties"/>            <entry key="signatureUser" value="client"/>            <entry key="passwordCallbackRef" value-ref="clientPasswordCallback"/>        </map>    </constructor-arg></bean>
                    其中action 为 Signature,client.properties为:
org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlinorg.apache.ws.security.crypto.merlin.file=client_store.jksorg.apache.ws.security.crypto.merlin.keystore.type=jksorg.apache.ws.security.crypto.merlin.keystore.password=storepass

             4)、调用 WS 并观察控制台日志

                   

       5、SOAP 消息的加密与解密

             WSS4J 除了提供签名与验签(Signature)这个特性以外,还提供了加密与解密(Encrypt)功能

             1)、服务端

<bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">    <constructor-arg>        <map>            <!-- 验签 与 解密 -->            <entry key="action" value="Signature Encrypt"/>            <!-- 验签(使用对方的公钥) -->            <entry key="signaturePropFile" value="server.properties"/>            <!-- 解密(使用自己的私钥) -->            <entry key="decryptionPropFile" value="server.properties"/>            <entry key="passwordCallbackRef" value-ref="serverPasswordCallback"/>        </map>    </constructor-arg></bean>

             2)、客户端

<bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">    <constructor-arg>        <map>            <!-- 签名 与 加密 -->            <entry key="action" value="Signature Encrypt"/>            <!-- 签名(使用自己的私钥) -->            <entry key="signaturePropFile" value="client.properties"/>            <entry key="signatureUser" value="client"/>            <entry key="passwordCallbackRef" value-ref="clientPasswordCallback"/>            <!-- 加密(使用对方的公钥) -->            <entry key="encryptionPropFile" value="client.properties"/>            <entry key="encryptionUser" value="server"/>        </map>    </constructor-arg></bean>

             3)、调用 WS 并观察控制台日志

                   

五、使用 CXF 开发 REST 服务

       1、REST全称是 Representational State Transfer(表述性状态转移),并没有 WSDL 的概念,主张用简单粗暴的方式来表达数据,传递的数据格式可以是 JSON 格式,

             也可以是 XML 格式,本质上是使用 URL 来访问资源的一种方式,服务端将内部资源发布 REST 服务,客户端通过 URL 来访问这些资源

       2、使用 CXF 发布与调用 REST 服务

             1)、添加 Maven 依赖

<?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>demo.ws</groupId>    <artifactId>rest_cxf</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <cxf.version>3.0.0</cxf.version>        <jackson.version>2.4.1</jackson.version>    </properties>    <dependencies>        <!-- CXF -->        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-frontend-jaxrs</artifactId>            <version>${cxf.version}</version>        </dependency>        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-transports-http-jetty</artifactId>            <version>${cxf.version}</version>        </dependency>        <!-- 使用了 Jackson 来实现 JSON 数据的转换 -->        <dependency>            <groupId>com.fasterxml.jackson.jaxrs</groupId>            <artifactId>jackson-jaxrs-json-provider</artifactId>            <version>${jackson.version}</version>        </dependency>    </dependencies></project>

             2)、定义一个 REST 服务接口

public interface ProductService {    /*      @Consumes(输入)、@Produces(输出),可使用 MediaType 常量      相关参数注解:@PathParam(路径参数)、@FormParam(表单参数)、@QueryParam(请求参数)    */    @GET    @Path("/products")    @Produces(MediaType.APPLICATION_JSON)    List<Product> retrieveAllProducts();    @GET    @Path("/product/{id}")    @Produces(MediaType.APPLICATION_JSON)    Product retrieveProductById(@PathParam("id") long id);    @POST    @Path("/products")    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)    @Produces(MediaType.APPLICATION_JSON)    List<Product> retrieveProductsByName(@FormParam("name") String name);    @POST    @Path("/product")    @Consumes(MediaType.APPLICATION_JSON)    @Produces(MediaType.APPLICATION_JSON)    Product createProduct(Product product);    /*      请求体中的数据将自动转换为 JSON 格式并映射到 Map      返回的 Product 类型的数据将自动转换为 JSON 格式并返回到客户端    */    @PUT    @Path("/product/{id}")    @Consumes(MediaType.APPLICATION_JSON)    @Produces(MediaType.APPLICATION_JSON)    Product updateProductById(@PathParam("id") long id, Map<String, Object> fieldMap);    @DELETE    @Path("/product/{id}")    @Produces(MediaType.APPLICATION_JSON)    Product deleteProductById(@PathParam("id") long id);}

             3)、使用 CXF 发布 REST 服务

//运行以上 Server 类,将以 standalone 方式发布 REST 服务public class Server {    public static void main(String[] args) {        // 添加 ResourceClass:一个或一组相关的资源类,即接口对应的实现类(注意:REST 规范允许资源类没有接口)        List<Class<?>> resourceClassList = new ArrayList<Class<?>>();        resourceClassList.add(ProductServiceImpl.class);        /*   ResourceProvider:资源类对应的 Provider,此时使用 CXF 提供的    org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider 进行装饰*/         List<ResourceProvider> resourceProviderList = new ArrayList<ResourceProvider>();        resourceProviderList.add(new SingletonResourceProvider(new ProductServiceImpl()));        /*   Providers:REST 服务所需的 Provider,此时使用了 Jackson 提供的 org.codehaus.jackson.jaxrs.JacksonJsonProvider,   用于实现 JSON 数据的序列化与反序列化*/        List<Object> providerList = new ArrayList<Object>();        providerList.add(new JacksonJsonProvider());        /*   CXF 提供了一个名为 org.apache.cxf.jaxrs.JAXRSServerFactoryBean 的类,专用于发布 REST 服务,   只需为该类的实例对象指定四个属性即可:Address/ResourceClasses/ResourceProvidersProviders*/         JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();        factory.setAddress("http://localhost:8080/ws/rest");        factory.setResourceClasses(resourceClassList);        factory.setResourceProviders(resourceProviderList);        factory.setProviders(providerList);        factory.create();        System.out.println("rest ws is published");    }}

             4)、使用 CXF 调用 REST 服务

                    a)、添加maven依赖

<dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-rs-client</artifactId>    <version>${cxf.version}</version></dependency>

                    b)、CXF 提供了三种 REST 客户端

                           方式1:JAX-RS 1.0 时代的客户端

                                        本质是使用 CXF 提供的 org.apache.cxf.jaxrs.client.JAXRSClientFactory 工厂类来创建 ProductService 代理对象,通过代理对象调用目标对象上

                                        的方法。客户端同样也需要使用 Provider,此时仍然使用了 Jackson 提供的 org.codehaus.jackson.jaxrs.JacksonJsonProvider

public class JAXRSClient {    public static void main(String[] args) {        String baseAddress = "http://localhost:8080/ws/rest";                List<Object> providerList = new ArrayList<Object>();        providerList.add(new JacksonJsonProvider());        ProductService productService = JAXRSClientFactory.create(baseAddress, ProductService.class, providerList);        List<Product> productList = productService.retrieveAllProducts();        for (Product product : productList) {            System.out.println(product);        }    }}

                           方式2:JAX-RS 2.0 时代的客户端

                                        在 JAX-RS 2.0 中提供了一个名为 javax.ws.rs.client.ClientBuilder 的工具类,可用于创建客户端并调用 REST 服务,显然这种方式比前一种要先进,

                                        因为在代码中不再依赖 CXF API 了

public class JAXRS20Client {    public static void main(String[] args) {        String baseAddress = "http://localhost:8080/ws/rest";                JacksonJsonProvider jsonProvider = new JacksonJsonProvider();        List productList = ClientBuilder.newClient()            .register(jsonProvider)            .target(baseAddress)            .path("/products")            .request(MediaType.APPLICATION_JSON)            .get(List.class);/*   如果想返回带有泛型的 List<Product>   List<Product> productList = ClientBuilder.newClient()    .register(jsonProvider)    .target(baseAddress)    .path("/products")    .request(MediaType.APPLICATION_JSON)    .get(new GenericType<List<Product>>() {});*/        for (Object product : productList) {            System.out.println(product);        }    }}

                           方式3:通用的 WebClient 客户端

                                        CXF 还提供了一种更为简洁的方式,使用 org.apache.cxf.jaxrs.client.WebClient 来调用 REST 服务

public class CXFWebClient {    public static void main(String[] args) {        String baseAddress = "http://localhost:8080/ws/rest";                List<Object> providerList = new ArrayList<Object>();        providerList.add(new JacksonJsonProvider());                List productList = WebClient.create(baseAddress, providerList)            .path("/products")            .accept(MediaType.APPLICATION_JSON)            .get(List.class);/*  如果想返回带有泛型的 List<Product>  List<Product> productList = WebClient.create(baseAddress, providerList)      .path("/products")      .accept(MediaType.APPLICATION_JSON)      .get(new GenericType<List<Product>>() {});*/        for (Object product : productList) {            System.out.println(product);        }    }}

       3、使用 Spring + CXF 发布 REST 服务

            1)、添加maven依赖

<?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>demo.ws</groupId>    <artifactId>rest_spring_cxf</artifactId>    <version>1.0-SNAPSHOT</version>    <packaging>war</packaging>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <spring.version>4.0.6.RELEASE</spring.version>        <cxf.version>3.0.0</cxf.version>        <jackson.version>2.4.1</jackson.version>    </properties>    <dependencies>        <!-- Spring -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-web</artifactId>            <version>${spring.version}</version>        </dependency>        <!-- CXF -->        <dependency>            <groupId>org.apache.cxf</groupId>            <artifactId>cxf-rt-frontend-jaxrs</artifactId>            <version>${cxf.version}</version>        </dependency>        <!-- Jackson -->        <dependency>            <groupId>com.fasterxml.jackson.jaxrs</groupId>            <artifactId>jackson-jaxrs-json-provider</artifactId>            <version>${jackson.version}</version>        </dependency>    </dependencies></project>

            2)、配置web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"         version="3.0">    <!-- Spring -->    <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>classpath:spring.xml</param-value>    </context-param>    <listener>        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>    <!-- CXF -->    <servlet>        <servlet-name>cxf</servlet-name>        <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>

            3)、编写接口实现类(添加@Component)

            4)、配置 Spring

<?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:context="http://www.springframework.org/schema/context"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd">    <context:component-scan base-package="demo.ws"/>    <import resource="spring-cxf.xml"/></beans>

            5)、配置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:jaxrs="http://cxf.apache.org/jaxrs"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd       http://cxf.apache.org/jaxrs       http://cxf.apache.org/schemas/jaxrs.xsd">    <jaxrs:server address="/rest">        <jaxrs:serviceBeans>            <ref bean="productServiceImpl"/>        </jaxrs:serviceBeans>        <jaxrs:providers>            <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>        </jaxrs:providers>    </jaxrs:server></beans>

            6)、调用调用 REST 服务

<script>    $(function() {        $.ajax({            type: 'get',            url: 'http://localhost:8080/ws/rest/products',            dataType: 'json',            success: function(data) {                var template = $("#product_table_template").html();                var render = Handlebars.compile(template);                var html = render({                    data: data                });                $('#product').html(html);            }        });    });</script>

       4、AJAX 的跨域问题

            如果服务端部署在 foo.com 域名下,而客户端部署在 bar.com 域名下,此时从 bar.com 发出一个 AJAX 的 REST 请求到 foo.com,就会出现报错:

                                      No 'Access-Control-Allow-Origin' header is present on the requested resource

            1)、使用 JSONP 解决 AJAX 跨域问题

                   JSONP 的全称是 JSON with Padding,实际上是在需要返回的 JSON 数据外,用一个 JS 函数进行封装,虽然 AJAX 不能跨域访问,但 JS 脚本是可以跨域

                   执行的,客户端将执行这个 callback 函数,并获取其中的 JSON 数据

                   a)、添加 Maven 依赖

<dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-rs-extension-providers</artifactId>    <version>${cxf.version}</version></dependency>

                   b)、添加 CXF 配置

<jaxrs:server address="/rest">    <jaxrs:serviceBeans>        <ref bean="productServiceImpl"/>    </jaxrs:serviceBeans>    <jaxrs:providers>        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>        <bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPreStreamInterceptor"/>    </jaxrs:providers>    <jaxrs:inInterceptors>        <bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpInInterceptor"/>    </jaxrs:inInterceptors>    <jaxrs:outInterceptors>        <bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPostStreamInterceptor"/>    </jaxrs:outInterceptors></jaxrs:server>

                   c)、使用 jQuery 发送基于 JSONP 的 AJAX 请求

$.ajax({    type: 'get',    url: 'http://localhost:8080/ws/rest/products',    //dataType:必须为“jsonp”,表示返回的数据类型为 JSONP 格式    dataType: 'jsonp',    //jsonp:表示 URL 中 JSONP 回调函数的参数名,CXF 默认接收的参数名是“_jsonp”,也可以在 JsonpInInterceptor 中配置    jsonp: '_jsonp',    //jsonpCallback:表示回调函数的名称,若未指定,则由 jQuery 自动生成    jsonpCallback: 'callback',    success: function(data) {        var template = $("#product_table_template").html();        var render = Handlebars.compile(template);        var html = render({            data: data        });        $('#product').html(html);    }});

            2)、使用 CORS 解决 AJAX 跨域问题

                   CORS 的全称是 Cross-Origin Resource Sharing(跨域资源共享),它是 W3C 提出的一个 AJAX 跨域访问规范,相比 JSONP 而言,它弥补了 JSONP 只能处

                   理 GET 请求的局限性,但是只有较为先进的浏览器才能全面支持 CORS。

                   a)、添加 Maven 依赖

<dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-rs-security-cors</artifactId>    <version>${cxf.version}</version></dependency>

                   b)、添加 CXF 配置

<jaxrs:server address="/rest">    <jaxrs:serviceBeans>        <ref bean="productServiceImpl"/>    </jaxrs:serviceBeans>    <jaxrs:providers>        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>        <bean class="org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter">    <!-- 配置 allowOrigins 属性,将其设置为客户端的域名,示例中为“http://localhost”,需根据实际情况进行设置 -->            <property name="allowOrigins" value="http://localhost"/>        </bean>    </jaxrs:providers></jaxrs:server>

                   c)、jQuery 发送 AJAX 请求

                         就像在相同域名下访问一样,无需做任何配置

                   d)、在 IE8 中使用 jQuery 发送 AJAX 请求时,需要配置 $.support.cors = true,才能开启 CORS 特性

六、Jersey RESTful WebService

       1、@PathParam

             1)、url:"/Jersey/api/1.0/my/first/1"

             2)、后台:

        @GET  @Path("/first/{id}")  @Produces({ MediaType.APPLICATION_JSON + ";charset=UTF-8" })  public String my(@PathParam(value = "id") String id) {       System.out.println("我的第一个jersey程序");       return "{\"id\":\""+id+"\"}";  }  

       2、@QueryParam

             1)、url:"/Jersey/api/1.0/my/first?id=123"

             2)、后台:

        @GET  @Path("/first")  @Produces({ MediaType.APPLICATION_JSON + ";charset=UTF-8" })  public String QueryParam(@QueryParam(value = "id") String id) {       System.out.println("我的第一个jersey程序");       return "{\"id\":\""+id+"\"}";  }  

       3、@FormParam

             1)、前端:

        <form action="/Jersey/api/1.0/my/form" method="post">  <input type="text" name="name">  <input type="submit" value="提交">  </form>

             2)、后台:

        @POST  @Path("/form")  @Produces({ MediaType.APPLICATION_JSON + ";charset=UTF-8" })  public String form(@FormParam("name") String name) {       System.out.println(name);       return "{\"name\":\""+name+"\"}";  }

       4、@BeanParam

             1)、前端:

        <form action="/Jersey/api/1.0/my/BeanParam" method="post">  <input type="text" name="name">  <input type="text" name="age">  <input type="submit" value="提交">  </form> 

             2)、bean:

           public class User {  @FormParam("name")  private String name;  @FormParam("age")  private String age;  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public String getAge() {  return age;  }  public void setAge(String age) {  this.age = age;  }   }

             3)、后台:

        @POST  @Path("/BeanParam")  @Produces({ MediaType.APPLICATION_JSON + ";charset=UTF-8" })  public String bean(@BeanParam User user) {  System.out.println(user);  return "{\"name\":\"" + user.toString() + "\"}";  }

       5、接收MultivaluedMap类型参数

             1)、前端:

        <body>      <input type="text" name="name" ng-model="user.name">      <input type="text" name="age" ng-model="user.age">      <input type="button" value="保存" ng-click="save()">  </body>

             2)、url请求:

           $http({  method : 'post',  url : "/Jersey/api/1.0/my/MultivaluedMap",  data : "json=" + angular.toJson($scope.user),  headers : {  'Content-Type' : 'application/x-www-form-urlencoded'  }     }).success(function(data) {  alert(data)     });

             3)、后端:

           @SuppressWarnings("unchecked")     @POST     @Path("/MultivaluedMap")     @Consumes("application/x-www-form-urlencoded")     @Produces({ MediaType.APPLICATION_JSON + ";charset=UTF-8" })     public String bean(MultivaluedMap<String, String> viParams) {  //得到viParams转换为json  System.out.println(viParams.getFirst("json"));  //转为map便于入库  System.out.println((Map<String, String>)JSON.parse(viParams.getFirst("json")));  return viParams.getFirst("json");     }

       6、文件上传

             1)、引入jar包:jersey-media-multipart-2.22.jar

             2)、前端:

    <body>  <input id="commonFile" type="file" class="commonFile"         onchange='uploadFile(this)'  multiple="multiple" />     </body>     <script type="text/javascript">                 function uploadFile() {                      var $$fd = new FormData();                      var _file = document.getElementById("commonFile");                      $$fd.append('file', _file.files[0]);                      $http({                          method : 'post',                          data : $$fd,                          //拼装uri路径参数                          url : "/Jersey/api/1.0/my/upload",                          headers : {                              'Content-Type' : undefined                          },                          /*序列化 formdata object*/                          transformRequest : angular.identity                      }).success(function(data) {                          alert(angular.toJson(data));                      });                  };        </script> 

             3)、后台:

           @POST     @Consumes(MediaType.MULTIPART_FORM_DATA)     @Path("/upload")     @Produces({ MediaType.APPLICATION_JSON + ";charset=UTF-8" })     public String upload(@FormDataParam("file") InputStream fileInputStream,@FormDataParam("file") FormDataContentDisposition disposition) {  String nFileName = disposition.getFileName();  File file = new File("D:\\file\\" + nFileName);  try {  // 使用common io的文件写入操作   FileUtils.copyInputStreamToFile(fileInputStream, file);  } catch (IOException ex) {  ex.printStackTrace();  }  return "{\"success\",\"true\"}";    }


总结:


                    

各种webService框架的解说:http://blog.csdn.net/chenleixing/article/details/44958549