webservice小结

来自hhstuhacker

可以用wsimport –keep http://localhost:9000/cxf?wsdl 生成客户端

也可以用CXFwsdl2java命令生成客户端代码

 

使用Cxf必须创建一个服务接口(客户端使用)、这个接口的实现类(服务端处理客户端请求的相关业务)、服务端启动类(发布服务)和客户端启动类(访问服务)。

注:Exception in thread “main” java.lang.NoClassDefFoundError:

Com/sun/mail/util/LineInputStream

         原因:JavaEE版本和JavaMail的版本不一致。

解决方法:windowàpreferencesàjava,把版本改成一致就可以了。

 

首先导入cxf的所有包。

HelloWorld为例,服务接口:

package com.test;

 

import javax.jws.WebService;

@WebService//必须注解WebService,让cxf知道这个接口是发布的WebService

public interface HelloWorld

{

    public String sayHi(String name);

}

服务实现类:

package com.test;

 

import javax.jws.WebService;

@WebService

public class HelloWorldImpl implements HelloWorld

{

    public String sayHi(String name)

{

System.out.println("Hello " + name);

        return "Hello " + name;

    }

}

服务端启动类:

package com.server;

 

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

 

import com.test.HelloWorldImpl;

public class ServerStart

{

    protected ServerStart() throws Exception

{

        HelloWorldImpl helloWorld = new HelloWorldImpl();

        String address = "http://localhost:9000/cxf";

        /**

        * 也可以使用注释的方式发布

        */

        //Endpoint.publish(address, helloWorld);

        //发布服务

        JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();

        server.setServiceClass(helloWorld.getClass());

        server.setAddress(address);

        server.create();

    }

   

    public static void main(String[] args) throws Exception

{

        new ServerStart();

    }

}

客户端启动类:

package com.client;

 

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

 

import com.test.HelloWorld;

public class ClientStart

{

    public static void main(String args[]) throws Exception

{

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        factory.setAddress("http://localhost:9000/cxf");

        HelloWorld client = factory.create(HelloWorld.class);

//调用客户端方法并打印在控制台 

System.out.println(client.sayHi("cxf"));

    }

}

 

2CXF复杂对象的传递

 

         复杂对象的传递,首先需要创建一个实体类,用于存放ListMap等,

提供其gettersetter方法。然后在接口中提供实体类Listgettersetter方法,以供客户端调用和赋值。相关业务在接口的实现类中处理。

例子如下:

实体类:

package com.server;

 

import java.util.List;

import java.util.Map;

public class Demo

{

    private String name;

    private int age;

    private List<Integer> list;

    private Map<Integer, String> map;

    private int array[];

 

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public List<Integer> getList() {

        return list;

    }

    public void setList(List<Integer> list) {

        this.list = list;

    }

    public Map<Integer, String> getMap() {

        return map;

    }

    public void setMap(Map<Integer, String> map) {

        this.map = map;

    }

    public int[] getArray() {

        return array;

    }

    public void setArray(int[] array) {

        this.array = array;

    }

}

接口:

package com.client;

 

import java.util.List;

@WebService

public interface ClientSimple {

 

    public List<Demo> getDemoList();

 

    public List<Demo> setDemoList(List<Demo> list);

}

接口实现类:

package com.server;

 

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

 

import javax.jws.WebService;

@WebService

public class ServerSimple implements ClientSimple {

    private int requestCount = 0;

   

    public List getDemoList(){

        requestCount++;//统计客户端访问次数

        System.out.println("requestCount= " + requestCount);

       

        List<Demo> demoList = new ArrayList<Demo>();

       

        Demo demo = new Demo();

        demo.setAge(22);

        demo.setName("xx");

        List<Integer> list = new ArrayList<Integer>();

        list.add(1);

        list.add(2);

        list.add(3);

        demo.setList(list);

        Map<Integer, String> map = new HashMap<Integer, String>();

        map.put(1, "a");

        map.put(2, "b");

        demo.setMap(map);

        int[] array = {1,2,3};

        demo.setArray(array);

       

        demoList.add(demo);

        return demoList;

    }

   

