WebService实例&调用本质&权限控制

转:http://blog.csdn.net/wang379275614/article/details/47749203

 

这里首先做一个用CXF开发WebService的实例。然后介绍WebService的调用本质与权限控制。


一、    实例


1.1        下载apache-cxf

  地址如下:http://cxf.apache.org/download.html,要下载稳定版。

  

  


1.2        使用CXF开发WebService服务端

  每个WebService组件需要2个部分,接口和实现类。开发一个WebService组件,一般需要三个步骤:

  Ø  开发一个WebService业务接口,该接口要用@WebService来修饰。

  Ø  开发一个WebService实现类,实现类也需要用@WebService来修饰。

  Ø  使用Endpoint类的静态方法来发布WebService。

  具体步骤如下:

  首先,新建JavaProject:01_WS_Server,即WebService的服务端,并导入需要的jar包:


  


  开发业务接口interface HelloWorld

  1. package com.tgb.cxf.ws.interfaces;  
  2.   
  3. import javax.jws.WebService;  
  4.   
  5. /** 
  6.  * 业务接口,要用@WebService来修饰 
  7.  *  
  8.  * @author wangzhipeng 
  9.  *  
  10.  */  
  11. @WebService  
  12. public interface HelloWorld {  
  13.     public void SayHi(String name);  
  14.   
  15. }  
package com.tgb.cxf.ws.interfaces;

import javax.jws.WebService;

/**
 * 业务接口,要用@WebService来修饰
 * 
 * @author wangzhipeng
 * 
 */
@WebService
public interface HelloWorld {
	public void SayHi(String name);

}

 

  开发业务实现class HelloWorldWs implements HelloWorld

  1. package com.tgb.cxf.ws;  
  2.   
  3. import javax.jws.WebService;  
  4.   
  5. import com.tgb.cxf.ws.interfaces.HelloWorld;  
  6.   
  7. /** 
  8.  * 业务实现,也要用@WebService来修饰 
  9.  *  
  10.  * @author wangzhipeng 
  11.  *  
  12.  */  
  13. @WebService(endpointInterface = "com.tgb.cxf.ws.interfaces.HelloWorld", serviceName = "HelloWorldWs")  
  14. public class HelloWorldWs implements HelloWorld {  
  15.   
  16.     @Override  
  17.     public void SayHi(String name) {  
  18.         System.out.println("hello " + name);  
  19.     }  
  20.   
  21. }  
package com.tgb.cxf.ws;

import javax.jws.WebService;

import com.tgb.cxf.ws.interfaces.HelloWorld;

/**
 * 业务实现,也要用@WebService来修饰
 * 
 * @author wangzhipeng
 * 
 */
@WebService(endpointInterface = "com.tgb.cxf.ws.interfaces.HelloWorld", serviceName = "HelloWorldWs")
public class HelloWorldWs implements HelloWorld {

	@Override
	public void SayHi(String name) {
		System.out.println("hello " + name);
	}

}

 

  使用Endpoint类的静态方法来发布WebService:

  1. package com.tgb.cxf.ws.publishes;  
  2.   
  3. import javax.xml.ws.Endpoint;  
  4.   
  5. import com.tgb.cxf.ws.HelloWorldWs;  
  6. import com.tgb.cxf.ws.interfaces.HelloWorld;  
  7.   
  8. /** 
  9.  *使用Endpoint类的静态方法来发布WebService 
  10.  *  
  11.  * @author wangzhipeng 
  12.  *  
  13.  */  
  14. public class ServerMain {  
  15.   
  16.     public static void main(String[] args) {  
  17.         HelloWorld helloWorld = new HelloWorldWs();  
  18.   
  19.         // 调用Endpoint的publish方法来发布Web Service  
  20.         Endpoint.publish("http://192.168.24.144/helloworld", helloWorld);  
  21.         System.out.println("Web service 发布成功!!");  
  22.     }  
  23. }  
package com.tgb.cxf.ws.publishes;

import javax.xml.ws.Endpoint;

import com.tgb.cxf.ws.HelloWorldWs;
import com.tgb.cxf.ws.interfaces.HelloWorld;

/**
 *使用Endpoint类的静态方法来发布WebService
 * 
 * @author wangzhipeng
 * 
 */
