[华为云在线课程][SpringMVC入门][七][RESTful与拦截器][学习笔记]

举报
John2021 发表于 2022/08/01 06:41:03 2022/08/01
【摘要】 1.RESTful 1.1.定义REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如web应用程序。它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Acces...

1.RESTful

1.1.定义

REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如web应用程序。它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。

1.2.原则条件

REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。
Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。
在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI (Universal Resource Identifier) 得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET、PUT、POST 和 DELETE。Hypermedia 是应用程序状态的引擎,资源表示通过超链接互联。

1.3.特点

  1. 每一个URI代表1种资源。
  2. 客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
  3. 通过操作资源的表现形式来操作资源。
  4. 资源的表现形式是XML或者HTML。
  5. 客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。

1.4.SpringMVC的支持

SpringMVC对RESTful提供了全面支持,主要有以下几个注解:

  • @RestController
    这个注解是一个组合注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 * @since 4.0.1
	 */
	@AliasFor(annotation = Controller.class)
	String value() default "";
}

所以直接用@RestController来标记Controller,可以不是用@Controller。
请求方法中,提供了常见的请求方法。

  • @PostMapping
    用于将HTTP post请求映射到特定处理程序的方法注解。具体来说,@PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。如果执行添加操作, 后面的添加请求不会覆盖前面的请求, 所以使用@Postmapping

  • @GetMapping
    用于将HTTP get请求映射到特定处理程序的方法注解。具体来说,@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。

  • @PutMapping
    和PostMapping作用等同,都是用来向服务器提交信息。如果是添加信息,倾向于用@PostMapping,如果是更新信息,倾向于用@PutMapping。两者差别不是很明显。如果执行修改操作, 后面的修改请求会把前面的请求给覆盖掉, 所以使用@PutMapping

  • @DeleteMapping
    @RequestMapping(method = RequestMethod.DELETE)的简写。作用:对应删除,表明是一个删除URL映射

提取请求地址中的参数的注解@PathVariable

@GetMapping("/book/{id}")
@ResponseBody
public Book getBookById(@PathVariable Integer id) {
    Book book = new Book();
    book.setId(id);
    return book;
}

输出结果:

{"id":3,"name":null,"author":null,"publish":null}

2.静态资源访问

在SpringMVC中,静态资源默认都是被拦截的,例如html、js、css、jpg、png、txt、pdf等,无法直接访问。所以针对静态资源我们要在配置文件对其放行,在SpringMVC配置文件中配置:

<mvc:resources mapping="/static/html/**" location="/static/html/"/>

mapping表示映射规则,也是拦截规则,如果请求地址是/static/html这样格式,那么对应资源就去/static/html中找。
在映射路径定义中,最后是两个*,通配符一共有3种:

通配符 含义
** 匹配多层路径
* 匹配一层路径
? 匹配任意单个字符

一种原始的配置方式是:

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

但由于**表示多级路径,所以可以进行简化:

<mvc:resources mapping="/**" location="/"/>

3.拦截器

SpringMVC中的拦截器,相当于jsp/servlet中的过滤器,只不过过滤器的功能更为强大。
定义如下:

package org.example.utils;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor1 implements HandlerInterceptor {
    /**
     * 这是请求预处理方法,只有当这个方法返回值为true时,后面方法才会执行
     * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1:preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1:postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1:afterCompletion");
    }
}
package org.example.utils;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor2 implements HandlerInterceptor {
    /**
     * 这是请求预处理方法,只有当这个方法返回值为true时,后面方法才会执行
     * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor2:preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor2:postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor2:afterCompletion");
    }
}

定义好拦截器后,在SpringMVC的配置文件中进行配置

<mvc:interceptors>
	<mvc:interceptor>
		<mvc:mapping path="/**"/>
		<ref bean="myInterceptor1"/>
	</mvc:interceptor>
	<mvc:interceptor>
		<mvc:mapping path="/**"/>
		<ref bean="myInterceptor2"/>
	</mvc:interceptor>
</mvc:interceptors>

可以看到,SpringMVC拦截器配置后主要对三个过程进行拦截:

  1. 方法执行前(返回true放行),Handle执行前
  2. 方法执行后,Handle执行后,ModelAndView返回前
  3. 页面渲染后,ModelAndView执行后,对异常处理

情况一,如果存在多个拦截器,两个返回值都为true的情况下,输出结果为:

MyInterceptor1:preHandle
MyInterceptor2:preHandle
MyInterceptor2:postHandle
MyInterceptor1:postHandle
MyInterceptor2:afterCompletion
MyInterceptor1:afterCompletion

情况二,如果MyInterceptor1中preHandle返回值为false,MyInterceptor2中preHandle为true时,打印一下结果:

MyInterceptor1:preHandle

只执行了MyInterceptor1的preHandle,当返回false时,后面的拦截器链不管是true还是false都不执行。

情况三,如果MyInterceptor1中preHandle返回值为true,MyInterceptor2中preHandle为false时,打印一下结果:

MyInterceptor1:preHandle
MyInterceptor2:preHandle
MyInterceptor1:afterCompletion

总结执行顺序:

  • preHandle,按拦截器定义顺序调用
  • postHandle,按拦截器定义逆序调用
  • afterCompletion,按拦截器定义逆序调用
  • postHandle,在拦截器链内所有拦截器返回成功调用
  • afterCompletion,只有preHandle返回true才调用
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。