第四课:RESTful Webservice 编程

课程网站:

  • http://ss.sysu.edu.cn/~pml/dct/4_restful_webservice.html

相关文章:

  • 第一课:Java进阶与Socket通讯实验
  • 第二课:Socket通讯与HTTP服务器
  • 第三课:Java Web 编程原理
  • 第四课:RESTful Webservice 编程

Restful 服务端编程


Restful简介

RPC(Remote Procedure Call Protocol),即远程过程调用,是一种进程之间通信的技术。在一开始,电脑的各个进程之间是无法通讯的。为了让进程之间能够互相通讯,于是就发明了IPC(Inter-process communication,单机中运行的进程之间的相互通信)技术。随着互联网的出现,人们又将IPC扩展成为了RPC,于是实现了不同机器之间进程的通讯。

但是,实现RPC是很麻烦的。为了让RPC变得简单,程序员发明了各种各样的框架。Restful就是其中一类高效以及简洁易用的架构风格。

REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性。REST提出设计概念和准则为:
1. 网络上的所有事物都可以被抽象为资源(resource)
2. 每一个资源都有唯一的资源标识(resource identifier),对资源的操作不会改变这些标识
3. 所有的操作都是无状态的
REST简化开发,其架构遵循CRUD原则,该原则告诉我们对于资源(包括网络资源)只需要四种行为:创建,获取,更新和删除就可以完成相关的操作和处理。您可以通过统一资源标识符(Universal Resource Identifier,URI)来识别和定位资源,并且针对这些资源而执行的操作是通过 HTTP 规范定义的。其核心操作只有GET,PUT,POST,DELETE。
由于REST强制所有的操作都必须是stateless的,这就没有上下文的约束,如果做分布式,集群都不需要考虑上下文和会话保持的问题。极大的提高系统的可伸缩性。
对于SOAP Webservice和Restful Webservice的选择问题,首先需要理解就是SOAP偏向于面向活动,有严格的规范和标准,包括安全,事务等各个方面的内容,同时SOAP强调操作方法和操作对象的分离,有WSDL文件规范和XSD文件分别对其定义。而REST强调面向资源,只要我们要操作的对象可以抽象为资源即可以使用REST架构风格。

参考资料:
http://blog.csdn.net/lilongsheng1125/article/details/41643665
https://www.zhihu.com/question/25536695

CXF Restful Service 基础

在下载程序包,例如最新的apache-cxf-3.1.7-src.zip。然后解压到自己喜欢的文件夹。例如我是放在了桌面。

第四课:RESTful Webservice 编程_第1张图片
apache-cxf-3.1.7-src

这里面的文件特别多。我们要找的是一个sample。我们打开神奇的IntelliJ IDEA,然后import project。找到apache-cxf-3.1.7-src\distribution\src\main\release\samples\jax_rs\basic这个路径。然后双击pom.xml。然后一直按next就可以打开这个项目了。

第四课:RESTful Webservice 编程_第2张图片
打开项目

然后和上次一样,在右边找到框,输入命令:

  • install:安装,你会看到制品放入本地仓库
  • -Pserver: 运行服务器,程序会自动启动 jetty
  • -Pclient: 运行客户端程序

我们只需要分别运行 install 和 -Pserver。 然后,在浏览器中输入 URL:http://localhost:9000/customerservice/customers/123 。我们就看到了运行的结果。

第四课:RESTful Webservice 编程_第3张图片
运行结果

返回的是万能的xml。于是简单的程序体验就到这里了。

CXF 与 spring 集成

maven创建web项目:选择maven-archetype-webapp,然后输入:

groupId: me.cxf-sample
artifactId: cxf-rs-spring

项目名为cxf-rs-spring。

然后我们创建在main文件夹里面创建java文件夹,然后把它设置为Source Root。接着加入Java包,命名为demo.jaxrs.server。

第四课:RESTful Webservice 编程_第4张图片
加入Java包

然后我们将刚刚Demo中的Customer.java, CustomerService.java, Product.java, Order.java拖入到该包。