    public List<Demo> setDemoList(List<Demo> list){

        requestCount++;

        System.out.println("requestCount= " + requestCount);

        return list;

    }

}

服务启动类:

package com.server;

 

import javax.xml.ws.Endpoint;

public class ServerStart {

    protected ServerStart() throws Exception{

        System.out.println("Starting Server...");

        ServerSimple server = new ServerSimple();

        String address = "http://localhost:9001/Demo";//设置访问路径

        Endpoint.publish(address, server); //发布服务

    }

   

    public static void main(String[] args) throws Exception{

        new ServerStart();

        System.out.println("Server ready...");

        Thread.sleep(5*60*1000);//5分钟后服务端退出

        System.out.println("Server exiting");

        System.exit(0);

    }

}

客户端启动类:

package com.client;

 

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

 

import org.apache.cxf.interceptor.LoggingInInterceptor;

import org.apache.cxf.interceptor.LoggingOutInterceptor;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class ClientStart {

   

    public static void getServerList(){

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        //利用拦截器打印输入输出日志

        factory.getOutInterceptors().add(new LoggingInInterceptor());

        factory.getInInterceptors().add(new LoggingOutInterceptor());

       

        factory.setServiceClass(ClientSimple.class);

        factory.setAddress("http://localhost:9001/Demo");

        ClientSimple client = (ClientSimple)factory.create();

        List<Demo> demoList = new ArrayList<Demo>();

       

        System.out.println("getServerList begin....");

        System.out.println("List Size: " + demoList.size());

       

        for(Iterator<Demo> iter = demoList.iterator(); iter.hasNext();){

            Demo demo = iter.next();

            System.out.println(demo.toString());

        }

        System.out.println("getServerList end....");

    }

   

    public static void setServiceList(){

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        factory.getOutInterceptors().add(new LoggingInInterceptor());

        factory.getInInterceptors().add(new LoggingOutInterceptor());

       

        factory.setServiceClass(ClientSimple.class);

        factory.setAddress("http://localhost:9001/Demo");

        ClientSimple client = (ClientSimple)factory.create();

        List<Demo> demoList = new ArrayList<Demo>();

        System.out.println("setServerList begin....");

       

        Demo demo = new Demo();

        //demo赋值

        demo.setAge(22);

        demo.setName("xx");

        List<Integer> list1 = new ArrayList<Integer>();

        list1.add(3);

        list1.add(2);

        list1.add(1);

        demo.setList(list1);

        Map<Integer, String> map1 = new HashMap<Integer, String>();

        map1.put(1, "A");

        map1.put(2, "b");

        demo.setMap(map1);

        int[] array = {1,2,3};

        demo.setArray(array);

        //Demo放入demoList

        demoList.add(demo);

       

        demo = new Demo();

        demo.setAge(23);

        demo.setName("x-x");

        List<Integer> list2 = new ArrayList<Integer>();

        list2.add(3);

        list2.add(6);

        list2.add(9);

        demo.setList(list2);

        Map<Integer, String> map2 = new HashMap<Integer, String>();

        map2.put(1, "a");

        map2.put(2, "B");

        demo.setMap(map2);

        int[] array1 = {3,6,3};

        demo.setArray(array1);

        //放入第二个Demo

        demoList.add(demo);

       

        System.out.println("demoList Size: " + demoList.size());

       

        for(Iterator<Demo> iter = demoList.iterator(); iter.hasNext();){

            demo = iter.next();

            System.out.println(demo.toString());

        }

        System.out.println("getServerList end....");

    }

   

    public static void main(String[] args){

   

        getServerList();

        setServiceList();

    }

}

