首页 > 程序开发 > 软件开发 > Java >

框架 day64 WebService(注解),CXF框架(jax-ws,Jax-rs,与spring整合)

2016-06-27

WebService第二天 1 webservice的注解 1 1 案例: 模拟查询天气信息,返回三天的天气情况。 1 1 1 实现步骤 服务端: 第一步:创建一个天气信息pojo,包含天气的信息、最高、最低温度、日期。 第二步:编

WebService第二天

1 webservice的注解

1.1 案例:

模拟查询天气信息,返回三天的天气情况。

1.1.1 实现步骤

服务端:

第一步:创建一个天气信息pojo,包含天气的信息、最高、最低温度、日期。

第二步:编写SEI

第三步:编写SEI实现类,返回天气list

第四步:发布Webservice。

1.1.2 代码实现

1.1.2.1 Pojo

public class WeatherModel {

	private String info;
	private int maxTemp;
	private int minTemp;
	private Date date;

1.1.2.2 SEI

天气查询SEI,返回三天的天气情况

@WebService
public interface WeatherInterface {

	List queryWeather(String cityName);
}


1.1.2.3 SEI实现类

实现类使用@WebService实现wsdl文档元素名称的修改

@WebService(
		//endpointInterface="com.itheima.weather.service.WeatherInterface" //可以指定SEI接口
		name="WeatherInterface", //不使用SEI接口时规范portType的名称
		serviceName="WeatherService",	//服务视图的名称
		portName="WeatherPort",			//Service节点中port节点的name属性
		targetNamespace="http://weather.itheima.com/"	//wsdl的命名空间
)
public class WeatherInterfaceImpl implements WeatherInterface {

	@Override
	@WebMethod/*(exclude=true)*/
	@WebResult(name="WeatherInfo")
	public List queryWeather(@WebParam(name="cityName")String cityName) {
		System.out.println("客户端发送的城市:" + cityName);
		//查询天气信息
		List info = getWeatherInfo(cityName);
		//返回天气信息
		return info;
	}
	
	private List getWeatherInfo(String cityName) {
		List weatherList = new ArrayList<>();
		Calendar calendar = Calendar.getInstance();
		//第一天
		WeatherModel model1 = new WeatherModel();
		model1.setInfo("雷阵雨");
		model1.setMaxTemp(31);
		model1.setMinTemp(22);
		model1.setDate(calendar.getTime());
		weatherList.add(model1);
		//第二天
		WeatherModel model2 = new WeatherModel();
		model2.setInfo("多云");
		model2.setMaxTemp(33);
		model2.setMinTemp(25);
		calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 1);
		model2.setDate(calendar.getTime());
		weatherList.add(model2);
		//第三天
		WeatherModel model3 = new WeatherModel();
		model3.setInfo("多云");
		model3.setMaxTemp(35);
		model3.setMinTemp(25);
		calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 1);
		model3.setDate(calendar.getTime());
		weatherList.add(model3);
		
		return weatherList;
	}

}


1.1.2.4 客户端

public class WeatherClient {

	public static void main(String[] args) throws Exception {
		//创建服务视图
		Service service = Service.create(new URL("http://127.0.0.1:12345/weather"), 
				new QName("http://service.weather.itheima.com/", "WeatherInterfaceImplService"));
		//从服务视图获得protType对象
		WeatherInterfaceImpl weatherInterfaceImpl = service.getPort(WeatherInterfaceImpl.class);
		//调用服务端方法
		List list = weatherInterfaceImpl.queryWeather("北京");
		//显示天气信息
		for (WeatherModel weatherModel : list) {
			System.out.println(weatherModel.getDate().toGregorianCalendar().getTime().toLocaleString());
			System.out.println(weatherModel.getInfo());
			System.out.println(weatherModel.getMaxTemp());
			System.out.println(weatherModel.getMinTemp());
			
		}
	}
}


1.2 要规范wsdl需要使用到webservice注解

1.2.1 @Webservice