public class ServerMain {

	public static void main(String[] args) {
		HelloWorld helloWorld = new HelloWorldWs();

		// 调用Endpoint的publish方法来发布Web Service
		Endpoint.publish("http://192.168.24.144/helloworld", helloWorld);
		System.out.println("Web service 发布成功!!");
	}
}

 

  查看WebService是否发布成功(出现如下页面表示发布成功):


  


1.3        使用CXF开发WebService客户端

  开发WebService客户端一般需要如下几个步骤:

  首先我们新建JavaProject:01_WS_Client,作为WebService的客户端(新建WsClient类用来调用服务端):


  


  调用CXF提供的wsdl2java工具(如下图)根据wsdl文档(发布成功的地址),生成相应的java代码。wsdl,即web service definition language。任何语言实现了WebService,都需要提供并暴露WSDL文档。

  首先将Apache-cxf的bin目录加入到环境变量Path中,方便后面使用wsdl2java工具。


  


  然后打开cmd命令窗口,并进入到01_WS_Client项目的src目录下,如下图:


  


      然后,执行命令wsdl2java http://192.168.24.144/helloworld?wsdl(为我们发布的服务端的访问地址)


  


      这样,即可生成服务端代码到客户端项目中,刷新我们的客户端项目就可看到:


  


  然后,在我们上面新建的WsClient类中写如下代码即可调用WebService的服务端:

  1. package com.tgb.ws.client;  
  2.   
  3. import com.tgb.cxf.ws.HelloWorldWs;  
  4. import com.tgb.cxf.ws.interfaces.HelloWorld;  
  5.   
  6. public class WsClient {  
  7.   
  8.     public static void main(String[] args) {  
  9.   
  10.         // HelloWorldWs为生成的com.tgb.cxf.ws包下的继承了Service的类  
  11.         HelloWorldWs factory = new HelloWorldWs();  
  12.   
  13.         // 此处返回的只是远程WebService的【代理】  
  14.         HelloWorld helloWorld = factory.getHelloWorldWsPort();  
  15.   
  16.         helloWorld.sayHi("wangzhipeng");// 输出:hello wangzhipeng,表示调用WebService成功  
  17.     }  
  18.   
  19. }  
package com.tgb.ws.client;

import com.tgb.cxf.ws.HelloWorldWs;
import com.tgb.cxf.ws.interfaces.HelloWorld;

public class WsClient {

	public static void main(String[] args) {

		// HelloWorldWs为生成的com.tgb.cxf.ws包下的继承了Service的类
		HelloWorldWs factory = new HelloWorldWs();

		// 此处返回的只是远程WebService的【代理】
		HelloWorld helloWorld = factory.getHelloWorldWsPort();

		helloWorld.sayHi("wangzhipeng");// 输出:hello wangzhipeng,表示调用WebService成功
	}

}

 

      这里我们需要找到 wsdl2java所生成的服务端类中,一个继承了Service的类,该类可当做工厂来使用,利用该类的getXXXPort方法可以返回WebService的代理。实例就到此结束。


二、    调用WebService的本质原理


       一次WebService调用其实并不是方法调用,而是发送SOAP消息,即xml文档片段。调用详细过程如下:

       1、客户端将调用方法、参数,转换生成xml文档片段(SOAP消息,input消息),该文档片段必须符合wsdl定义的格式。

       2、客户端通过网络将生成的xml文档片段传给服务器。

  3、服务器接受到客户端发来的xml文档片段。

  4、服务器解析xml文档片段,提取其中的数据,并将数据转换为调用WebService所需要的参数值。

  5、服务器执行方法。

  6、服务器将方法的执行结果再次转换为xml文档片段(SOAP消息,output消息),该文档片段必须符合wsdl定义的格式。

  7、服务端通过网络将执行结果的xml文档片段通过网络发送给客户端。

  8、客户端接收到执行结果的xml文档片段。

  9、客户端解析执行结果的xml文档片段,提取其中的数据,并将数据转换为调用WebService的返回值。

  从上面的调用本质上来看,方法的执行是在服务端,客户端只做发送xml、接收xml、解析xml。所以,一种语言支持WebService唯一的要求就是:该语言支持xml文档的解析、生成、网络传输。为什么WebService离不开xml呢?WebService的三个基础如下:

  1、WSDL:Web Service Definition Language——WebService定义语言

  2、SOAP:Simple Object Access Protocol——简单对象访问协议

  3、UDDI:Universal Description Discovery and Integration——通用描述、发现与集成服务,是一种目录服务

  其中的WSDL与SOAP都为xml,所以WebService离不开xml。