3CXF图片上传(MTOM

附件上传需要借助MTOM,也需要一个实体类,用来处理上传的附件。

实体类:

public class Resume {

    private String candidateName;//附件名

    private String resumeFileType;//附件类型

    private DataHandler resume;//附件

    public String getCandidateName() {

        return candidateName;

    }

    public void setCandidateName(String candidateName) {

        this.candidateName = candidateName;

    }

    public String getResumeFileType() {

        return resumeFileType;

    }

    public void setResumeFileType(String resumeFileType) {

        this.resumeFileType = resumeFileType;

    }

    public DataHandler getResume() {

        return resume;

    }

    public void setResume(DataHandler resume) {

        this.resume = resume;

    }

}

服务接口:

@WebService

public interface ResumeUploadService {

    void uploadResume(@WebParam(name="resume") Resume resume);

}

接口实现类:

@WebService(endpointInterface = "com.webservice.ResumeUploadService",

         serviceName = "ResumeService")

public class ResumeUploadServiceImpl implements ResumeUploadService {

 

    public void uploadResume(Resume resume) {

        DataHandler handler = resume.getResume();

        try{

            InputStream is = handler.getInputStream();

            OutputStream os = new FileOutputStream(

                    new File("d:\\" + resume.getCandidateName() + "."

                            + resume.getResumeFileType()));

           

            byte[] b = new byte[5*1000*1024];//设置附件最大限制

            int bytesRead = 0;

            while((bytesRead = is.read(b)) != -1){

                os.write(b, 0, bytesRead);

            }

            os.flush();

            os.close();

            is.close();

        }catch(IOException e){

            e.printStackTrace();

        }

    }

 

}

服务启动类:

public class ServerStart {

    public static void main(String[] args) throws Exception{

        new ServerStart();

        System.out.println("Server ready...");

        Thread.sleep(5*60*1000);//5分钟后服务端退出

        System.out.println("Server exiting");

        System.exit(0);

    }

   

    protected ServerStart() {

        System.out.println("Starting Server...");

        ResumeUploadServiceImpl rus = new ResumeUploadServiceImpl();

        String address = "http://localhost:9000/mtom0.2/upload";

        Endpoint ep = Endpoint.publish(address, rus);

        Binding binding = ep.getBinding();

        ((SOAPBinding)binding).setMTOMEnabled(true);

    }

 

}

客户端启动类:

public class ClientStart {

 

    /**

     * @param args

     */

    public static void main(String[] args) throws Exception{

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        factory.setServiceClass(ResumeUploadService.class);

        factory.setAddress("http://localhost:9000/mtom0.2/upload");

        ResumeUploadService client = (ResumeUploadService)factory.create();

        Resume resume = new Resume();

       

        int i = new Random().nextInt();

System.out.println("生成的随机数为:" + i);

        resume.setCandidateName("cxf" + i);//设置附件名

        resume.setResumeFileType("png");//设置附件类型

       

        DataSource source = new FileDataSource(new File("e:\\upload.png"));

        resume.setResume(new DataHandler(source));

        //测试文件大小

        InputStream is = resume.getResume().getInputStream();

        System.out.println("文件大小为:" + is.available());

       

        client.uploadResume(resume);//开始上传附件

System.out.println("上传成功!");

        System.exit(0);

    }

 

}

4CXFMTOM

(原文地址:http://blog.csdn.net/fhd001/archive/2010/08/05/5789311.aspx)

MTOM消息传输优化机制Message Transmission and Optimization Mechanism)是一个标准的服务,让你的服务传输二进制数据更方便,更有效率。很多框架都支持MTOM---Axis2,JAX-WS RI, JBoss WS , XFire , Microsoft WCF ,等更多.如果二进制是xml文档的一部分,它需要base64编码。当MTOM在一个服务上启用时,它可能需要二进制数据且通常是xml文档的一部分, 并为它创建一个附件。

启用MTOM是一个相当简单的过程。首先,你必须注解POJO类型或schema类型.........下面告诉你怎样为JAXB激活MTOM.   MTOM也支持Aegis.

1、    注解

a. 为MTOM修改你的schema

假如我们有这样一个Picture的schema类型,如:

<schema targetNamespace="http://pictures.com"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <element name="Picture">

    <complexType>

      <sequence>

        <element name="Title" type="xsd:string"/>

        <element name="ImageData" type="xsd:base64Binary"/>

      </sequence>

    </complexType>

  </element>

</schema>

在这种情况下,ImageData元素是我们想作为附件传送。我们只需要添加一个xmime : expectedContentTypes 注解:

<schema targetNamespace="http://pictures.com"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns:xmime="http://www.w3.org/2005/05/xmlmime">

  <element name="Picture">

    <complexType>

      <sequence>

        <element name="Title" type="xsd:string"/>

        <element name="ImageData" type="xsd:base64Binary"

           xmime:expectedContentTypes="application/octet-stream"/>

      </sequence>

    </complexType>

  </element>

</schema>

这告诉JAXB(其中WSDL2Java用来为你的服务生成POJO),这个字段可以是任何内容类型。 而不是为base64Binary创建一个byte[]数组它将创建一个DataHandler ,而不是用于流数据。

b. 注解你的JAXB bean来启用MTOM

@XmlType

public class Picture {

  private String title;

  @XmlMimeType("application/octet-stream")

  private DataHandler imageData;

  public String getTitle() { return title; }

  public void setTitle(String title) { this.title = title; }

  public DataHandler getImageData() { return imageData; }

  public void setImageData(DataHandler imageData) { this.imageData = imageData; }

}

2、    在你的服务上启用MTOM

 

如果你使用JAX-WS  API发布你的服务,你可以像这样启用MTOM,如:

import javax.xml.ws.Endpoint;

import javax.xml.ws.soap.SOAPBinding;

Endpoint ep = Endpoint.publish("http://localhost/myService", new MyService());

SOAPBinding binding = (SOAPBinding) ep.getBinding();

binding.setMTOMEnabled(true);

或者,你用xml来发布你的服务:

<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-2.0.xsd

http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">

  <jaxws:endpoint

    id="helloWorld"

    implementor="demo.spring.HelloWorldImpl"

    address="http://localhost/HelloWorld">

    <jaxws:properties>

      <entry key="mtom-enabled" value="true"/>

    </jaxws:properties>

  </jaxws:endpoint>

</beans>

如果你使用simple frontend,你可以在ServerFactoryBeanClientProxyFactoryBean设置mtom-enabled属性.

Map<String,Object> props = new HashMap<String, Object>();

props.put("mtom-enabled", Boolean.TRUE); // Boolean.TRUE or "true" will work as the property value here

ClientProxyFactoryBean pf = new ClientProxyFactoryBean();

pf.setPropertyies(props);

....

YourClient client = (YourClient) pf.create();

ServerFactoryBean sf = new ServerFactoryBean();

sf.setPropertyies(props);

...

sf.create();

你也可以用xml来配置(simple frontend):

<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-2.0.xsd

http://cxf.apache.org/simple http://cxf.apache.org/schema/simple.xsd">

  <simple:server

    id="helloWorld"

    serviceClass="demo.spring.HelloWorldImpl"

    address="http://localhost/HelloWorld">

    <simple:properties>

      <entry key="mtom-enabled" value="true"/>

    </simple:properties>

  </simple:server>

  <simple:client

    id="helloWorldClient"

    serviceClass="demo.spring.HelloWorldImpl"

    address="http://localhost/HelloWorld">

    <simple:properties>

      <entry key="mtom-enabled" value="true"/>

    </simple:properties>

  </simple:client>

</beans>

3、    使用DataHandlers

Picture picture = ...;

DataHandler handler = picture.getImageData();

InputStream is = handler.getInputStream();

 

DataSource source = new ByteArrayDataSource(new byte[] {...}, "content/type");

DataSource source = new FileDataSource(new File("my/file"));

Picture picture = new Picture();

picture.setImageData(new DataHandler(source));

4、    大文件上传

上传需要一个实体类(类上需注解XmlAccessorType(XmlAccessType.FIElD)),实例类里有三个参数(candidateName附件名、resumeFileType附件类型、DataHandler resume附件DataHandler上需注解@XmlMineType(“application/octet-stream”)还需要在服务接口注解@SOAPBinding(style=”SOAPBinding.Style.RPC”)@MTOM来开启MTOM

@SOAPBinding(style = SOAPBinding.Style.RPC)指定SOAP消息样式,有两个枚举值:SOAPBinding.Style.DOCUMENT(默认)和 SOAPBinding.Style.RPC,可以对比这两种方式生成的wsdl会有所不同,而且生成的客户端代码也会有所不同。

附件实体类:

package com.pojo;

 

import javax.activation.DataHandler;

import javax.xml.bind.annotation.XmlAccessType;

import javax.xml.bind.annotation.XmlAccessorType;

import javax.xml.bind.annotation.XmlMimeType;

@XmlAccessorType(XmlAccessType.FIELD)

public class Resume {

    private String candidateName;//附件名

    private String resumeFileType;//附件类型

    @XmlMimeType("application/octet-stream")

    private DataHandler resume;//附件

    public String getCandidateName() {

        return candidateName;

    }

    public void setCandidateName(String candidateName) {

        this.candidateName = candidateName;

    }

    public String getResumeFileType() {

        return resumeFileType;

    }

    public void setResumeFileType(String resumeFileType) {

        this.resumeFileType = resumeFileType;

    }

    public DataHandler getResume() {

        return resume;

    }

    public void setResume(DataHandler resume) {

        this.resume = resume;

    }

}

接口类:

package com.webservice;

 

import java.io.IOException;

 

import javax.jws.WebParam;

import javax.jws.WebService;

import javax.jws.soap.SOAPBinding;

import javax.xml.ws.soap.MTOM;

 

import com.pojo.Resume;

@WebService

@SOAPBinding(style=SOAPBinding.Style.RPC)

@MTOM

public interface ResumeUploadService {

    void uploadResume(@WebParam(name="resume") Resume resume) throws IOException;

}

接口实现类:

package com.webservice;

 

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

 

import javax.activation.DataHandler;

import javax.jws.WebService;

 

import com.pojo.Resume;

@WebService(endpointInterface = "com.webservice.ResumeUploadService",

         serviceName = "ResumeService")

//@BindingType(SOAPBinding.SOAP11HTTP_MTOM_BINDING)

public class ResumeUploadServiceImpl implements ResumeUploadService {

 

    public void uploadResume(Resume resume) throws IOException{

        DataHandler handler = resume.getResume();

        final int BUFFER_SIZE = 50*1024*1024;// 缓冲区大小为3M

        long fileLength = 0;

        int read = 0;

        InputStream is = null;

        OutputStream os = null;

       

        try{

//1.

            is = handler.getInputStream();

            os = new FileOutputStream(

                    new File("d:\\" + resume.getCandidateName() + "."

                            + resume.getResumeFileType()));

//          is = new BufferedInputStream(handler.getInputStream());

//          os = new BufferedOutputStream(new FileOutputStream("d:\\" + resume.getCandidateName() + "."

//                  + resume.getResumeFileType()));

            fileLength = is.available();

System.out.println("服务端测试文件大小:" + fileLength);

 

            byte[] b = new byte[BUFFER_SIZE];

            while((read = is.read(b)) != -1){

                os.write(b, 0, read);

               

            }

           

//2.目前测试6M文件可以上传,10M内存溢出

//

//          byte[] dst = new byte[BUFFER_SIZE];//每次读出3M

//          for(int offset=0; offset<fileLength; offset+=BUFFER_SIZE){

//              if(fileLength - offset >= BUFFER_SIZE){

//                  read = is.read(dst);

//                  os.write(dst, 0, read);

//System.out.println("test if run " + offset);

//              }else{

//                  read = is.read(dst);

//                  os.write(dst, 0, read);

//System.out.println("test else run");

//              }

//              read=0;

//              os.flush();

//          }

           

        }catch(IOException e){

            e.printStackTrace();

        }finally{

            if(is != null)is.close();

            if(os != null){

                os.flush();

                os.close();

            }

        }

    }

}

服务端启动类:

package com.server;

 

import javax.xml.ws.Endpoint;

public class ServerStart {

 

    /**

     * @param args

     * 上传附件的时候应注意把MyException自带的Java EE 5 Libraries删掉,

     * 否则会出现Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream

     * 原因:JavaEE版本和JavaMail的版本不一致。

     */

    public static void main(String[] args) throws Exception{

        new ServerStart();

        System.out.println("Server ready...");

        Thread.sleep(5*60*1000);//5分钟后服务端退出

        System.out.println("Server exiting");

        System.exit(0);

    }

   

    protected ServerStart() {

        System.out.println("Starting Server...");

        ResumeUploadServiceImpl rus = new ResumeUploadServiceImpl();

        String address = "http://localhost:9000/mtom0.2/upload";

        Endpoint.publish(address, rus);

//      Endpoint ep = Endpoint.publish(address, rus);

//      Binding binding = ep.getBinding();

//      System.out.println(binding.getBindingID());

//      ((SOAPBinding)binding).setMTOMEnabled(true);

    }

}

客户端启动类:

package com.client;

 

import java.io.File;

import java.io.InputStream;

import java.util.Random;

 

import javax.activation.DataHandler;

import javax.activation.DataSource;

import javax.activation.FileDataSource;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

 

import com.pojo.Resume;

import com.webservice.ResumeUploadService;

public class ClientStart {

 

    /**

     * @param args

     */

    public static void main(String[] args) throws Exception{

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        factory.setServiceClass(ResumeUploadService.class);

        factory.setAddress("http://localhost:9000/mtom0.2/upload");

        ResumeUploadService client = (ResumeUploadService)factory.create();

        Resume resume = new Resume();

       

        //启动MTOM(有问题)

//      QName qname = new QName("http://webservice.com/", "ResumeService");

//      Service svc = Service.create(qname);

//      ResumeUploadService proxy = svc.getPort(ResumeUploadService.class);

//      BindingProvider bp = (BindingProvider) proxy;

//      SOAPBinding binding = (SOAPBinding) bp.getBinding();

//      binding.setMTOMEnabled(true);

       

        int i = new Random().nextInt();

System.out.println("生成的随机数为:" + i);

        resume.setCandidateName("cxf" + i);//设置附件名

       

        DataSource source = new FileDataSource(new File("e:\\myTools\\jdk-1_5_0-windows-i586.exe"));

        DataHandler handler = new DataHandler(source);

        resume.setResume(handler);//设置附件

        //得到附件类型

        String fileType = source.getName().substring(source.getName().lastIndexOf(".")+1);

System.out.println("文件类型为:" + fileType);

        resume.setResumeFileType(fileType);//设置附件类型

        //测试文件大小

        InputStream is = resume.getResume().getInputStream();

        System.out.println("文件大小为:" + is.available() + "个字节");

       

        client.uploadResume(resume);//开始上传附件

System.out.println("上传成功!");

        System.exit(0);

    }

 

}

5、 CXFWS-Security安全机制

一个WebService挂在互联网上,如果知道地址,那么任何人都可以访问,所以应该考虑 WebService的安全问题。应该只让指定的客户端访问。下面利用Jax-WS的拦截器来做用户验证。

和上面例子一样,首先需要一个服务接口和服务实现类,这里省略。

其次需要2个身份验证的CallbackHandler

服务端CallbackHandler

package com.mms.webservice.test;

 

import java.io.IOException;

 

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.UnsupportedCallbackException;

 

import org.apache.ws.security.WSPasswordCallback;

public class ServerPasswordCallback implements CallbackHandler {

 

    public void handle(Callback[] callbacks) throws IOException,

            UnsupportedCallbackException {

 

        WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[0];

        String id = pwcb.getIdentifier();

        switch (pwcb.getUsage()) {

        case WSPasswordCallback.USERNAME_TOKEN_UNKNOWN:

            // 密码方式 plaintext

            if (!"cxf".equals(id)) {

                throw new UnsupportedCallbackException(pwcb,

                        "username is invalid.");

            }

            if (!"mima".equals(pwcb.getPassword())) {

                throw new UnsupportedCallbackException(pwcb,

                        "password is invalid.");

            }

            break;

 

        case WSPasswordCallback.DECRYPT:

        case WSPasswordCallback.SIGNATURE:

            // used to retrieve password for private key

            if ("serverkey".equals(id)) {

                pwcb.setPassword("serverpass");

            }

            break;

        }

 

    }

}

客户端CallbackHandler

package com.mms.webservice.test;

 

import java.io.IOException;

 

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.UnsupportedCallbackException;

 

import org.apache.ws.security.WSPasswordCallback;

public class ClientPasswordCallback implements CallbackHandler {

 

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

 

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

 

        //服务器标识

        System.out.println("Server ID:"+pc.getIdentifier());

        // 设置返回给客户的服务器密码信息

        pc.setPassword("mima");

        pc.setIdentifier("cxf");

    }

}

然后还需要服务端启动类和和客户端启动类:

服务端启动类:

package com.server;

import java.util.HashMap;

import java.util.Map;

 

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;

import org.apache.ws.security.WSConstants;

import org.apache.ws.security.handler.WSHandlerConstants;

 

import com.mms.webservice.HelloWorldImpl;

import com.mms.webservice.test.ServerPasswordCallback;

public class Server {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

        Server server = new Server();

        //server.test();//没有安全验证WS

        server.testUsernameToken();//有安全验证WS

    }

   

    private void test() {

 

        JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();

//      server.getInInterceptors().add(new LoggingInInterceptor());

//      server.getOutInterceptors().add(new LoggingOutInterceptor());

        server.setServiceClass(HelloWorldImpl.class);

        server.setAddress("http://localhost:9000/security");

        server.create();

 

    }

 

    private WSS4JInInterceptor getInInterceptor() {

        Map<String, Object> inProps = new HashMap<String, Object>();

        inProps.put(WSHandlerConstants.ACTION,

                WSHandlerConstants.USERNAME_TOKEN);

        // 密码类型 : plain text

        inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);

        // 客户信息校验类设置

        inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,

                ServerPasswordCallback.class.getName());

 

        return new WSS4JInInterceptor(inProps);

    }

   

    private void testUsernameToken() {

        JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();

        //将回调拦截器加入server拦截器

        server.getInInterceptors().add(getInInterceptor());

        //server.getOutInterceptors().add(getOutInterceptor());

       

        server.setServiceClass(HelloWorldImpl.class);

        server.setAddress("http://localhost:9000/security");

        server.create();

    }

}