这个时候,发现没有rs包。

第四课:RESTful Webservice 编程_第5张图片
没有rs包

我们添加依赖:


    javax.ws.rs
    javax.ws.rs-api
    2.0.1

按系统文档配置src/main/webapp/WEB-INF/web.xml




  cxf-rs-spring Maven Webapp

  
  
        contextConfigLocation
        WEB-INF/beans.xml
  
  
  
        org.springframework.web.context.ContextLoaderListener
  
  
        org.springframework.web.util.IntrospectorCleanupListener
  

  
  
        CXFServlet
        org.apache.cxf.transport.servlet.CXFServlet
  
  
        CXFServlet
        /*
  


再在同一文件夹下,创建beans.xml,然后继续配置

第四课:RESTful Webservice 编程_第6张图片
创建beans.xml



  

  
  

  
        
          
        
  

  

最后,我们配置pom.xml。然后导入需要的包。


  4.0.0
  me.cxf-sample
  cxf-rs-spring
  war
  1.0-SNAPSHOT
  cxf-rs-spring Maven Webapp
  http://maven.apache.org

  
  
    9.3.7.v20160115
    3.1.6
  
  
    
      junit
      junit
      3.8.1
      test
    
    
      javax.ws.rs
      javax.ws.rs-api
      2.0.1
    
    
    
      org.apache.cxf
      cxf-rt-transports-http
      ${cxf.version}
    
    
      org.apache.cxf
      cxf-rt-frontend-jaxrs
      ${cxf.version}
    

    
    
      org.apache.cxf
      cxf-rt-rs-service-description
      ${cxf.version}
    

    
    
      org.springframework
      spring-web
      3.2.8.RELEASE
    
  
  
    cxf-rs-spring
    
      
        org.eclipse.jetty
        jetty-maven-plugin
        ${jettyVersion}
      
    
  

最后用jetty:run启动服务器。然后,在浏览器输入:http://localhost:8080/与http://localhost:8080/service1/customerservice/customers/123 看效果就行了。

如果我们输入http://localhost:8080/service1?_wadl 就可以看到该服务接口的定义。

我做的时候,出现了下面这个问题,服务器启动不了。找了很久,原来是之前搞apache的时候,服务器没有关闭。于是关闭服务器就好了。

[INFO] Jetty server exiting.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.110s
[INFO] Finished at: Tue Sep 27 22:13:51 CST 2016
[INFO] Final Memory: 25M/249M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.3.7.v20160115:run (default-cli) on project cxf-rs-spring: Failure: Address already in use: bind -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

JAX-RS 服务端编程

将cxf-rs-spring文件夹复制出来,改名为cxf-rs-spring-test。然后进入pom.xml,将原来cxf-rs-spring改为cxf-rs-spring-test

然后我们用IntelliJ IDEA打开这个文件。在java文件夹下,创建org.me.examples.helloworld,然后在这个包下面新建Hello.java。

使用下面代码:

package org.me.examples.helloworld;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

@Path("/hello/{username}")
public class Hello {
    @GET
    @Produces("text/xml")
    public String sayHello(@PathParam("username") String userName) {
        return "hello " + userName;
    }
}

再将beans.xml文件下的关键部分稍作修改。


        
            
            
        
    

    
    

然后我们使用命令行,输入命令:curl http://localhost:8080/service1/hello/Monkey

效果如下:

第四课:RESTful Webservice 编程_第7张图片
效果图

返回了“hello Monkey”,说明成功了。

习题部分


RESTful Webservice 作为远程调用(RPC),它的输入是什么?输入是什么?

REST核心是URL和面向资源,用URL代替了原来复杂的操作方法,把它简化成了GET,PUT,POST,DELETE四个核心操作。一个URL对应着一个资源。因此我们可以认为,输入是一段URL,输出是一段资源(例如Json或者xml)。

有一个 Java 远程函数声明 public Customer getCustomer(String id),把 HTTP 协议输入/输出映射到该函数,至少要申明(annotation)哪些信息?请写出这些 annotation,并简单解释协议与函数的关系。

@GET
@Path("/customers/{id}/")

修改 实验1 的 @Path 为 @Path(“/myservice/”),请用 curl -v 给出结果

我们将@Path("/customerservice/")改为@Path(“/myservice/”)。我们知道,@Path("/customerservice/")表示项目根访问该类的URI路径。如果我们将其换成myservice,那么URL也要换成http://localhost:9000/myservice/customers/123。同理,如果我们换的是@Path("/customers/…")部分,对应的URL也要改变。否则就会显示404。实验结果如下:

第四课:RESTful Webservice 编程_第8张图片
实验结果

简述 GET 与 POST 的区别

Http获取资源的核心操作有四个:GET,POST,PUT,DELETE,对应着对这个资源的查,改,增,删4个操作。因此原理上,GET方法得到资源是不能修改信息的,而POST代表资源有可能会被修改。

在表面上,GET和POST的区别表现在以下方面:

  1. GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),POST把提交的数据则放置在是HTTP包的包体中。
  2. GET方式提交的数据最多只能是1024字节(因为GET用URL提交数据,所有关键在于浏览器对URL的支持),理论上POST没有限制,可传较大量的数据(实际为了安全起见,也有对应的限制)。
  3. 在用不同技术编程的时候,GET和POST的使用方法不一样。
  4. POST的安全性要比GET的安全性高。比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存,(2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击。

参考资料:
http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html

在实际应用中 Map customers 使用会产生副作用吗?为什么?

在多线程编程的时候,会产生副作用。有可能两个用户同时请求同一个ID。因此要尽量避免这种情况。

Spring IOC 与 DI 是 java 编程核心内容之一。阅读Spring IoC 使用详解用自己的语言解释 IoC 解耦原理。

IoC通过依赖注入,使用set或者构造方法实现了解耦。就是本来要修改一个接口的实现,必须要修改里面的内容,用依赖注入,就只需要set一下,就可以了。

(!)使用 Maven 构建(6)给出的案例,项目名称 IOC_test

……

在 Spring 试验中, 阅读 beans.xml, 写出申明根资源的关键内容


    
        
    



(!)尝试写一个根资源类 Hello,用 GET 方法实现 String SayHello() 远程服务。请给出 Hello类代码,增加根资源的配置(不是修改)XML内容,curl测试结果。

package org.me.examples.helloworld;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

@Path("/hello/{username}")
public class Hello {
    @GET
    @Produces("text/xml")
    public String sayHello(@PathParam("username") String userName) {
        return "hello " + userName;
    }
}

        
            
            
        
    

    
    

WADL 的全称。从程序结果返回中截取一段 WADL 内容。

WADL全称为Web Application Description Language,即Web 应用程序描述语言。

第四课:RESTful Webservice 编程_第9张图片
实验返回的WADL

输出对象格式协商是Resquest的Header段的哪个 Field 决定的?

Accept:application/xml

JAX-RS 的全称

JAX-RS即Java API for RESTful Web Services,是一个Java 编程语言的应用程序接口,支持按照表述性状态转移(REST)架构风格创建Web服务。

@Produces 和 @Consumes 的作用

@Produces:
用于指定输出格式,参数可以是字符串数组。 如果是一个数组,第一个是默认输出格式。如果客户端指定输出,则会匹配其他输出。 例如:

@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})

@Consumes:
指定处理输入媒体的类型,例如 “Content-Type: application/json”。 如果你的服务中函数中带一个自由的参数,规定用合适的 输入 provider ,使用 body 中内容,实例化这个参数。例如:

@POST
@Consumes("text/plain")
@Produces("text/xml")
public String sayHello(@PathParam("username") String userName, String letter) {
        return "hello " + userName + ":" + letter;
}

(!)请完成 实验3 的每个参数处理的内容,然后在jesery上完成类似工作。请描述两个平台是否完全兼容?简述不兼容的内容。

……

你可能感兴趣的:(第四课:RESTful Webservice 编程)