三、    CXF类型问题


       发布的WebService的方法,当形参、返回值类型是String、基本数据类型时,CXF肯定可以轻松地处理,例如:public void SayHi(String name);

  当形参、返回值类型是JavaBean式的复合类、List集合、数组等时,CXF也可以很好的处理,例如:public List<Cat> queryCatsByUser(User user);

  还有一些像Map、非JavaBean式的复合类,CXF是处理不了的,例如:public Map<String, Cat> getAllCats();此时会报异常:javax.xml.ws.WebServiceException:org.apache.cxf.service.factory.ServiceConstructionException。

       对于处理不了的类型,例如:Map<String, Cat>就需要我们手动写工具类将它转换为CXF可以处理的类型,例如我们可以将它转换为如下类型:

  1. package com.tgb.cxf.ws.utils;  
  2.   
  3. import java.util.List;  
  4.   
  5. import com.tgb.cxf.domain.Cat;  
  6. /** 
  7.  * 将cxf不能处理的类型Map<String, Cat>转换为如下cxf可以处理的类型StringCat 
  8.  * @author wangzhipeng 
  9.  * 
  10.  */  
  11. public class StringCat {  
  12.   
  13.     public static class Entry {  
  14.         private String key;  
  15.         private Cat value;  
  16.   
  17.         public Entry() {  
  18.         };  
  19.   
  20.         public Entry(String key, Cat cat) {  
  21.             this.key = key;  
  22.             this.value = cat;  
  23.         }  
  24.   
  25.         public String getKey() {  
  26.             return key;  
  27.         }  
  28.   
  29.         public void setKey(String key) {  
  30.             this.key = key;  
  31.         }  
  32.   
  33.         public Cat getValue() {  
  34.             return value;  
  35.         }  
  36.   
  37.         public void setValue(Cat value) {  
  38.             this.value = value;  
  39.         }  
  40.   
  41.     }  
  42.   
  43.     private List<Entry> entries;  
  44.   
  45.     public List<Entry> getEntries() {  
  46.         return entries;  
  47.     }  
  48.   
  49.     public void setEntries(List<Entry> entries) {  
  50.         this.entries = entries;  
  51.     }  
  52.   
  53. }  
package com.tgb.cxf.ws.utils;

import java.util.List;

import com.tgb.cxf.domain.Cat;
/**
 * 将cxf不能处理的类型Map<String, Cat>转换为如下cxf可以处理的类型StringCat
 * @author wangzhipeng
 *
 */
public class StringCat {

	public static class Entry {
		private String key;
		private Cat value;

		public Entry() {
		};

		public Entry(String key, Cat cat) {
			this.key = key;
			this.value = cat;
		}

		public String getKey() {
			return key;
		}

		public void setKey(String key) {
			this.key = key;
		}

		public Cat getValue() {
			return value;
		}

		public void setValue(Cat value) {
			this.value = value;
		}

	}

	private List<Entry> entries;

	public List<Entry> getEntries() {
		return entries;
	}

