6.Spring MVC RESTful风格

目录


Spring MVC专栏目录(点击进入…)



Web技术发展与REST的由来

Web(万维网World Wide Web的简称)是个包罗万象的万花筒,不同的人从不同的角度观察,对于Web究竟是什么会得出大不相同的观点。作为Web开发者,需要从技术上来理解Web

从技术架构层面上看,Web的技术架构包括了四个基石
①URI
②HTTP
③HyperText(除了HTML外,也可以是带有超链接的XML或JSON)
④MIME

这四个基石相互支撑,促使Web这座宏伟的大厦以几何级数的速度发展了起来。


Web发展

在这四个基石之上,Web开发技术的发展可以粗略划分成以下几个阶段。

(1)静态内容阶段

使用Web的主要是一些研究机构。Web由大量的静态HTML文档组成,其中大多是一些学术论文。Web服务器可以被看作是支持超文本的共享文件服务器

(2)CGI程序阶段

在这个阶段,Web服务器增加了一些编程API。通过这些API编写的应用程序,可以向客户端提供一些动态变化的内容。Web服务器与应用程序之间的通信,通过CGI(Common Gateway Interface)协议完成,应用程序被称作CGI程序

(3)脚本语言阶段

服务器端出现了ASP、PHP、JSP、ColdFusion等支持session的脚本语言技术,浏览器端出现Java Applet、JavaScript 等技术。使用这些技术,可以提供更加丰富的动态内容

(4)瘦客户端应用阶段

在服务器端出现了独立于Web服务器的应用服务器。同时出现了Web MVC开发模式,各种Web MVC开发框架逐渐流行,并且占据了统治地位。基于这些框架开发的Web应用,通常都是瘦客户端应用,因为它们是在服务器端生成全部的动态内容

(5)RIA应用阶段

出现了多种RIA(Rich Internet Application)技术,大幅改善了Web应用的用户体验。应用最为广泛的RIA技术是DHTML + Ajax。Ajax技术支持在不刷新页面的情况下动态更新页面中的局部内容。同时诞生了大量的Web前端DHTML开发库,例如Prototype、Dojo、ExtJS、jQuery/jQuery UI等等,很多开发库都支持单页面应用(Single Page Application)的开发。其他的RIA技术还有Adobe公司的Flex、微软公司的Silverlight、Sun公司的JavaFX(现在为Oracle公司所有)等等

(6)移动Web应用阶段

出现了大量面向移动设备的Web应用开发技术。除了Android、iOS、Windows Phone等操作系统平台原生的开发技术之外,基于HTML5的开发技术也变得非常流行

从上述Web开发技术的发展过程看,Web从最初其设计者所构思的主要支持静态文档的阶段,逐渐变得越来越动态化。Web应用的交互模式,变得越来越复杂;从静态文档发展到以内容为主的门户网站、电子商务网站、搜索引擎、社交网站,再到以娱乐为主的大型多人在线游戏、手机游戏。


常见应用架构风格

架构风格的抽象划分(3种)

从架构风格的抽象高度来看,常见的分布式应用架构风格有三种。

(1)分布式对象(DO)

Distributed Objects架构实例有:CORBA/RMI/EJB/DCOM/.NET Remoting等等

(2)远程过程调用(RPC)

Remote Procedure Call架构实例:SOAP/XML-RPC/Hessian/Flash AMF/DWR等等

(3)表述性状态转移(REST)

Representational State Transfer架构实例:HTTP/WebDAV


架构风格比较

DORPC这两种架构风格在企业应用中非常普遍,而REST则是Web应用的架构风格

REST与DO的差别
①REST支持抽象(即建模)的工具是资源,DO支持抽象的工具是对象
在不同的编程语言中,对象的定义有很大差别,所以DO风格的架构通常都是与某种编程语言绑定的。跨语言交互即使能实现,实现起来也会非常复杂。而REST中的资源,则完全中立于开发平台和编程语言,可以使用任何编程语言来实现
②DO中没有统一接口的概念。不同的API,接口设计风格可以完全不同。DO也不支持操作语义对于中间组件的可见性
③DO中没有使用超文本,响应的内容中只包含对象本身。REST使用了超文本,可以实现更大粒度的交互,交互的效率比DO更高
④REST支持数据流和管道,DO不支持数据流和管道
⑤DO风格通常会带来客户端与服务器端的紧耦合。在三种架构风格之中,DO风格的耦合度是最大的,而REST的风格耦合度是最小的。REST松耦合的源泉来自于统一接口 + 超文本驱动