客户端启动类:

package com.client;

 

import java.util.HashMap;

import java.util.Map;

 

import org.apache.cxf.interceptor.LoggingInInterceptor;

import org.apache.cxf.interceptor.LoggingOutInterceptor;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;

import org.apache.ws.security.WSConstants;

import org.apache.ws.security.handler.WSHandlerConstants;

 

import com.mms.webservice.HelloWorld;

import com.mms.webservice.test.ClientPasswordCallback;

public class client {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        //打印日志

        factory.getOutInterceptors().add(new LoggingInInterceptor());

        factory.getInInterceptors().add(new LoggingOutInterceptor());

       

        factory.getOutInterceptors().add(getOutInterceptor());

        factory.setAddress("http://localhost:9000/security");

        factory.setServiceClass(HelloWorld.class);

       

       

        HelloWorld client = (HelloWorld)factory.create();

        System.out.println(client.sayHi("cxf"));

    }

   

    private static WSS4JOutInterceptor getOutInterceptor() {

        Map<String, Object> outProps = new HashMap<String, Object>();

        outProps.put(WSHandlerConstants.ACTION,

                WSHandlerConstants.USERNAME_TOKEN);

        // 服务器用户标识

        outProps.put(WSHandlerConstants.USER"IamServer");

        // 密码类型 : plain text

        outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);

        // 返回给客户端的密码信息

        outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,

                ClientPasswordCallback.class.getName());

        return new WSS4JOutInterceptor(outProps);

    }

}

