WebService基础教程

商业性web项目

学习WebService开始之前,让我们先来了解一下一般的商业性项目结构。

  1. 首先用户在浏览器上输入网址,显示相应页面。
  2. 在视图层根据不同操作访问对应Controler =》Service =》Dao
  3. 由Dao层访问数据库,获取相应数据,并返回。
  4. 视图接收到返回的数据,对页面进行渲染,显示到浏览器。
  5. 项目中的部分接口,可以作为服务发布出去,由第三方应用访问。
  6. 而该项目也调用到第三方服务,获取相关的数据。

WebService基础教程

 上述的1-4步是普通的请求与响应,而5、6步需要与第三方平台交互,而我们无法控制第三方所使用的语言,所以要完成不同语言平台的相互访问,就要使用到WebService了。

 

Socket实现客户端与服务端通信

  在学习WebService之前,我们回顾一下Socket是如何通信的,下面是一个简单的案例。

WebService基础教程
package socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Socket服务端:将客户端发送的数据转换为大写返回
 */
public class MySocketServer {

    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(8080);
        System.out.println("服务地址为:127.0.0.1:8080");
        Socket socket = ss.accept();
        // 接收客户端数据
        InputStream in = socket.getInputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        len = in.read(buffer);
        String data = new String(buffer, 0, len);
        System.out.println("接收客户端数据:" + data);
        // 返回数据
        OutputStream out = socket.getOutputStream();
        String upperData = data.toUpperCase();
        out.write(upperData.getBytes("UTF-8"));
        // 释放资源
        out.flush();
        out.close();
        in.close();
        socket.close();
        ss.close();
    }
}
View Code
WebService基础教程
package socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * Socket客户端
 */
public class MySocketClient {

    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入字符串:");
        String data = sc.nextLine();
        // 定位服务地址
        Socket socket = new Socket("127.0.0.1", 8080);
        // 发送数据
        OutputStream out = socket.getOutputStream();
        out.write(data.getBytes());
        // 接收服务端返回数据
        InputStream in = socket.getInputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        len = in.read(buffer);
        String result = new String(buffer, 0, len);
        System.out.println("服务端返回数据:" + result);
        // 释放资源
        in.close();
        out.close();
        socket.close();
    }
}
View Code

 

WebService介绍

什么是WebService?

  • 是应用程序组件,可以通过web发布服务。
  • 使用开放协议进行通信,如:Http
  • 是独立的,可自我描述(WSDL描述语言)
  • 通过使用UDDI来发现
  • 服务发布后可被其他程序所使用
  • XML是WebService的基础
  • 可向全世界发布功能和消息

  通俗的讲,WebService就是一个部署在Web容器上的一个应用程序,它向外界暴露一个能够通过Web进行调用的API。你能够通过编程的方法

来调用这个应用程序,我们把调用WebService的应用程序叫做客户端,发布这个Web服务的机器叫做服务器。

WebService元素

  • SOAP( simple object access protocol ):简单对象访问协议
  • UDDI:通用发现、描述、整合
  • WSDL:webservice 描述语言

什么是SOAP?

  SOAP,简单对象访问协议,可实现应用程序间的通信,是一种用于发送消息的数据格式,独立于平台,独立于语言,基于XML的一种通信协议。

什么是WSDL?

  可以理解为WebService的说明书,使用XML编写,用来描述WebService以及如何访问WebService的语言。

 

Get请求

  这里有一个发布第三方服务的网站:webxml.com.cn/zh_cn/index.aspx,我们可以使用get请求一下“手机号码归属地查询”服务。

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

/**
 * 调用第三方服务,获取手机号归属地测试
 */
public class MobileTest {

    public static void getMobileCodeInfo(String mobileCode, String userID) throws Exception{
        String urlStr = "http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?" +
                "mobileCode="+ mobileCode +"&userID=" + userID;
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
            InputStream in = conn.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = in.read(buffer)) != -1){
                baos.write(buffer, 0, len);
            }
            System.out.println(baos.toString());
        }
    }

    public static void main(String[] args) throws Exception{
        getMobileCodeInfo("18305422179", "");
    }
}

  执行结果:

WebService基础教程

 

Soap请求

  还是以刚刚的“手机号码归属地查询”服务为例,使用soap进行请求。

  我们点开服务说明,查看WSDL信息。

WebService基础教程

 

  获取到WSDL地址,可以通过java的wsimport命令生成服务代码。切换到指定目录下,执行如下命令:

wsimport http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL

  wsimport命令有几个选项,可以简单了解下:  

    -d 指定输出文件的位置
    -s 解析java源码,默认只解析class源码
    -p 指定包名

  这时可以看到,目录下了几个.class文件。

 WebService基础教程

 

   将这些文件打成jar包,引用到自己的项目中去。

WebService基础教程

   将我们生成好的jar包添加到项目中,然后测试soap请求,代码如下:

import cn.com.webxml.MobileCodeWS;
import cn.com.webxml.MobileCodeWSSoap;

public class TestPhone {

    public static void main(String[] args) {
        MobileCodeWS ws = new MobileCodeWS();
        MobileCodeWSSoap soap = ws.getMobileCodeWSSoap();
        String result = soap.getMobileCodeInfo("18305422179", "");
        System.out.println(result);
    }
}

   执行结果:

WebService基础教程

 

使用wsimport生成本地代理

  我们知道了怎么样去调用别人发布的服务,但我们如何自己发布一个WebService服务呢?

  下面使用wsimport生成本地代理,发布服务,并测试。

  首先,创建一个项目,定义一个WebService服务类。

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;

@WebService(serviceName = "HobbyServiceService") // 定义webservice服务类
public class HobbyService {

    @WebMethod(operationName = "getHobbyInfo")
    public @WebResult(name = "hobby") Hobby getHobbyInfo(@WebParam(name = "code") int code){
        Hobby hobby = new Hobby();
        hobby.setCode(code);
        switch (code){
            case 1:
                hobby.setName("游戏");
                break;
            case 2:
                hobby.setName("唱歌");
                break;
            case 3:
                hobby.setName("篮球");
                break;
            default:
                hobby.setName("无爱好");
        }
        return hobby;
    }

    public static void main(String[] args) {
        String address = "http://localhost:9999/ws/hobby";
        HobbyService hs = new HobbyService();
        Endpoint.publish(address, hs);
        System.out.println("发布服务地址为:" + address + "?WSDL");
    }
}

  将我们的地址发布后,可以在浏览器*问:

WebService基础教程

   此时服务已经发布成功,使用wsimport命令生成服务代码,然后新建一个项目,编写客户端代码,测试本地服务

public class HobbyClient {

    public static void main(String[] args) {
     // 创建服务类 HobbyServiceService hss
= new HobbyServiceService(); HobbyService port = hss.getHobbyServicePort(); Hobby info = port.getHobbyInfo(1); System.out.println(info); } }

  执行结果:

WebService基础教程

 

WSDL文件介绍

  阅读WSDL文件建议从下往上,这样更容易理解,以下是一部分参数说明:

    service name  服务名

    port name  服务访问方式

    soap address  服务地址

    binding name  绑定名

    binding type  webservice类名或接口名

    soap transport  访问方式,soap

    operation name  webservice方法名

    input message  输入参数

    output message  返回参数

 

回顾练习

  看到这里,可以写一个简单的项目,加深一下对WebService的理解。

  项目描述:创建一个Servlet项目,页面中提供几个省市的信息,根据选择的省市,返回对应的城市天气(访问第三方接口)

  1、通过天气服务的WSDL文件,生成代码。这里直接使用发布的WSDL文件会有错误,所以将这个文件另存为本地,去掉错误的约束,将wsimport中的路径指向本地。

  2、引入servlet-api.jar、jsp-api.jar以及刚刚生成的jar包。

WebService基础教程

  3、Servlet代码