REST与RPC的差别
①REST支持抽象的工具是资源,RPC支持抽象的工具是过程
②REST风格的架构建模是以名词为核心的,RPC风格的架构建模是以动词为核心的;简单类比一下,REST是面向对象编程,RPC则是面向过程编程
③RPC中没有统一接口的概念。不同的API,接口设计风格可以完全不同。RPC也不支持操作语义对于中间组件的可见性
④RPC中没有使用超文本,响应的内容中只包含消息本身。REST使用了超文本,可以实现更大粒度的交互,交互的效率比RPC更高
⑤REST支持数据流和管道,RPC不支持数据流和管道
因为使用了平台中立的消息,RPC风格的耦合度比DO风格要小一些,但是RPC风格也常常会带来客户端与服务器端的紧耦合。支持统一接口 + 超文本驱动的REST风格,可以达到最小的耦合度

远程过程调用协议(RPC)
RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易
RPC代表:JAVA RMI(二进制协议)、Web Service(文本协议)

消息传递
RPC是一种请求——响应协议,一次RPC在客户端初始化,再由客户端将请求消息传递到远程的服务端,执行指定的带有参数的过程。经过远程服务端执行过后,将结果作为响应内容返回到客户端

存根
在一次分布式计算RPC中,客户端和服务端转换参数的一段代码,由于存根的参数转化,RPC执行过程如同本地执行函数调用。存根必须在客户端和服务端两端均装载,并且必须保持兼容


REST核心介绍

关键要素(5个)

①资源(Resource)
②资源的表述(Representation)
③状态转移(State Transfer)
④统一接口(Uniform Interface)
⑤超文本驱动(Hypertext Driven)

(1)资源

资源是一种看待服务器的方式,即将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在 Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的 URI 与其进行交互

(2)资源的表述

资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端 - 服务器端之间转移(交换)。资源的表述可以有多种格式,如HTML/XML/JSON/ 纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求 - 响应方向的表述通常使用不同的格式

(3)状态转移

状态转移(state transfer)与状态机中的状态迁移(state transition)的含义是不同的。状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的

(4)统一接口

REST 要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。以 HTTP/1.1 协议为例,HTTP/1.1 协议定义了一个操作资源的统一接口,主要包括以下内容:
(1)7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS
(2)HTTP头信息(可自定义)
(3)HTTP响应状态代码(可自定义)
(4)一套标准的内容协商机制
(5)一套标准的缓存机制
(6)一套标准的客户端身份认证机制
REST还要求,对于资源执行的操作,其操作语义必须由HTTP消息体之前的部分完全表达,不能将操作语义封装在HTTP消息体内部。这样做是为了提高交互的可见性,以便于通信链的中间组件实现缓存、安全审计等等功能

(5)超文本驱动

“超文本驱动”又名“将超媒体作为应用状态的引擎”(Hypermedia As The Engine Of Application State,来自Fielding博士论文中的一句话,缩写为HATEOAS)。将Web应用看作是一个由很多状态(应用状态)组成的有限状态机。资源之间通过超链接相互关联,超链接既代表资源之间的关系,也代表可执行的状态迁移。在超媒体之中不仅仅包含数据,还包含了状态迁移的语义。以超媒体作为引擎,驱动Web应用的状态迁移。通过超媒体暴露出服务器所提供的资源,服务器提供了哪些资源是在运行时通过解析超媒体发现的,而不是事先定义的。从面向服务的角度看,超媒体定义了服务器所提供服务的协议。客户端应该依赖的是超媒体的状态迁移语义,而不应该对于是否存在某个URI或URI的某种特殊构造方式作出假设。一切都有可能变化,只有超媒体的状态迁移语义能够长期保持稳定


主要特性(6个)

(1)面向资源(Resource Oriented)
(2)可寻址(Addressability)
(3)连通性(Connectedness)
(4)无状态(Statelessness)
(5)统一接口(Uniform Interface)
(6)超文本驱动(Hypertext Driven)
这六个特征是REST架构设计优秀程度的判断标准。其中,面向资源是REST最明显的特征。即,REST架构设计是以资源抽象为核心展开的。可寻址说的是:每一个资源在Web之上都有自己的地址。连通性说的是:应该尽量避免设计孤立的资源,除了设计资源本身,还需要设计资源之间的关联关系,并且通过超链接将资源关联起来。无状态、统一接口是REST的两种架构约束,超文本驱动是REST的一个关键词