原理:利用CXF自身的拦截器

参考文章:http://hi.baidu.com/leezuu/blog/item/e502c3ae3de7da044a36d675.html

6、 CXFJSON应用

下面例子展示如何在ServerFactoryBeans应用JSON,首先创建一个HashMap属性来设置StAXXMLInputFactoryXMLOutputFactory

Map<String,Object> properties = new HashMap<String,Object>();

 

// Create a mapping between the XML namespaces and the JSON prefixes.

// The JSON prefix can be "" to specify that you don't want any prefix.

HashMap<String, String> nstojns = new HashMap<String,String>();

nstojns.put("http://customer.acme.com", "acme");

 

MappedXMLInputFactory xif = new MappedXMLInputFactory(nstojns);

properties.put(XMLInputFactory.class.getName(), xif);

 

MappedXMLOutputFactory xof = new MappedXMLOutputFactory(nstojns);

properties.put(XMLOutputFactory.class.getName(), xof);

 

设置Context-Type属性:

// Tell CXF to use a different Content-Type for the JSON endpoint
// This should probably be application/json, but text/plain allows
// us to view easily in a web browser.
properties.put("Content-Type", "text/plain");

最后创建服务:

// Build up the server factory bean
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setServiceClass(CustomerService.class);
// Use the HTTP Binding which understands the Java Rest Annotations
sf.setBindingId(HttpBindingFactory.HTTP_BINDING_ID);
sf.setAddress("http://localhost:8080/json");
sf.setServiceBean(new CustomerServiceImpl());
 