@WebService(

//endpointInterface="com.itheima.weather.service.WeatherInterface"//可以指定SEI接口

name="WeatherInterface",//不使用SEI接口时规范portType的名称

serviceName="WeatherService", //服务视图的名称

portName="WeatherPort", //Service节点中port节点的name属性

targetNamespace="http://weather.itheima.com/" //wsdl的命名空间

)

1.2.2 @WebMethod

如果不指定@WebMethod注解默认是吧实现类中所有的public方法都发布成服务方法。

如果类中有的public方法不想发布成服务,就可以使用@WebMethod(exclude=true)把此方法排除,也就是不发布为webservice方法。

注意:每个Porttype中,必须有一个public方法并且不能标注为@WebMethod(exclude=true)

1.2.3 @WebParam、@WebResult

可以规范参数的名称

@WebResult(name="xxxx")修改返回值的元素的父标签名字

@WebParam(name="xxxxx")修改传入参数的元素的父标签名字

2 CXF框架

2.1 什么是CXF

Apache CXF = Celtix + Xfire,开始叫 Apache CeltiXfire,后来更名为 Apache CXF 了,以下简称为 CXF。Apache CXF

是一个开源的 web Services 框架,CXF 帮助您构建和开发 web Services ,它支持多种协议,比如:SOAP1.1,1,2、XML/HTTP、RESTful 或者 CORBA。

RESTful:一种风格而不是一个协议。它理念是网络上的所有事物都被抽象为资源,每个资源对应一个唯一的资源标识符。

CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构,早期语言使用的WS。C,c++,C#)

Cxf是基于SOA总线结构,依靠spring完成模块的集成,实现SOA方式。

灵活的部署:可以运行在Tomcat,Jboss,Jetty(内置),weblogic上面。

2.2 CXF的安装及配置

从官网下载:cxf.apache.org

学习使用的版本是:3.0.2

使用的方法,直接把cxf的jar包添加到工程中就可以了。

环境配置

JAVA_HOME需要jdk的支持

CXF_HOME解压目录(bin的上层目录) 需要使用bin目录的可执行命令生成客户端代码

\

path = %JAVA_HOME%\bin;%CXF_HOME%\bin;

2.3 使用CXF实现java-ws规范的webservice

Soap1.1:

2.3.1 服务端

实现步骤:

第一步:创建一java工程。

第二步:导入jar包导入cxf的jar包共138个。

第三步:编写SEI,在SEI上添加@Webservice注解。

第三步:编写SEI实现类。需要实现SEI接口,可以不加@Webservice注解

第四步:发布服务。

1、创建一个JaxWsServerFactoryBean对象。

2、设置服务的发布地址,是一个http url

3、设置SEI接口

4、设置SEI实现类对象

5、调用create方法发布服务。

2.3.2 代码实现

2.3.2.1 SEI

@WebService
public interface WeatherInterface {

	String queryWeather(String cityName);
}


2.3.2.2 实现类

public class WeatherInterfaceImpl implements WeatherInterface {

	@Override
	public String queryWeather(String cityName) {
		
		System.out.println("城市名称:" + cityName);
		String result = "多云";
		
		return result;
	}
}


2.3.3 发布服务

服务发布类:后面整合spring按照此步骤配置即可

public class WeatherServer {

	public static void main(String[] args) {
		//创建一个JaxWsServerFactoryBean对象
		JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
		//设置服务发布的地址
		factoryBean.setAddress("http://127.0.0.1:12345/weather");
		//设置SEI
		factoryBean.setServiceClass(WeatherInterface.class);
		//设置实现类对象
		factoryBean.setServiceBean(new WeatherInterfaceImpl());
		//发布服务
		factoryBean.create();
	}
}


2.4 客户端

2.4.1 Wsdl2java

可以使用wsimport生成客户端调用代码,也可以使用CXF自带的工具生成。Wsdl2java。

可以实现wsimport同样的功能,两个工具生成的代码都是一样,wsdl2java工具的版本高。Wsimport对soap1.2支持的不好。

它包含以下参数:

a)-d参数,指定代码生成的目录。

b) -p参数,指定生成的新的包结构。

例:

在命令行执行

wsdl2java &ndash;d .-p cn.test.cxftexthttp://127.0.0.1:6666/helloworld?wsdl

2.4.2 客户端的代码实现

2.4.2.1 实现步骤

1、可以直接使用生成的代码调用服务端方法。

2、使用CXF提供的工厂类调用。

第一步:创建JaxWsProxyFactoryBean对象

第二步:设置服务的url,服务端地址

第三步:设置SEI(portType)类型

第四步:调用Create方法获得portType对象。

第五步:调用服务端方法。

2.4.2.2 代码实现

使用CXF工厂调用webservice,后面与spring整合配置可以用来参考

public class WeatherClient {

	public static void main(String[] args) {
		//创建一个JaxWsProxyFactoryBean对象
		JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
		//设置服务的url
		factoryBean.setAddress("http://127.0.0.1:12345/weather?wsdl");
		//设置SEI的类型
		factoryBean.setServiceClass(WeatherInterface.class);
		//获得porttype对象
		WeatherInterface portType = (WeatherInterface) factoryBean.create();
		//调用服务端方法
		String result = portType.queryWeather("北京");
		System.out.println(result);
	}
}


2.5 Jax-rs规范的webservice

2.5.1 什么是rest服务

一句话解释:URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

简单来讲,就是可以用httprequest 调用某个function. 比如在浏览器里输入www.chx.site/api/guesswhoisawesome,就会调用后台的某个function得到一个response(可以是Json).

REST 是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。

它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

rest服务采用HTTP 做传输协议,REST 对于HTTP 的利用分为以下两种:资源定位资源操作

关于JAX-WS与JAX-RS:

两者是不同风格的SOA(面向服务的体系结构)架构。

前者以动词为中心,指定的是每次执行函数。

而后者以名词为中心,每次执行的时候指的是资源。

&#61548; 资源定位

Rest要求对资源定位更加准确,如下:

非rest方式:http://ip:port/queryUser.action?userType=student&id=001

Rest方式:http://ip:port/user/student/001

Rest方式表示互联网上的资源更加准确,但是也有缺点,可能目录的层级较多不容易理解。

&#61548; 资源操作

利用HTTP 的GET、POST、PUT、DELETE 四种操作来表示数据库操作的SELECT、UPDATE、INSERT、DELETE 操作。

比如:

查询学生方法:

设置Http的请求方法为GET,url如下:

http://ip:port/user/student/001

添加学生方法:

设置http的请求方法为PUT,url如下:

http://ip:port/user/student/001/张三/......

Rest常用于资源定位,资源操作方式较少使用。

REST 是一种软件架构理念,现在被移植到Web 服务上,那么在开发Web 服务上,

偏于面向资源的服务适用于REST,REST 简单易用,效率高,

SOAP 成熟度较高,安全性较好。

注意:REST 不是WebService,JAX-RS 只是将REST 设计风格应用到Web 服务开发上。

代码实现

2.5.2 服务端

2.5.2.1 实现步骤

第一步:创建一个pojo,返回值的类型。需要在pojo上添加@XmlRootElement。

第二步:创建一个SEI。也就是一个接口。需要用到的注解

1、@Path:标注请求url

2、@GET、@POST、@PUT、@DELETE:标注操作的方法

3、@Produce:指定返回结果的数据类型,xml或者json等。

第三步:创建SEI的实现类。可以不使用任何注解。

第四步:发布rest服务。

1、使用JAXRsServerFactoryBean对象发服务。

2、设置服务发布的地址。设置url

3、设置SEI实现类对象。

4、发布服务,create方法。

2.5.2.2 代码实现

2.5.2.2.1 Pojo

返回值pojo类需要添加一个@XmlRootElement注解

@XmlRootElement
public class WeatherModel {