REST架构风格为Web带来的利益?

从面向实用的角度来看,REST架构风格可以为Web开发者带来三方面的利益。

(1)简单性

采用REST架构风格,对于开发、测试、运维人员来说,都会更简单。可以充分利用大量HTTP服务器端和客户端开发库、Web功能测试/性能测试工具、HTTP缓存、HTTP代理服务器、防火墙。这些开发库和基础设施早已成为了日常用品,不需要什么火箭科技(例如神奇昂贵的应用服务器、中间件)就能解决大多数可伸缩性方面的问题

(2)可伸缩性

充分利用好通信链各个位置的HTTP缓存组件,可以带来更好的可伸缩性。其实很多时候,在Web前端做性能优化,产生的效果不亚于仅仅在服务器端做性能优化,但是HTTP协议层面的缓存常常被一些资深的架构师完全忽略掉

(3)松耦合

统一接口 + 超文本驱动,带来了最大限度的松耦合。允许服务器端和客户端程序在很大范围内,相对独立地进化。对于设计面向企业内网的API来说,松耦合并不是一个很重要的设计关注点。但是对于设计面向互联网的API来说,松耦合变成了一个必选项,不仅在设计时应该关注,而且应该放在最优先位置


RESTful特点

RESTful(Representational State Transfer)(表述性状态转移)其实是一个开发理念,是对http的很好的诠释

REST是一种软件架构风格,或者说是一种规范,其强调HTTP应当以资源为中心,并且规范了URI的风格;规范了HTTP请求动作(GET/PUT/POST/DELETE/HEAD/OPTIONS)的使用,具有对应的语义

简单理解:使用URL表示资源,每个资源都用一个独一无二的URL表示,并使用HTTP表示操作方法;即准确描述服务器对资源的处理动作(GET,POST,PUT,DELETE),实现资源的增删改查

RESTful架构,目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
(1)RESTful不是一套标准,只是一套开发方式,构架思想
(2)URL更加简洁
(3)有利于不同系统之间的资源共享

1.对url进行规范

非REST的url:http://…/queryItems.action?id=001&type=T01
REST的url风格:http://…/items/001
特点:url简洁,将参数通过url传到服务端

2.http的方法规范

不管是删除、添加、更新。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加
后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加

3.对http的contentType规范

请求时指定contentType,要json数据,设置成json格式的type


RESTful具体使用

RESTful具体来讲就是HTTP协议的四种形式,四种基本操作
①GET:获取资源
②POST:新建资源
③PUT:修改资源
④DELETE:删除资源

1.配置请求转换器

web.xml

 <!--过滤器,将请求转换为标准的http方法,使得支持GET,POST,PUT,DELETE请求-->
<filter>
   <filter-name>hiddenHttpMethodFilter</filter-name>
   <filter-class>
        org.springframework.web.filter.HiddenHttpMethodFilter
   </filter-class>
</filter>

<filter-mapping>
   <filter-name>hiddenHttpMethodFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

2.Controller控制器,实现基本请求

@RequestMapping(value=“/ itemsView/{id}”):{×××}占位符。请求的URL可以是“/viewItems/1”或“/viewItems/2”,通过在方法中使用@PathVariable获取{×××}中的×××变量。

@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上

如果RequestMapping中表示为"/ itemsView /{id}",id和形参名称一致,@PathVariable不用指定名称

定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入controller。输出json使用@ResponseBody将java对象输出json

// @PostMapping(value = "/restful/{id}") 等价下面
@RequestMapping(value = "/restful/{id}", method = RequestMethod.POST)
public String getRestful(@PathVariable("id") Integer id) {
	System.out.println("修改======" + id);
	return "message";
}

@RequestMapping(value = "/restful/{id}", method = RequestMethod.GET)
public String delRestful(@PathVariable("id") Integer id) {
	System.out.println("查询------" + id);
	return "message";
}

@RequestMapping(value = "/restful", method = RequestMethod.PUT)
@ResponseBody
public String addRestful() {
	System.out.println("增加++++++++");
	return "message";
}

@RequestMapping(value = "/restful/{id}", method = RequestMethod.DELETE)
@ResponseBody
public String upRestful(@PathVariable("id") Integer id) {
	System.out.println("删除------" + id);
	return "message";
}

