课程网站:
- 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。然后解压到自己喜欢的文件夹。例如我是放在了桌面。
这里面的文件特别多。我们要找的是一个sample。我们打开神奇的IntelliJ IDEA,然后import project。找到apache-cxf-3.1.7-src\distribution\src\main\release\samples\jax_rs\basic这个路径。然后双击pom.xml。然后一直按next就可以打开这个项目了。
然后和上次一样,在右边找到框,输入命令:
- install:安装,你会看到制品放入本地仓库
- -Pserver: 运行服务器,程序会自动启动 jetty
- -Pclient: 运行客户端程序
我们只需要分别运行 install 和 -Pserver。 然后,在浏览器中输入 URL:http://localhost:9000/customerservice/customers/123 。我们就看到了运行的结果。
返回的是万能的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。
然后我们将刚刚Demo中的Customer.java, CustomerService.java, Product.java, Order.java拖入到该包。
这个时候,发现没有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,然后继续配置
最后,我们配置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,将原来
改为
。
然后我们用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
。
效果如下:
返回了“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。实验结果如下:
简述 GET 与 POST 的区别
Http获取资源的核心操作有四个:GET,POST,PUT,DELETE,对应着对这个资源的查,改,增,删4个操作。因此原理上,GET方法得到资源是不能修改信息的,而POST代表资源有可能会被修改。
在表面上,GET和POST的区别表现在以下方面:
- GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),POST把提交的数据则放置在是HTTP包的包体中。
- GET方式提交的数据最多只能是1024字节(因为GET用URL提交数据,所有关键在于浏览器对URL的支持),理论上POST没有限制,可传较大量的数据(实际为了安全起见,也有对应的限制)。
- 在用不同技术编程的时候,GET和POST的使用方法不一样。
- 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 应用程序描述语言。
输出对象格式协商是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上完成类似工作。请描述两个平台是否完全兼容?简述不兼容的内容。
……