	public void setEntries(List<Entry> entries) {
		this.entries = entries;
	}

}

 

  转换类如下:

  1. package com.tgb.cxf.ws.utils;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. import javax.xml.bind.annotation.adapters.XmlAdapter;  
  8.   
  9. import com.tgb.cxf.domain.Cat;  
  10. import com.tgb.cxf.ws.utils.StringCat.Entry;  
  11.   
  12. /** 
  13.  * CXF类型转换类Map<String, Cat>——StringCat 
  14.  *  
  15.  * @author wangzhipeng 
  16.  *  
  17.  */  
  18. public class FkXmlAdapter extends XmlAdapter<StringCat, Map<String, Cat>> {  
  19.   
  20.     @Override  
  21.     public StringCat marshal(Map<String, Cat> v) throws Exception {  
  22.         StringCat tStringCat = new StringCat();  
  23.         for (String key : v.keySet()) {  
  24.             tStringCat.getEntries().add(new Entry(key, v.get(key)));  
  25.         }  
  26.   
  27.         return tStringCat;  
  28.     }  
  29.   
  30.     @Override  
  31.     public Map<String, Cat> unmarshal(StringCat v) throws Exception {  
  32.         Map<String, Cat> catMap = new HashMap<String, Cat>();  
  33.   
  34.         List<Entry> entryLists = v.getEntries();//    
  35.         for (Entry entry : entryLists) {  
  36.             catMap.put(entry.getKey(), entry.getValue());  
  37.         }  
  38.   
  39.         return catMap;  
  40.     }  
  41.   
  42. }  
package com.tgb.cxf.ws.utils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.adapters.XmlAdapter;

import com.tgb.cxf.domain.Cat;
import com.tgb.cxf.ws.utils.StringCat.Entry;

/**
 * CXF类型转换类Map<String, Cat>——StringCat
 * 
 * @author wangzhipeng
 * 
 */
public class FkXmlAdapter extends XmlAdapter<StringCat, Map<String, Cat>> {

	@Override
	public StringCat marshal(Map<String, Cat> v) throws Exception {
		StringCat tStringCat = new StringCat();
		for (String key : v.keySet()) {
			tStringCat.getEntries().add(new Entry(key, v.get(key)));
		}

		return tStringCat;
	}

	@Override
	public Map<String, Cat> unmarshal(StringCat v) throws Exception {
		Map<String, Cat> catMap = new HashMap<String, Cat>();

		List<Entry> entryLists = v.getEntries();//  
		for (Entry entry : entryLists) {
			catMap.put(entry.getKey(), entry.getValue());
		}

		return catMap;
	}

}


 

  然后需要我们在WebService的接口的相应的方法上加@XmlJavaTypeAdapter(转换类.class),其它保持不变即可:


  

  1. package com.tgb.cxf.ws.interfaces;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import javax.jws.WebService;  
  7. import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;  
  8.   
  9. import com.tgb.cxf.domain.Cat;  
  10. import com.tgb.cxf.domain.User;  
  11. import com.tgb.cxf.ws.utils.FkXmlAdapter;  
  12.   
  13. @WebService  
  14. public interface HelloWorld {  
  15.     public void SayHi(String name);  
  16.   
  17.     public List<Cat> queryCatsByUser(User user);  
  18.   
  19.     // CXF不能处理Map<String,Cat>类型,于是我们采用FkXmlAdapter进行处理  
  20.     public @XmlJavaTypeAdapter(FkXmlAdapter.class)  
  21.     Map<String, Cat> getAllCats();  
  22. }  
package com.tgb.cxf.ws.interfaces;

import java.util.List;
import java.util.Map;

import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import com.tgb.cxf.domain.Cat;
import com.tgb.cxf.domain.User;
import com.tgb.cxf.ws.utils.FkXmlAdapter;

@WebService
public interface HelloWorld {
	public void SayHi(String name);

	public List<Cat> queryCatsByUser(User user);

	// CXF不能处理Map<String,Cat>类型,于是我们采用FkXmlAdapter进行处理
	public @XmlJavaTypeAdapter(FkXmlAdapter.class)
	Map<String, Cat> getAllCats();
}


 


四、    权限控制


       上面发布的WebService服务,只要我们拿到访问地址就都可以随意调用,这样显然是不合适的。所以我们还需要进行权限验证。WebService权限控制的思路可以如下:

       服务端要求input消息总是携带有用户名、密码信息,如果没有携带该信息,或携带信息不正确,那么直接拒绝调用。我们可以用CXF提供的拦截器来实现此效果。就是为了程序员能够访问、并修改CXF框架所生成的SOAP消息,CXF才提供了拦截器。我们可以在客户端添加out拦截器,截获SOAP消息,并添加上用户名、密码信息,然后再发给服务端;于是我们在服务端添加in拦截器,来截获SOAP消息,进而验证用户名、密码信息;


  

  


 

       拦截结构如下图:


  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值