3.前台表单发送基本请求

<!-- GET 查询 -->
<a href="${pageContext.request.contextPath }/restful/1">get,查询</a>

<!-- POST 增加 -->
<form action="${pageContext.request.contextPath }/restful/1"
		method="post">
	<input type="submit" value="post,修改" />
</form>

<!-- PUT 修改 -->
<form action="${pageContext.request.contextPath }/restful" method="post">
	<input type="hidden" name="_method" value="PUT" />
	<input type="submit" value="put、增加" />
</form>

<!-- DELETE 删除 -->
<form action="${pageContext.request.contextPath }/restful/1" method="post">
	<input type="hidden" name="_method" value="DELETE" />
	<input type="submit" value="delete、删除" />
</form>

静态资源解析器

优雅REST风格的资源URL不希望带.html或.do等后缀。由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往使用*.do、*.xhtml等方式。这就决定了请求URL必须是一个带后缀的URL,而无法采用真正的REST风格的URL

如果将DispatcherServlet请求映射配置为“/”,则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求,Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。
如何让Spring框架能够捕获所有URL的请求,同时又将静态资源的请求转由Web容器处理,是可将DispatcherServlet的请求映射配置为“/”的前提。由于REST是Spring 3.0最重要的功能之一,所以Spring团队很看重静态资源处理这项任务,给出了堪称经典的两种解决方案

先调整web.xml中的DispatcherServlet的配置,使其可以捕获所有的请求

<!-- 激活tomcat的defaultservlet拦截静态资源 -->
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>*.png</url-pattern>
</servlet-mapping>

通过上面url-pattern的配置,所有URL请求都将被Spring MVC的DispatcherServlet截获


方法一:采用<mvc:default-servlet-handler />

<mvc:default-servlet-handler/>

在springmvc-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理

一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:

<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />

方法二:采用<mvc:resources />

<mvc:default-servlet-handler />将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。而<mvc:resources />更进一步,由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能
首先,<mvc:resources />允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,甚至可以将JavaScript等静态文件打到JAR包中。通过location属性指定静态资源的位置,由于location属性是Resources类型,因此可以使用诸如“classpath:”等的资源前缀指定资源位置。传统Web容器的静态资源只能放在Web容器的根路径下,<mvc:resources />完全打破了这个限制

location元素:表示webapp目录下(即服务器根目录)的resource包下的所有文件
mapping元素:表示所有文件请求路径,可自定义,如/resource/
该配置的作用是:DispatcherServlet不会拦截以/resource开头的所有请求路径,并当作静态资源属交由Servlet处理

在springmvc-servlet中添加如下配置

<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/*"/>

以上配置将Web根路径“/”及类路径下/META-INF/publicResources/的目录映射为/resources路径
(1)location:指location指定的目录不要拦截,直接请求,这里指在根目录下的resources文件下的所有文件
(2)mapping:在resources文件下的所有文件(*,代表所有文件)
意思就是在根目录下resources的所有文件不会被DispatcherServlet拦截,直接访问,当做静态资源交个Servlet处理
假设Web根路径下拥有images、js这两个资源目录,在images下面有bg.gif图片,在js下面有test.js文件,则可以通过/resources/images/bg.gif和/resources/js/test.js访问这二个静态资源

假设WebRoot还拥有images/bg1.gif及js/test1.js,可以在网页中通过/resources/images/bg1.gif及/resources/js/test1.js进行引用

<mvc:resources />依据当前著名的Page Speed、YSlow等浏览器优化原则对静态资源提供优化。可以通过cacheSeconds属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。在输出静态资源时,会根据配置设置好响应报文头的Expires和Cache-Control值
在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能

<mvc:resources location="/img/" mapping="/img/**"/>   
<mvc:resources location="/js/" mapping="/js/**"/>    
<mvc:resources location="/css/" mapping="/css/**"/> 

系统在使用Spring MVC作为前端访问控制器时,使用<mvc:resources />不当可能导致系统安全泄露,暴露后端代码以及重要的系统配置文件,数据库配置文件、服务器配置文件等

<mvc:resources location="WEB-INF/resources/" mapping="/resources/**" />

当在Spring MVC中配置了该项,则系统上线后将会暴露自己在WEB-INF中底下resources中的所有的文件,赤裸裸的任人查看,更有甚者,location=“WEB-INF/”,这个底下的文件是所有后端文件,包括所有class、xml、properties文件,这是非常危险的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值