Webservice笔记(二)

1. Jaxws常用注解
  如果不使用注解,默认namespace是服务类包名倒序;默认portType是服务类的类名。注解的作用:jaxws提供的注解可以对webservice的接口规范化。
  1.1 @webservice注解
  @WebService定义服务,在服务实现类上。

targetNamespace: 指定命名空间
name: portType的名称
portName: port的名称
serviceName: 服务名称
endpointInterface: SEI接口地址,如果一个服务类实现了多个接口,只需要发布一个接口的方法,可通过此注解指定要发布服务的接口。

  1.2 @WebMethod 定义方法,在公开方法上面

operationName: 方法名
exclude: 设置为true表示此方法不是webservice方法,反之则表示webservice方法。

  1.3 @WebResult 定义返回值,在方法返回值前面

name:返回结果值的名称

  1.4 @WebParam定义参数,在方法参数前面

name:指定参数的名称

  备注:如果修改webservice的接口内容,比如namespace、portType,必须要重新生成客户端调用代码。
2. CXF入门
  2.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方式。灵活的部署:可以运行有Tomcat,Jboss,Jetty(内置),weblogic上面。
  2.2 环境配置
  从官网下载下载cxf2.7.11版本。
Webservice笔记(二)_第1张图片
环境变量的配置:
CXF_HOME=cxf的目录
Path = %JAVA_HOME%\bin;%CXF_HOME%\bin;
CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar

  2.3 Cxf第一个程序
   2.3.1 服务端
    1. 开发SEI及SEI实现类

//Model类字段内容如下:
public class WeatherModel {
    private String detail;
    private Date date;
    private Integer tempratureMax;
    private Integer tempratureMin;
}

package cn.keymobile.server;

import java.util.List;
import javax.jws.WebService;
import cn.keymobile.pojo.WeatherModel;

/**
 * cxf第一个程序,SEI接口
 * cxf开发SEI接口,需要将@WebService注解加在SEI接口上
 * @author zhaojd
 */

/**
 * 注解的作用:jaxws提供的注解可以对webservice的接口规范化。
 * targetNamespace:指定wsdl命名空间
 * name:指定portType名称
 * portName:指定port的名称
 * serviceName:服务视图的名称
 */
@WebService(
    targetNamespace="http://server.keymobile.cn/",
    name="WeatherInterface",
    portName="WeatherInterfacePortName",
    serviceName="WeatherInterfaceServiceName"
        )
public interface WeatherInterface {

    //查询三天的天气
    List queryWeather(String cityName);
}
package cn.keymobile.server;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import cn.keymobile.pojo.WeatherModel;

public class WeatherInterfaceImpl implements WeatherInterface {

    @Override
    public List queryWeather(String cityName) {
      //构造三天天气
        List list = new ArrayList();

        Calendar calendar = Calendar.getInstance();
        int day = calendar.get(Calendar.DATE);

        WeatherModel weatherModel_1  =new WeatherModel();
        weatherModel_1.setDetail("晴");
        weatherModel_1.setDate(new Date());
        weatherModel_1.setTempratureMax(20);
        weatherModel_1.setTempratureMin(15);

        WeatherModel weatherModel_2  =new WeatherModel();
        weatherModel_2.setDetail("阴");
        calendar.set(Calendar.DATE, day+1);
        weatherModel_2.setDate(calendar.getTime());
        weatherModel_2.setTempratureMax(15);
        weatherModel_2.setTempratureMin(10);

        WeatherModel weatherModel_3  =new WeatherModel();
        weatherModel_3.setDetail("晴");
        calendar.set(Calendar.DATE, day+2);
        weatherModel_3.setDate(calendar.getTime());
        weatherModel_3.setTempratureMax(10);
        weatherModel_3.setTempratureMin(5);


        list.add(weatherModel_1);
        list.add(weatherModel_2);
        list.add(weatherModel_3);

        return list;
    }
}

    2. 发布服务代码

package cn.keymobile.server;

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

public class WeatherServer {

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

   2.3.2 客户端
    1. 客户端开发技术不受webservice服务端限制,服务端使用cxf,客户端采用多种方法,比如Service类标准方法。如果使用cxf提供客户端类或方法,需要加入cxf的jar包。
 2. 使用cxf的wsdl2java工具生成,生成源文件,命令如下:

wsdl2java -d . http://127.0.0.1:12345/weather?wsdl

    客户端代码如下:

package cn.keymobile.client;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import cn.keymobile.server.WeatherInterface;
import cn.keymobile.server.WeatherModel;

/**
 * cxf实现webservice客户端
 * @author zhaojd
 *
 */
public class WeatherClient {

