WebService中注解开发,CXF,Spring整合,Rest风格

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yangqian201175/article/details/51302587

本文主要就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);
}

对于实现类和server的启动类,不再贴出;当我们发布了当前的服务之后,就可以从wsdl的说明文档中看见改变如下:
利用注解后文档关键位置更加清晰易读


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();
    }

}

猜你喜欢

转载自blog.csdn.net/yangqian201175/article/details/51302587