本文主要就WebService中的利用注解配置开发,发布WebService服务,使用CXF开源框架发布服务,如何使用REST风格,以及WebService与Spring整合的使用进行详细的讲解与分析。
1、Jaxws常用注解
2、Cxf使用分析
3、Cxf与Spring整合开发
4、Rest风格
1、JaxWs常用注解
@WebService-定义服务
targetNamespace:指定命名空间
name:portType的名称
portName:port的名称
serviceName:服务名称
endpointInterface:SEI接口地址,如果一个服务类实现了多个接口,只需要发布一个接口的方法,可通过此注解指定要发布服务的接口。@WebMethod-定义方法(所注解的方法必须是公开方法)
operationName:方法名
exclude:设置为true表示此方法不是webservice方法,反之则表示webservice方法@WebResult-定义返回值(所注解位置在方法返回值名称处)
name:返回结果值的名称@WebParam-定义参数(所注解位置在方法属性名称处)
name:指定参数的名称无论是注释或者其他的修改,都必须要重新启动WebService服务才可以生效,否则当前的WebService服务均是以未修改之前的发布版本为准
代码片段如下:
*首先准备PO类*
import java.util.Date;
public class WeatherModel {
//天气概况
private String detail;
//日期
private Date data;
//最高温度
private int temperature_max;
//最低温度
private int temperature_min;
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public Date getData() {
return data;
}
public void setData(Date data) {
this.data = data;
}
public int getTemperature_max() {
return temperature_max;
}
public void setTemperature_max(int temperature_max) {
this.temperature_max = temperature_max;
}
public int getTemperature_min() {
return temperature_min;
}
public void setTemperature_min(int temperature_min) {
this.temperature_min = temperature_min;
}
@Override
public String toString() {
return "WeatherModel [detail=" + detail + ", data=" + data
+ ", temperature_max=" + temperature_max + ", temperature_min="
+ temperature_min + "]";
}
}
利用注解开发的接口类
import java.util.List;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import com.ws.po.WeatherModel;
@WebService(
targetNamespace="http://weather.ws.com/",//指定 wsdl的命名空间
name="WeatherInterface",//指定portType的名称
portName="WeatherInterfacePort",//指定port的名称
serviceName="WeatherService"//服务视图的名称
)
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface WeatherInterface {
public @WebResult(name="list") List<WeatherModel> queryWeather(@WebParam(name="cityName")String name);
}
2、Cxf使用分析
1)首先需要明确的一点是,什么是cxf:(摘自百科,详情可以在百科中查看)
Cxf是隶属于apache下的webservice的开源框架。
简单的说:Apache CXF = Celtix + Xfire,开始叫 Apache CeltiXfire,后来更名为 > Apache CXF 了,以下简称为 CXF。Apache CXF 是一个开源的 web Services 框架,CXF 帮助您构建和开发 web Services ,它支持多种协议,比如:SOAP1.1,1,2、XML/HTTP、RESTful HTTP 或者 CORBA。
CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构,早期语言使用的WS。C,c++,C#)
Cxf是基于SOA总线结构,依靠spring完成模块的集成,实现SOA方式。
Cxf可以部署在多种不同类型的服务器上面,比如:Tomcat,Jboss,Jetty(已经实现了内置),WebLogic。2)如何配置Cxf(本文暂时叙述的是Windows下的配置方法,Ubuntu等Linux的配置实际上大同小异,在/etc/profile中添加CXF_HOME路径并且进行配置即可)
Windows中配置方法:
配置环境:Win7,apache-cxf-2.4.2
CXF_HOME=CXF的目录
Path = %JAVA_HOME%\bin;%CXF_HOME%\bin;
CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar
配置成功后可以使用wsdl2java命令进行测试;
- 3)CXF开发步骤:
SEI开发:
PO类还是使用上文1)中的POWeatherModel类不变;
WeatherInterface.java
@WebService(
targetNamespace="http://weather.ws.com/",//指定 wsdl的命名空间
name="WeatherInterface",//指定portType的名称
portName="WeatherInterfacePort",//指定port的名称
serviceName="WeatherService"//服务视图的名称
)
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface WeatherInterface {
public @WebResult(name="list") List<WeatherModel> queryWeather(@WebParam(name="cityName")String name);
}
WeatherInterfaceImpl.java
public class WeatherInterfaceImpl implements WeatherInterface {
@Override
public List<WeatherModel> queryWeather(String name) {
//构造测试数据
List<WeatherModel> list = new ArrayList<WeatherModel>();
WeatherModel weatherModel_1 =new WeatherModel();
weatherModel_1.setDetail("晴");
weatherModel_1.setData(new Date());
weatherModel_1.setTemperature_max(30);
weatherModel_1.setTemperature_min(28);
WeatherModel weatherModel_2 =new WeatherModel();
weatherModel_2.setDetail("晴转多云");
weatherModel_2.setData(new Date());
weatherModel_2.setTemperature_max(24);
weatherModel_2.setTemperature_min(20);
list.add(weatherModel_1);
list.add(weatherModel_2);
return list;
}
}
WeatherService.java
public class WeatherService {
public static void main(String[] args) {
//使用Jaxws发布soap协议的webservice
JaxWsServerFactoryBean jaxWsServerFactoryBean = new JaxWsServerFactoryBean();
//指定webService的地址
jaxWsServerFactoryBean.setAddress("http://127.0.0.1:12345/weather");
//指定portType
jaxWsServerFactoryBean.setServiceClass(WeatherInterface.class);
//指定服务类对象
jaxWsServerFactoryBean.setServiceBean(new WeatherInterfaceImpl());
//发布服务
jaxWsServerFactoryBean.create();
}
}
运行WeatherService 发布服务
首先使用创建客户端工程,导入CXF的jar包,在使用wsdl2java生成客户端代码
wsdl2java -d . http://127.0.0.1:12345/weather?wsdl
WeatherClientCXF.java : 客户端使用CXF
public class WeatherClientCXF {
public static void main(String[] args) {
//利用JaxWsProxyFactoryBean调用webService的服务端
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
//调用地址
jaxWsProxyFactoryBean.setAddress("http://127.0.0.1:12345/weather?wsdl");
//获取service服务视图
jaxWsProxyFactoryBean.setServiceClass(WeatherInterface.class);
//获取portType
WeatherInterface weatherInterface = (WeatherInterface) jaxWsProxyFactoryBean.create();
//调用portType方法
List<WeatherModel> list = weatherInterface.queryWeather("");
for (WeatherModel weatherModel : list) {
System.out.println(weatherModel.getDetail());
System.out.println(weatherModel.getTemperatureMax());
System.out.println(weatherModel.getTemperatureMin());
System.out.println("==============================");
}
}
}
3、Cxf与Spring整合开发
- Cxf框架本身依赖spring,在Cxf的下载包中本身就带有了Spring的jar包,但是一定要注意在整合的时候,要先对自己的项目备份,并且查看自己当前项目中所以依赖的jar有哪些,如果有Spring包那用的是哪一个版本的Spring,是否要先删除,或者删除CXF中的Spring包,否则造成包的冲突出现的问题很不好解决。
- 在上面的项目中主要是使用JaxWsServerFactoryBean和JaxWsProxyFactoryBean,所以与Spring的结合点就在这个位置,利用Spring来生成类。
- 发布服务:使用spring和cxf整合的标签
<jaxws:server>
- 客户端调用服务:使用spring和cxf整合的标签
<jaxws:client>
<jaxws:server>
和<jaxws:client>
可以理解为spring容器中的bean,发布服务和客户端调用交给spring容器管理。
applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<!--
配置发布服务端
-->
<bean id="weatherInterface" class="com.ws.service.WeatherInterfaceImpl"></bean>
<!--
发布服务
和使用endpoint发布服务类似
WebService地址=tomcat地址+cxf+/weather
-->
<jaxws:server address="/weather" serviceClass="com.ws.service.WeatherInterface">
<jaxws:serviceBean>
<ref bean="weatherInterface" />
</jaxws:serviceBean>
</jaxws:server>
</beans>
web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringWebServiceServer</display-name>
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- cxf的Servlet -->
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置cxf的访问地址 -->
<!-- 本系统中webService必须以/ws/*开头 -->
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
在PO类,service接口以及Service的实现类均不变,与上文中的相同
Client客户端的开发
applicationContext.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<!-- 使用client标签调用服务端 -->
<jaxws:client id="weatherClient" address="http://localhost:8080/SpringWebServiceServer/ws/weather?wsdl" serviceClass="com.ws.weather.WeatherInterface">
</jaxws:client>
</beans>
使用wsdl2java命令生成相关的类之后,就可以进行客户端的测试了
ClientTest.java
public class ClientTest {
private ApplicationContext applicationContext;
@Before
public void before() {
applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void testClientByCxfAndSpring() {
//从Spring容器中取出portType方法
WeatherInterface weatherInterface = (WeatherInterface) applicationContext.getBean("weatherClient");
//调用portType方法
List<WeatherModel> list = weatherInterface.queryWeather("北京");
for (WeatherModel weatherModel : list) {
System.out.println(weatherModel);
System.out.println("=======================================");
}
}
}
4、Rest风格
REST 是一种软件架构模式,只是一种风格,rest服务采用HTTP 做传输协议,REST 对于HTTP 的利用分为以下两种:资源定位和资源操作。
更加准确去定位一个互联网资源。使用url定位一个互联网资源。
比如:查询一个学生信息url
资源定位要定位一个学生信息:
不使用 rest 的url:http://ip:port/queryUser.actionuserType=XXX&studentid=001&XXXX
使用 rest 的url:http://ip:port/user/student/001
使用 rest 方式表达url更加简单、可以准确表达这个url是一个学生信息查询url
代码实现
Student.java
package com.ws.rest.pojo;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="student")
public class Student {
private long id;
private String name;
private Date birthday;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", birthday="
+ birthday + "]";
}
}
StudentService.java
package com.ws.rest.service;
import java.util.List;
import javax.jws.WebService;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.ws.rest.pojo.Student;
@WebService
@Path("/student")
public interface StudentService {
//查询学生信息
@GET //http中的GET方法
@Path("/query/{id}") //id参数通过URL访问传递
@Produces(MediaType.APPLICATION_XML) //返回XML
public Student queryStudent(@PathParam("id")long id);
//查询学生列表
@GET //http中的GET方法
@Path("/querylist/{type}") //JSON格式
@Produces({MediaType.APPLICATION_JSON,"application/json;charset=utf-8"}) //返回JSON
//如果想让json返回xml需要在rest的url后边添加?_type=xml
public List<Student> queryStudentList(@PathParam("type")String type) throws Exception;
}
StudentServiceImpl.java
package com.ws.rest.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.ws.rest.pojo.Student;
public class StudentServiceImpl implements StudentService {
public Student queryStudent(long id) {
//使用静态数据
Student student = new Student();
student.setId(id);
student.setName("张三");
student.setBirthday(new Date());
return student;
}
public List<Student> queryStudentList(String type) throws Exception {
List<Student> list = new ArrayList<Student>();
Student student1 = new Student();
student1.setId(1L);
student1.setName("张三");
student1.setBirthday(new Date());
Student student2 = new Student();
student2.setId(2L);
student2.setName("王五");
student2.setBirthday(new Date());
list.add(student1);
list.add(student2);
return list;
}
}
StudentServer.java
package com.ws.rest.service;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
/** * 编程方式发布查询学生信息的服务 * @author YQ * */
public class StudentServer {
public static void main(String[] args) {
//使用jaxrsServerFactoryBean发布rest的服务
JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean();
//设置rest的服务地址
jaxrsServerFactoryBean.setAddress("http://127.0.0.1:12345/rest");
//设置服务对象
jaxrsServerFactoryBean.setServiceBean(new StudentServiceImpl());
//设置资源独享
jaxrsServerFactoryBean.setResourceClasses(StudentServiceImpl.class);
//发布rest服务
jaxrsServerFactoryBean.create();
}
}