    public static void main(String[] args) {
        // jaxWsProxyFactoryBean调用webservice服务端
        JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
        /**
         * 1. 设置wsdl文档路径
         * 2. 设置portType
         * 3. 创建portType
         */
        jaxWsProxyFactoryBean.setAddress("http://127.0.0.1:12345/weather?wsdl");
        jaxWsProxyFactoryBean.setServiceClass(WeatherInterface.class);
        WeatherInterface weatherInterface = (WeatherInterface) jaxWsProxyFactoryBean.create();

        List list = weatherInterface.queryWeather("广州");

        for (WeatherModel wm : list) {
            System.out.println(wm.getDetail());
            Date date = wm.getDate().toGregorianCalendar().getTime();
            System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
            System.out.println(wm.getTempratureMax());
            System.out.println(wm.getTempratureMin());
        }
    }
}

   2.3.3 服务端
  1. Cxf编程方式实现webservice使用JaxWsServerFactoryBean发布webservice服务;在客户端使用JaxWsProxyFactoryBean创建portTypen,通过portType调用webservice服务端;
  2. Cxf和spring整合后,可以将上边的编程方式修改为spring配置方式实现内部使用JaxWsServerFactoryBean和JaxWsProxyFactoryBean 。

   2.3.4 Cxf发布soap1.2
  使用cxf发布soap1.2不需要下载jaxws-ri扩展包。在服务接口的上面添加@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING) 如下:

@WebService
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface WeatherServerInterface 

3. Cxf和spring整合
  3.1 思路
    Cxf框架本身依赖spring,从官方下载cxf包中有spring的jar包。上边使用JaxWsServerFactoryBean和JaxWsProxyFactoryBean,改为spring配置方式。发布服务:使用spring和cxf整合的标签jaxws:server 客户端调用服务:使用spring和cxf整合的标签 jaxws:client 上边的 jaxws:server和 jaxws:client相当于spring容器的bean,发布服务和客户端调用交给spring容器管理。
  3.2 服务端
   1. 创建工程、加入cxf的jar包
   2. 开发SEI和实现类

//Model类字段信息
public class WeatherModel {

    private String detail;
    private Date date;
    private Integer tempratureMax;
    private Integer tempratureMin;
}
///////////////////////////////////////////////////
package cn.keymobile.server;

import java.util.List;
import javax.jws.WebService;
import cn.keymobile.pojo.WeatherModel;

/**
 * 天气查询SEI接口;
 * cxf开发SEI需要将@WebService 写在SEI接口上面
 * @author zhaojd
 */

/**
 * 注解的作用:jaxws提供的注解可以对webservice的接口规范化。
 * targetNamespace:指定wsdl命名空间
 * name:指定portType名称
 * portName:指定port的名称
 * serviceName:服务视图的名称
 */

@WebService(
    targetNamespace="http://server.keymobile.cn/",
    name="WeatherInterface",
    portName="WeatherInterfacePort",
    serviceName="WeatherInterfaceService"
        )
public interface WeatherInterface {

    List queryWeather(String cityName);
}
package cn.keymobile.server;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import cn.keymobile.pojo.WeatherModel;

/**
 * 天气查询SEI 实现类
 * @author zhaojd
 *
 */
public class WeatherInterfaceImpl implements WeatherInterface {

    @Override
    public List queryWeather(String cityName) {
        //构造三天天气
        List list = new ArrayList();

        Calendar calendar = Calendar.getInstance();
        int day = calendar.get(Calendar.DATE);

        WeatherModel weatherModel_1 = new WeatherModel();
        weatherModel_1.setDetail("晴");
        weatherModel_1.setDate(new Date());
        weatherModel_1.setTempratureMax(20);
        weatherModel_1.setTempratureMin(15);

        WeatherModel weatherModel_2 = new WeatherModel();
        weatherModel_2.setDetail("阴");
        calendar.set(Calendar.DATE, day + 1);
        weatherModel_2.setDate(calendar.getTime());
        weatherModel_2.setTempratureMax(15);
        weatherModel_2.setTempratureMin(10);

        WeatherModel weatherModel_3 = new WeatherModel();
        weatherModel_3.setDetail("晴");
        calendar.set(Calendar.DATE, day + 2);
        weatherModel_3.setDate(calendar.getTime());
        weatherModel_3.setTempratureMax(10);
        weatherModel_3.setTempratureMin(5);


        list.add(weatherModel_1);
        list.add(weatherModel_2);
        list.add(weatherModel_3);

        return list;
    }
}

   3. 编写applicationContext.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"
    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.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="cn.keymobile.server.WeatherInterfaceImpl" />

    
    <jaxws:server address="/weather"
        serviceClass="cn.keymobile.server.WeatherInterface">
        <jaxws:serviceBean>
            <ref bean="weatherInterface" />
        jaxws:serviceBean>
    jaxws:server>