WebService基础教程
import cn.ws.wather.service.WeatherService;
import cn.ws.wather.service.impl.WeatherServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class WeatherServlet extends HttpServlet {

    private WeatherService ws;

    @Override
    public void init() throws ServletException {
        ws = new WeatherServiceImpl();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String code = req.getParameter("code");
        String result = ws.getWatherByCode(code);
        resp.setContentType("text/html; charset=UTF-8");
        PrintWriter pw = resp.getWriter();
        pw.write(result);
        pw.flush();
        pw.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
View Code

  4、业务类代码

WebService基础教程
public interface WeatherService {
    public String getWatherByCode(String code);
}
View Code
WebService基础教程
import cn.com.webxml.WeatherWS;
import cn.com.webxml.WeatherWSSoap;
import cn.ws.wather.service.WeatherService;
import java.util.List;

public class WeatherServiceImpl implements WeatherService {

    @Override
    public String getWatherByCode(String code) {
        WeatherWS ws = new WeatherWS();
        WeatherWSSoap soap = ws.getWeatherWSSoap();
        List<String> list = soap.getWeather(code, "").getString();
        return list.get(4);
    }
}
View Code

  5、jsp代码,引入jquery.js文件

WebService基础教程
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>天气预报</title>
    <script src="js/jquery-1.8.2.js"></script>
  </head>
  <body>
    <select id="city">
      <option value="937">济南</option>
      <option value="963">青岛</option>
      <option value="911">威海</option>
      <option value="909">烟台</option>
    </select>
    <span>xxx</span>
    <hr/>
    <script>
      $("#city").change(function(){
          var code = $(this).val();
          $.post(
              "/weather/weatherService",
              {"code": code},
              function (backData) {
                  $("span").text(backData).css("color", "red");
              }
          );
      });
    </script>
  </body>
</html>
View Code

 

采用CXF框架发布服务

1、CXF框架概念介绍

  Apache CXF 是一个开源的 WebService 框架,CXF可以用来构建和开发 WebService,这些服务可以支持多种协议,比如:SOAP、POST/HTTP、HTTP ,CXF 大大简化了WebService并且可以天然地和 Spring 进行无缝集成。CXF是 Celtrix (ESB框架)和 XFire(webserivice) 合并而成,核心是org.apache.cxf.Bus(总线),类似于Spring的 ApplicationContext,CXF默认是依赖于Spring的,另 CXF 发行包中的jar,如果全部放到lib中,需要 JDK1.6 及以上,否则会报JAX-WS版本不一致的问题。CXF 内置了Jetty服务器 ,它是servlet容器。

2、CXF框架特点

  A、与Spring、Servlet做了无缝对接,cxf框架里面集成了Servlet容器Jetty

       B、支持注解的方式来发布webservice

       C、能够显示一个webservice的服务列表

       D、能够添加拦截器:输入拦截器、输出拦截器 :输入日志信息拦截器、输出日志拦截器、用户权限认证的拦截器

3、CXF如何发布服务?

  1、创建一个maven项目,添加以下依赖。

WebService基础教程
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cxf.version>2.7.1</cxf.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxws</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http-jetty</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-ws-security</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-ws-policy</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-bundle-jaxrs</artifactId>
      <version>${cxf.version}</version>
    </dependency>
    <dependency>
      <groupId>javax.ws.rs</groupId>
      <artifactId>jsr311-api</artifactId>
      <version>1.1.1</version>
    </dependency>
  </dependencies>
View Code

  2、创建业务类

WebService基础教程
/**
 *    业务接口
 */
@WebService(serviceName = "languageManager")
public interface LanguageService {
    public @WebResult(name = "language") String getLanguageInfo(@WebParam(name = "rank") int rank);
}

/**
 *    业务实现
 */
public class LanguageServiceImpl implements LanguageService {
    @Override
    public String getLanguageInfo(int rank) {
        String language = "";
        // 根据rank的值获取语言排名
        switch (rank){
            case 1:
                language = "Python";
                break;
            case 2:
                language = "Java";
                break;
            case 3:
                language = "PHP";
                break;
            case 4:
                language = "C#";
                break;
            default:
                language = "不清楚";
                break;
        }
        return language;
    }
    
    /**
     *    测试类
     */
    public static void main(String[] args) {
        LanguageService bean = new LanguageServiceImpl();
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setAddress("http://127.0.0.1:8701/ws/cxf/language");
        factory.setServiceClass(LanguageService.class);
        factory.setServiceBean(bean);
        // 添加日志输入输出拦截器
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());
        // 创建发布WebService
        factory.create();
    }
}
View Code

  发布成功后,可以按照之前的方式访问WSDL,然后编写客户端测试,这里不再赘述。

 

Spring整合CXF发布服务

  在上个项目的基础上,在pom中添加如下依赖。

WebService基础教程
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <org.springframework.version>3.1.1.RELEASE</org.springframework.version>
    <cxf.version>2.7.1</cxf.version>
    <junit.version>4.8.1</junit.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-oxm</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc-portlet</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${org.springframework.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>
    <dependency>
      <groupId>commons-httpclient</groupId>
      <artifactId>commons-httpclient</artifactId>
      <version>3.0</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
View Code

  web.xml

WebService基础教程
<?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_3_0.xsd"
         id="WebApp_ID" version="3.0">

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

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

  实体类

WebService基础教程
public class Employee {
    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name=‘" + name + ‘\‘‘ +
                ", age=" + age +
                ‘}‘;
    }
}
View Code

  业务类

WebService基础教程
@WebService
public interface EmployeeService {

    public void add(Employee employee);

    public List<Employee> query();
}

public class EmployeeServiceImpl implements EmployeeService {

    private List<Employee> emps = new ArrayList<>();

    @Override
    public void add(Employee employee) {
        emps.add(employee);
    }

    @Override
    public List<Employee> query() {
        return emps;
    }
}
View Code

  applicationContext.xml

WebService基础教程
<?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:jaxws="http://cxf.apache.org/jaxws"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans.xsd
                       http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    <bean id="empImpl" class="cn.ws.cxf.service.impl.EmployeeServiceImpl"></bean>

    <jaxws:server address="/employeeManager" serviceClass="cn.ws.cxf.service.EmployeeService">
        <jaxws:serviceBean>
            <ref bean="empImpl"/>
        </jaxws:serviceBean>
        <jaxws:inInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
        </jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
        </jaxws:outInterceptors>
    </jaxws:server>
</beans>
View Code

  启动Tomcat,访问http://localhost:8080/springcxfcore/ws/employeeManager?WSDL,出现WSDL文件,则发布成功。

 

WebService基础教程

上一篇:CSS之BFC的使用场景


下一篇:HDU 3584 Cube (三维 树状数组)