sf.setProperties(properties);
 
sf.create();

原文来自Apache官网:http://cxf.apache.org/docs/json-support.html

7、 CXF之嵌入Jetty

这次只介绍服务端,嵌入Jetty不需要导入Jettyjar包,只需要导入CXF的包即可(CXF已把Jetty整合)。

首先的创建服务接口和服务实现类,这里不再重复,参照前面例子。

其次创建一个Jetty启动类,用来启动Jetty并且发布Web服务。

package com.server;

 

import javax.xml.ws.Endpoint;

 

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import org.eclipse.jetty.server.Connector;

import org.eclipse.jetty.server.nio.SelectChannelConnector;

 

import com.service.HelloWorldImpl;

 

 

public class JettyServer {

    public static void main(String[] args){

        new JettyServer();

    }

   

    private JettyServer(){

        System.out.println(System.getProperty("user.dir"));

        String app = System.getProperty("user.dir");//得到项目路径

       

        org.eclipse.jetty.server.Server server

            = new org.eclipse.jetty.server.Server();//新建一个Jetty服务器

        Connector conn = new SelectChannelConnector();//新建Connector组件

        conn.setHost("127.0.0.1");

        conn.setPort(9000);

        server.setConnectors(new Connector[]{conn});//插入服务器主件中

       

        org.eclipse.jetty.server.handler.ContextHandler context

            = new org.eclipse.jetty.server.handler.ContextHandler();//新建Handler组件

        context.setContextPath("/");//Web应用的上下文跟路径

        context.setResourceBase(app);

        server.setHandler(context);//插入服务器主件中

       

        org.eclipse.jetty.util.thread.QueuedThreadPool pool

            = new org.eclipse.jetty.util.thread.QueuedThreadPool();//创建线程池组件

        pool.setMaxThreads(100);//设置最大线程数

        pool.setMinThreads(10);//设置最小线程数

        server.setThreadPool(pool);

       

        //发布Web服务

        //Endpoint.publish("http://127.0.0.1:9000/WS-CXF-Jetty", new HelloWorldImpl());

        JaxWsServerFactoryBean wsServer = new JaxWsServerFactoryBean();

        wsServer.setAddress("http://127.0.0.1:9000/WS-CXF-Jetty");

        wsServer.setServiceBean(new HelloWorldImpl());

        wsServer.create();

       

        try {

            server.start();

            //System.out.println(server.isStarted());

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

参考文档:http://liuskysun.blog.163.com/blog/static/9981297820101023139723/

8、 关于wsdl2java自动生成客户端

利用wsdl2java生成的客户端,有个继承javax.xml.ws.Service的类,此方法的3个构造函数会报错(The constructor Service(URL, QName, WebServiceFeature[]) is undefined),原因是:jdk中有个javax.xml.ws.Service(低版本),而CXFgeronimo-jaxws_2.2_spec-1.0.jar中也有个javax.xml.ws.Service(高版本),而类里默认调用的是jdk(低版本)的Service,故报错!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值