beans>

   4. 在web.xml 中配置cxf的servlet及加载spring


<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>cxf_spring_serverdisplay-name>

    
    <context-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>/WEB-INF/classes/applicationContext.xmlparam-value>
    context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
    listener>

    
    <servlet>
        <servlet-name>cxfservlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServletservlet-class>
        <load-on-startup>1load-on-startup>
    servlet>
    
    <servlet-mapping>
        <servlet-name>cxfservlet-name>
        <url-pattern>/ws/*url-pattern>
    servlet-mapping>
web-app>

   5. 启动tomcat

http://localhost:8080/工程名/ws

   7. 测试注意
  因为通过spring和cxf整合将webservice通过tomcat发布,webservice和应用程序共用一个端口都是8080。测试webservice和应用程序(jsp)是否可以共存(都可以访问)。正式上线使用80端口。

  3.3 客户端
   1. 创建工程、加入jar包
   2. 使用wsdl2java或者wsimport工具生成客户端调用代码
   3. 编写applicationContext.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"
    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.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">

    
    <jaxws:client id="weatherClient"
        address="http://localhost:8080/cxf_spring_server/ws/weather?wsdl"
        serviceClass="cn.keymobile.server.WeatherInterface">
    jaxws:client>
beans>

   4. 测试

package cn.keymobile.client;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.keymobile.server.WeatherInterface;
import cn.keymobile.server.WeatherModel;

/**
 * cxf和spring整合
 * @author zhaojd
 *
 */
public class ClientTest {

    private ApplicationContext applicationContext;

    @Before
    public void before() {
        applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void testCxfSpringClient() {
        // 从spring容器中取出portType
        WeatherInterface weatherInterface =
                (WeatherInterface) applicationContext.getBean("weatherClient");

        // 调用portType的方法
        List list = weatherInterface.queryWeather("广州");

        for (WeatherModel weatherModel : list) {
            System.out.println(weatherModel.getDetail());
            Date date = weatherModel.getDate().toGregorianCalendar().getTime();
            System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
            System.out.println(weatherModel.getTempratureMax());
            System.out.println(weatherModel.getTempratureMin());
        }
    }
}

4. CXF发布rest风格的webservice
  4. 1 什么是restFul
  REST是一种软件架构模式,只是一种风格,rest服务采用HTTP 做传输协议,REST对于HTTP的利用分为以下两种:资源定位和资源操作。
  1. 资源定位
    使用url更加准确去定位一个互联网资源,比如:查询一个学生信息url。
    不使用rest的url:http://ip:port/queryUser.action?userType=XXX&studentid=001&XXXX
    使用 rest的url:http://ip:port/user/student/001
    使用rest方式表达url更加简单、可以准确表达这个url是一个学生信息查询url。
  2. 资源操作
    利用HTTP的GET、POST、PUT、DELETE四种操作来表示数据库操作的SELECT、UPDATE、INSERT、DELETE操作。比如:更新学生信息:设置http请求的方法为post。
    定义rest的url:http://ip:port/user/student/001/张三/13
    Rest方式一般要求url中不要有动词。动词采用GET、POST、PUT、DELETE表示。
    Rest风格是对http协议很好的诠释。
    Rest好处:
      定义的url对资源定位更加准确、简单。
    Rest缺点:
      如果rest的url定义层级比较多,可读性较差。
  4. 2 发布rest风格的webservice的实现
   使用cxf发布rest的webservice,使用jaxrs(java开发webservice一个规范)
   1. 创建工程、加入jar包
   2. 编写pojo

/**
 * 学生信息
 * 使用 @XmlRootElement(name = "student") 将pojo转成xml。
 * @author zhaojd
 */
@XmlRootElement(name = "student")
public class Student {

    private long id;
    private String name;
    private Date birthday;
}

   3. 编写SEI

package cn.keymobile.rest.server;

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 cn.keymobile.rest.pojo.Student;

/**
 * rest风格的SEI 
 * @author zhaojd
 */
@WebService
@Path("/student")
public interface StudentService {

    /**
     * @param id 通过url传递的id参数
     * @return 
     * 
     * 根据id查询学生信息
     * @GET      
     *      http的get方法
     * @Path("/query/{id}") 
     *      id参数通过url传递
     * @Produces(MediaType.APPLICATION_XML)
     *      设置媒体类型xml格式 
     */
    @GET
    @Path("/query/{id}")
    @Produces(MediaType.APPLICATION_XML)
    public Student queryStudent(@PathParam("id") long id);