	private String info;
	private int maxTemp;
	private int minTemp;
	private Date date;

2.5.2.2.2 SEI

rest服务SEI

//窄化请求映射
@Path("/weather")
public interface WeatherInterface {
	//方法的请求路径{}中的内容就是参数,需要对应的使用@PathParam注解取参数
	@Path("/city/{cityName}")
	//请求的方法
	@GET
	//返回结果的数据类型,可以是xml也可以是json
	@Produces({MediaType.APPLICATION_JSON+";charset=utf-8", MediaType.APPLICATION_XML})
	List queryWeather(@PathParam(value="cityName")String cityName);
}

2.5.2.2.3 SEI实现类

public class WeatherInterfaceImpl implements WeatherInterface{

	@Override
	public List queryWeather(String cityName) {
		
		List weatherInfo = getWeatherInfo(cityName);
		
		return weatherInfo;
	}
...


2.5.2.2.4 发布服务

使用执行命令生成相应的代码后

public class WeatherServer {

	public static void main(String[] args) {
		//创建一个JAXRSServerFactoryBean对象
		JAXRSServerFactoryBean factoryBean = new JAXRSServerFactoryBean();
		//设置服务发布的地址
		factoryBean.setAddress("http://127.0.0.1:12345/rest");
		//设置实现类对象
		factoryBean.setServiceBean(new WeatherInterfaceImpl());
		//发布服务
		factoryBean.create();		
	}
}


2.5.3 查看结果

http://127.0.0.1:12345/rest/weather/city/上海

\

2.5.4 如果是多个参数可以使用

\

2.5.5 结果数据格式

2.5.5.1 Json

@Produces({MediaType.APPLICATION_JSON+";charset=utf-8", MediaType.APPLICATION_XML})

其中charset=utf-8 为了防止出现乱码

2.5.6 同一个方法返回两种数据类型

支持xml或者json数据格式

MediaType.APPLICATION_JSON

MediaType.APPLICATION_XML

默认返回xml格式的数据

如果想访问json格式的数据需要加参数:?_type=json

http://127.0.0.1:12345/rest/weather/city/%E4%B8%8A%E6%B5%B7?_type=json

2.5.7 客户端

可以使用ajax请求json数据。还可以使用HttpClient访问数据。需要自己转换成java对象。

3 CXF整合spring

3.1 整合的思路

Spring就是一个容器,服务端让spring容器实现服务的发布。客户端使用spring容器完成获得porttype的过程,直接从spring容器中获得一个porttype对象。

3.2 案例需求

服务端发布手机号查询服务供客户端调用,服务端配置调用公网手机号查询服务客户端,调用公网WebService查询手机号。

3.3 分析

\

3.4 实现步骤

服务端:有两个身份,一个是调用公网webservice的客户端。一个是对外提供手机号查询服务的服务端。

第一步:实现调用公网webservice的客户端

1、根据公网webservice的wsdl生成客户端调用代码

2、配置spring容器,完成创建服务视图获得porttype的过程。直接从spring容器中获得prottype对象。

3、直接调用porttype对象的服务端方法,查询手机号。

第二步:对外发布服务,实现手机号查询。

1、编写一个SEI接口。需要在SEI上添加@Webservice注解。

2、编写一个SEI实现类,调用公网webservice的porttype实现手机号查询。

3、发布服务,使用spring容器完成。

3.5 开发环境的搭建

第一步:创建一个Web工程

第二步:导入jar包。需要spring的jar包和cxf的jar包

3.6 代码实现

3.6.1 服务端

3.6.1.1 生成调用公网webservice的客户端调用代码

3.6.1.2 在spring容器中配置porttype

applicationContext.xml



	
	
	
	
	
		
	

NoClassDefFoundError: org/apache/cxf/logging/FaultListener
解决方法:添加FaultListener。
	
        
            
            	            
                
            
        
    

需要的xmlns和xsd
xmlns:cxf="http://cxf.apache.org/core
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd


3.6.1.3 SEI

调用公网webservice查询手机号的SEI

@WebService
public interface MobileInterface {