    /**
     * @param type
     * @return
     * 
     * 根据类型查询所有的学生信息
     * @Produces({"application/json;charset=utf-8",MediaType.APPLICATION_XML})
     *     设置媒体类型xml格式和json格式
     * 
     * 如果想让rest返回xml需要在rest的url后边添加?_type=xml,默认为xml
     * 如果想让rest返回json需要在rest的url后边添加?_type=json
     */
    //查询学生列表
    @GET
    @Path("/querylist/{type}")
    @Produces({"application/json;charset=utf-8", MediaType.APPLICATION_XML})
    public List queryStudentList(@PathParam("type") String type);

}

   4. 编写SEI实现类

package cn.keymobile.rest.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import cn.keymobile.rest.pojo.Student;

/**
 * rest风格的学生信息查询 SEI实现类
 * @author zhaojd
 */
public class StudentServiceImpl implements StudentService {

    @Override
    public Student queryStudent(long id) {
        // 使用静态数据
        Student student = new Student();
        student.setId(id);
        student.setName("张三");
        student.setBirthday(new Date());
        return student;
    }

    @Override
    public List queryStudentList(String type) {
        // 使用静态数据
        List list = new ArrayList();
        Student student1 = new Student();
        student1.setId(1000l);
        student1.setName("张三");
        student1.setBirthday(new Date());

        Student student2 = new Student();
        student2.setId(1000l);
        student2.setName("张三");
        student2.setBirthday(new Date());

        list.add(student1);
        list.add(student2);
        return list;
    }
}

   5. 发布rest服务

package cn.keymobile.rest.server;

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;

/**
 * 编程方式发布查询学生信息的rest风格的webservice服务
 * @author zhaojd
 */
public class StudentServer {
    public static void main(String[] args) {

        /**
         * 1. 使用jaxrsServerFactoryBean发布rest服务
         * 2. 设置rest的服务地址
         * 3. 设置资源对象,如果有多个资源对象,中间以半角逗号隔开
         * 4. 发布rest风格的webservice服务
         */
        JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean();
        jaxrsServerFactoryBean.setAddress("http://127.0.0.1:12345/rest");
        jaxrsServerFactoryBean.setServiceBean(new StudentServiceImpl());
        jaxrsServerFactoryBean.setResourceClasses(StudentServiceImpl.class);
        jaxrsServerFactoryBean.create();
    }
}

   6. 测试rest服务

http://127.0.0.1:12345/rest/student/query/001  查询学生信息 
http://127.0.0.1:12345/rest/student/querylist/001?_type=xml  查询学生信息列表,返回xml
http://127.0.0.1:12345/rest/student/querylist/001?_type=json  查询学生信息列表,返回json

   7. rest服务的客户端httpclient方式

package cn.keymobile.rest.client;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 模拟http请求,向webservice的服务端发送soap协议体
 * @author zhaojd
 *
 */
public class HttpClient {

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

        /**
         * 开启一个http链接;webservice的地址
         */
        URL url = new URL("http://127.0.0.1:12345/rest/student/querylist/001?_type=json");
        HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();

        //设置GET请求,GET是大写
        httpUrlConnection.setRequestMethod("GET");
        httpUrlConnection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");

        //设置请求和响应
        httpUrlConnection.setDoInput(true);
        httpUrlConnection.setDoOutput(true);

        //接受响应内容
        InputStream inputStream = httpUrlConnection.getInputStream();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        int len = -1;
        byte[] b = new byte[1024];
        while((len= inputStream.read(b, 0, 1024))!=-1){
            byteArrayOutputStream.write(b, 0, len);
        }
        //获取响应的内容
        String responseString = byteArrayOutputStream.toString();
        System.out.println(responseString);

        //解析响应数据
    }
}

   8. 使用spring的配置方式发布rest服务


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.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="studentService" class="cn.keymobile.rest.server.StudentServiceImpl" />

    
    <jaxrs:server address="/rest">
        <jaxrs:serviceBeans>
            <ref bean="studentService" />
        jaxrs:serviceBeans>
    jaxrs:server>
beans>

   9. rest服务的客户端ajax方式

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js">script>

<script type="text/javascript">

script>
<script type="text/javascript">
    function rest() {
        $.ajax({
            type : 'get',
            url : 'http://localhost:8080/cxf_spring_server_rest/ws/rest/student/querylist/001?_type=json',
            success : function(data) {
                alert(data.student[0].name);
            }
        });
    }
script>
head>
<body>
    <input type="button" value="rest请求" onclick="rest()"/>
body>
html>

你可能感兴趣的:(webservice)