	Mobile queryMobile(String code);
	
}


3.6.1.4 SEI实现类

手机号归属地查询服务

public class MobileInterfaceImpl implements MobileInterface {

	//公网webservice的porttype配置注入
	private MobileCodeWSSoap mobileCodeWSSoap;	
	public void setMobileCodeWSSoap(MobileCodeWSSoap mobileCodeWSSoap) {
		this.mobileCodeWSSoap = mobileCodeWSSoap;
	}

	@Override
	public Mobile queryMobile(String code) {
		//第一个参数:手机号
		//第二个参数:免费用户是空串
		String info = mobileCodeWSSoap.getMobileCodeInfo(code, "");
		Mobile mobile = new Mobile();
		mobile.setAddress(info);
		mobile.setCode(code);
		return mobile;
	}
}


3.6.1.5 发布服务

3.6.1.6 Web.xml

配置spring容器,配置cxf使用servlet。

web.xml



	B06_spring_cxf

	
	
	
		contextConfigLocation
		classpath:applicationContext.xml
	
	
		org.springframework.web.context.ContextLoaderListener
	
	
	
	
	
	
		cxf
		org.apache.cxf.transport.servlet.CXFServlet
		
		1
	
	
		cxf
		/ws/*
	

applicationContext.xml发布自己的服务



	
	
	
	
	
		
	
	
	
	
	
		
			
		
	
	
	
	
		
	
	
	
		
			
		
	
				          


3.6.1.7 访问路径

http://localhost:8081/B06_spring_cxf/ws/mobile?wsdl

\

3.6.2 客户端

步骤:

1、生成客户端调用代码

2、创建服务视图

3、获得porttype

4、调用服务端方法

3.7 Spring整合cxf发布rest服务

3.7.1 实现步骤

第一步:调用公网webservice查询手机号,需要公网webservice的porttype。

第二步:发布rest服务

1、先写一个pojo,需要加上@xmlrootElement注解。

2、编写一个SEI,需要添加@path、@GET、@Produces

3、编写一个SEI实现类,需要调用公网的webservice查询手机号。

4、发布服务,使用spring容器发布服务。

3.7.2 代码实现

3.7.2.1 SEI

rest风格的服务

@Path("/mobile")
public interface MobileRest {

	@Path("/code/{code}")
	@GET
	@Produces({MediaType.APPLICATION_JSON+";charset=utf-8", MediaType.APPLICATION_XML})
	Mobile queryMobile(@PathParam(value = "code")String code);
}


3.7.2.2 SEI实现类

public class MobileRestImpl implements MobileRest {
	
	//公网webservice的porttype
	private MobileCodeWSSoap mobileCodeWSSoap;
	
	public void setMobileCodeWSSoap(MobileCodeWSSoap mobileCodeWSSoap) {
		this.mobileCodeWSSoap = mobileCodeWSSoap;
	} 

	@Override
	public Mobile queryMobile(String code) {
		String address = mobileCodeWSSoap.getMobileCodeInfo(code, "");
		Mobile mobile = new Mobile();
		mobile.setAddress(address);
		mobile.setCode(code);
		
		return mobile;
	}

}


3.7.2.3 发布服务

	
	
		
	
	
	
		
			
		
	


3.7.2.4 Url的构成

\

使用jquery调用cxf(ws)

$(function(){
		$("#mybutton").click(function(){
			var data = &#39;&#39;
				  +&#39;&#39;
				  +&#39;&#39;
				  +&#39;   sss&#39;
				  +&#39; &#39;
				  +&#39;&#39;
				  +&#39;&#39;;
				  
				$.ajax({
					url:&#39;http://localhost:8080/cxf-web-server/services/hello&#39;,
					type:&#39;post&#39;,
					dataType:&#39;xml&#39;,
					contentType:&#39;text/xml;charset=UTF-8&#39;,
					data:data,
					success:function(responseText){
						alert($(responseText).find(&#39;return&#39;).text());
					},
					error:function(){
						alert("error");
					}
				})
		})
	})

相关文章
最新文章
热点推荐