Spring MVC学习记录

一、MVC模式

1. MVC模型:一种软件架构模式

  • Model-View-Controller(模型-视图-控制器)模式,目标是将软件的用户界面(即前台页面)和业务逻辑分离,使代码具有更高的可扩展性、可复用性、可维护性以及灵活性。
  • MVC 模式将应用程序划分成模型(Model)、视图(View)、控制器(Controller)三层:
分层描述

Model

(模型)

它是应用程序的主体部分,主要由以下 2 部分组成:
  • 实体类 Bean:专门用来存储业务数据的对象,它们通常与数据库中的某个表对应,例如 User、Student 等。
  • 业务处理 Bean:指 Service 或 Dao 的对象,专门用于处理业务逻辑、数据库访问。
一个模型可以为多个视图(View)提供数据,一套模型(Model)的代码只需写一次就可以被多个视图重用,有效地减少了代码的重复性,增加了代码的可复用性。

View

(视图)

指在应用程序中专门用来与浏览器进行交互,展示数据的资源。在 Web 应用中,View 就是我们常说的前台页面,通常由 HTML、JSP、CSS、JavaScript 等组成。

Controller(控制器)

通常指的是,应用程序的 Servlet。它负责将用户的请求交给模型(Model)层进行处理,并将 Model 层处理完成的数据,返回给视图(View)渲染并展示给用户。
在这个过程中,Controller 层不会做任何业务处理,它只是 View(视图)层和 Model (模型)层连接的枢纽,负责调度 View 层和 Model 层,将用户界面和业务逻辑合理的组织在一起,起粘合剂的效果。

 2. MVC模式 VS 三层架构

        三层架构是由表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三个层次构成。各层之间采用接口相互访问,并通过实体类作为数据传递的载体。不同的实体类一般对应于数据库中不同的数据表,且实体类的属性与数据库表的字段名一一对应 。
  • 表示层(UI):用来实现与用户的交互,接收用户请求,并将请求交给业务逻辑层(BLL)和数据访问层(DAL)进行处理,最后将处理结果返回给用户。包含 HTML、JSP 等前台页面以及后台的 Servlet,相当于 MVC 模式中的 View 层 + Controller 层。 
  • 业务逻辑层(BLL):起到承上启下的作用,接收表示层传递来的请求,并针对业务对数据进行处理,以实现业务目标。包含了 Service 接口及其实现类(Servicelmpl)的代码,相当于 MVC 模式中 Model 层的一部分(Service部分)
  • 数据访问层(DAL):用于实现与数据库的交互和访问,例如从数据库中获取数据、保存或修改数据库中的数据等。包含了 Dao 接口及其实现类(DaoImpl)的代码,相当于 MVC 模式中 Model 层的一部分(Dao部分)

3. MVC工作流程

  1. 用户发送请求到服务器;
  2. 在服务器中,请求被控制层(Controller)接收;
  3. Controller 调用相应的 Model 层处理请求;
  4. Model 层处理完毕将结果返回到 Controller;
  5. Controller 再根据 Model 返回的请求处理结果,找到相应的 View 视图;
  6. View 视图渲染数据后最终响应给浏览器。

4. MVC优点

  • 降低代码耦合性:在 MVC 模式中,三层之间相互独立,各司其职。一旦某一层的需求发生了变化,我们就只需要更改相应层中的代码即可,而不会对其他层中的代码造成影响。
  • 有利于分工合作:在 MVC 模式中,将应用系统划分成了三个不同的层次,可以更好地实现开发分工。例如,网页设计人员专注于视图(View)层的开发,而那些对业务熟悉的开发人员对 Model 层进行开发,其他对业务不熟悉的开发人员则可以对 Controller 层进行开发。
  • 有利于组件的重用:在 MVC 中,多个视图(View)可以共享同一个模型(Model),大大提高了系统中代码的可重用性。

5. MVC缺点

  • 增加了系统结构和实现的复杂性:对于简单的应用,如果也严格遵循 MVC 模式,按照模型、视图与控制器对系统进行划分,无疑会增加系统结构的复杂性,并可能产生过多的更新操作,降低运行效率。
  • 视图与控制器间的联系过于紧密:虽然视图与控制器是相互分离的,但它们之间联系却是十分紧密的。视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了它们的独立重用。
  • 视图对模型数据的低效率访问:视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

MVC 并不适合小型甚至中型规模的项目,花费大量时间将 MVC 应用到规模并不是很大的应用程序中,通常会得不偿失,因此对于 MVC 设计模式的使用要根据具体的应用场景来决定。 

二、Spring MVC

1. Spring Web MVC

        Spring 框架提供的一款基于 MVC 模式的轻量级 Web 开发框架,是 Spring 为表示层(UI)开发提供的一整套完备的解决方案。

Spring MVC 各层的职责如下:

  • Model:负责对请求进行处理,并将结果返回给 Controller;
  • View:负责将请求的处理结果进行渲染,展示在客户端浏览器上;
  • Controller:是 Model 和 View 交互的纽带;主要负责接收用户请求,并调用 Model 对请求处理,然后将 Model 的处理结果传递给 View。

        Spring MVC 本质是对 Servlet 的进一步封装最核心的组件是 DispatcherServlet,它是 Spring MVC 的前端控制器,主要负责对请求和响应的统一地处理和分发。Controller 接收到的请求就是 DispatcherServlet 根据一定的规则分发给它的。
        Spring MVC 框架内部采用松耦合、可插拔的组件结构,具有高度可配置性,比起其他的 MVC 框架更具有扩展性和灵活性。此外,Spring MVC 的注解驱动(annotation-driven)和对 REST 风格的支持,也是它最具有特色的功能。 

2. Spring MVC 的常用组件

组件提供者描述
DispatcherServlet框架提供前端控制器,它是整个 Spring MVC 流程控制中心,负责统一处理请求和响应,调用其他组件对用户请求进行处理。
HandlerMapping框架提供处理器映射器,根据请求的 url、method 等信息查找相应的 Handler
HandlerAdapter框架提供处理器适配器,Handler执行业务方法前,需要进行一系列的操作,包括表单数据的验证,数据类型的转换,将表单数据封装到JavaBean等。DispatcherServlet通过HandlerAdapter执行不同的Handler。
Handler开发人员提供处理器,通常被称为 Controller(控制器)。它可以在 DispatcherServlet 的控制下,处理具体的业务逻辑
HandlerInterceptor处理器拦截器,是一个接口,若需要完成拦截处理,可以实现该接口。
HandlerExecutionChain处理器执行链,包括Handler和HandlerInterceptor(系统有一个默认的HandlerInterceptor,如需额外拦截,可以添加拦截器)。
ModelAndView装载模型数据和视图信息,作为Handler的处理结果,返回DispatcherServlet。
ViewResolver框架提供

视图解析器,其职责是对视图进行解析,得到相应的视图对象。DispatcherServlet通过它将逻辑视图解析为物理视图。最终将渲染结果显示到客户端。常见的视图解析器有 ThymeleafViewResolver、InternalResourceViewResolver 等。

View开发人员提供视图,它作用是将模型(Model)数据通过页面展示给用户

3. Spring MVC工作流程 

  1. 用户通过浏览器发起一个 HTTP 请求,该请求会被 DispatcherServlet(前端控制器)拦截;
  2. DispatcherServlet 调用 HandlerMapping(处理器映射器)找到具体的处理器(Handler)及拦截器,最后以 HandlerExecutionChain 执行链的形式返回给 DispatcherServlet
  3. DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
  4. HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(即 Controller 控制器)对请求进行处理;
  5. Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC 的底层对象,包括 Model 数据模型和 View 视图信息);
  6. HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet
  7. DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
  8. ViewResolver 解析完成后,会将 View 视图并返回给 DispatcherServlet
  9. DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
  10. 视图负责将结果显示到浏览器(客户端)。

4. Spring MVC 的特点

  • Spring MVC 是 Spring 家族原生产品,可以与 IoC 容器等 Spring 基础设施无缝对接;
  • Spring MVC 支持各种视图技术,例如 JSP、Thymeleaf、 JSP 和 FreeMaker 等。 
  • Spring MVC 基于原生的 Servlet 实现,通过功能强大的前端控制器 DispatcherServlet,对请求和响应进行统一处理;
  • Spring MVC 对表示层各细分领域需要解决的问题全方位覆盖,并提供一整套全面的解决方案;
  • 代码清新简洁,大幅度提升开发效率;
  • 内部组件化程度高,可插拔式组件即插即用,想要使用什么功能,配置相应组件即可;
  • 性能卓著,尤其适合现代大型、超大型互联网项目的开发。

三、@Controller 和 @RequestMapping注解

1. @Controller 注解:将普通 Java 类标识成控制器(Controller)类

package com.circle.controller;

import org.springframework.stereotype.Controller;

@Controller
public class IndexController {
    // 处理请求的方法
}
Spring MVC 通过组件扫描机制查找应用中的控制器类的,为了保证控制器能够被 Spring MVC 扫描到,我们还需要在 Spring MVC 的配置文件中使用 <context:component-scan/> 标签,指定控制器类的基本包(请确保所有控制器类都在基本包及其子包下)
<!-- SpringMVC.xml -->
<!-- 使用扫描机制扫描控制器类,控制器类都在net.biancheng.controller包及其子包下 -->
<context:component-scan base-package="com.circle.controller" />

2. @RequestMapping 注解:标注在控制器方法上,负责将请求与处理请求的控制器方法关联起来,建立映射关系。

前端控制器(DispatcherServlet)拦截到用户发来的请求后,会通过 @RequestMapping 注解提供的映射信息找到对应的控制器方法,对这个请求进行处理。
@RequestMapping 既可以标注在控制器类上,也可以标注在控制器方法上。

2.1 修饰方法

当 @RequestMapping  注解被标注在方法上时,value 属性值就表示访问该方法的 URL 地址。当用户发送过来的请求想要访问该 Controller 下的控制器方法时,请求路径就必须与这个 value 值相同
@Controller
public class HelloController {

    @RequestMapping("/login")
    public String welcome() {
        return "login";
    }
}

2.2 修饰类

当 @RequestMapping 注解标注在控制器类上时,value 属性的取值就是这个控制器类中的所有控制器方法 URL 地址的父路径。也就是说,访问这个 Controller 下的任意控制器方法都需要带上这个父路径。 
@Controller
@RequestMapping(value = "/springmvc")
public class HelloController {
    @RequestMapping("/login")
    public String welcome() {
        return "login";
    }
}
用户想要访问 HelloController 中的 welcome() 方法,请求地址必须为“/springmvc/login” 

2.3 @RequestMapping 注解的属性

2.3.1 value:设置控制器方法的请求映射地址
  • 所有能够匹配到该请求映射地址的请求,都可以被该控制器方法处理
  • 默认属性,只设置了一个 value 属性,则"value="可以被省略
  • 当取值是一个字符串类型的数组,表示该控制器方法可以匹配多个请求地址
@RequestMapping( "/register")

@RequestMapping( value = {"/register", "/login"})
  • 可以使用 Ant 风格的统配符
通配符说明请求映射举例匹配的请求地址举例
?表示任意的单个字符。@RequestMapping(value = "/test-user?")
  • localhost:8080/test-userA
  • localhost:8080/test-userb
  • localhost:8080/test-user1
*表示任意的 0 个或多个字符。@RequestMapping(value = "/test-user*")
  • localhost:8080/test-user
  • localhost:8080/test-userA
  • localhost:8080/test-user-abc
**表示任意的一层或多层目录。
注意,在使用该通配符时,其使用方式只能是 "/**/xxx"。
@RequestMapping(value = "/**/testuser")
  • localhost:8080/test-user
  • localhost:8080/aa/test-user
  • localhost:8080/aa/bb/test-user
2.3.2 name:方法的注释
@RequestMapping(value = "toUser",name = "获取用户信息")
public String getUsers() {
    ……
}
2.3.3 method:设置控制器方法支持的请求方式
@RequestMapping(value = "/toUser",method = RequestMethod.GET)
  • 常用的请求方式有 GET(查看)、POST(创建)、DELETE(删除)、PUT (更新或创建)等。http://t.csdnimg.cn/XfsY3
  • 没设置method说明该控制器方法支持全部请求类型,可以处理所有类型的请求
  • 也可以为同一个控制器方法指定支持多种类型的请求,取值是一个 RequestMethod 类型的数组
@RequestMapping(value = "/toUser",method = {RequestMethod.GET,RequestMethod.POST})
2.3.4 params:指定请求中的参数,只有当请求中携带了符合条件的参数时,控制器方法才会对该请求进行处理
表达式含义
 "param"请求中必须携带名为 param 的参数
"!param"请求中不能携带名为 param 的参数
"param=value"请求中必须携带名为 param 的参数,且参数的取值必须为:value
"param!=value"请求中不能携带参数:param = value。

当取值是一个字符串类型的数组,表示只有请求中同时携带了 params 属性指定的全部参数时,控制器方法才会对该请求进行处理。 

2.3.5 headers:设置请求中请求头信息,只有当请求中携带指定的请求头信息时,控制器方法才会处理该请求。
表达式含义
 "header"请求必须携带请求头信息:header 
"!header"请求中不能携带请求头信息:header
"header=value"请求中必须携带请求头信息:header=value 。
"header!=value"请求中不能携带请求头信息:header=value。

3. @ResponseBody注解:直接响应客户端,不进行视图解析

 

4. @RestController

 如果在每一个方法前都加@ResponseBody,则可以将类前的@Controller注解改为@RestController,功能一致。

四、获取请求参数

  • 通过 HttpServletRequest 获取请求参数
  • 通过控制器方法的形参获取请求参数
  • 使用 @RequestParam 注解获取请求参数
  • 通过实体类对象获取请求参数(推荐)

1.  通过 HttpServletRequest 获取请求参数

        在控制器方法中设置一个 HttpServletRequest 类型的形参,Spring MVC 会自动将请求中携带的参数封装到 HttpServletRequest 形参中,然后我们就可以通过 HttpServletRequest 提供的 getParameter() 方法获取所需的请求参数。
    @RequestMapping("/getRequestParam")
    public String requestParam(HttpServletRequest request) {
        String name = request.getParameter("name");
        String url = request.getParameter("url");
        System.out.println("name:" + name);
        System.out.println("url:" + url);
        return "index";
    }

2. 通过控制器方法的形参获取请求参数

        在 Controller 的控制器方法中设置与请求参数同名的形参,以获取请求中携带的参数。当浏览器发送的请求匹配到这个控制器方法时,Spring MVC 会自动将请求参数赋值给相应的方法形参。
        当发送的请求的 url 为“http://localhost:8080/project/test?name=tom&language=java”时,那么处理该请求的控制器方法的代码如下。
@RequestMapping("/test")
public String test(String name, String language) {
    System.out.println("name:" + name);
    System.out.println("language:" + language);
    return "success";
}
  • 必须保证控制器方法的形参名称请求中携带参数名称完全一致(区分大小写),否则控制器方法接收到的请求参数值会是 null。 
  • 这种方式是无视参数的数据类型的,我们可以在控制器方法中使用 String 字符串类型的形参接收所有的请求参数,也可以根据实际情况在控制器方法中使用对应数据类型的参数来接收请求参数,而无须自行进行数据类型转换。
  • 不适用于请求参数过多的请求
  • 当请求中包含多个同名的请求参数时,通过以下 2 种类型的形参来获取请求参数
形参的数据类型获取到的请求参数值举例
String(字符串)所有同名请求参数的值通过逗号(“,”)拼接在一起。"true,false,true"
数组

由所有同名请求参数值组成的数组。
该数组通常为 String(字符串)类型的,如果所有同名请求参数值都符合同一个数据类型的规范,我们还可以使用与之对应的数据类型的数组进行接收。

例如,如果所有同名请求参数的取值都是 true 或 false,那么我们就可以在控制器方法中使用 Boolean 类型数组的形参进行接收。

{"true", "false", "true"}

3. 使用 @RequestParam 注解获取请求参数

        在控制器方法中通过 @RequestParam 注解,在请求参数与控制器方法的形参之间建立起映射关系,将它们绑定起来。这样即使请求参数与控制器方法中的形参名称不一致,我们也能获取到对应的请求参数值。
请求的地址为“http://localhost:8080/project/test?name=Java&pass=yyds”
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam("name") String username, @RequestParam("pass") String password) {
    System.out.println(username + "," + password);
    return "success";
}
属性说明
name请求中的参数名。
name 为 @RequestParam 注解 value 属性的别名,它与 value 属性完全等价。
value请求中的参数名。
value 为 @RequestParam 注解 name 属性的别名,它与 name 属性完全等价。
required请求参数名是否必须,默认值为 true,即默认情况下请求中必须包含对应的请求参数名,否则就会抛出异常。
注意:required 属性是对请求参数名设置的规则,但并没有对该请求参数是否有值进行限制。也就是说,当 required 属性为 true 或没有设置 required 属性时,请求中就必须包含对应的参数名,至于该请求参数是否有值则无所谓。
defaultValue请求参数的默认值。如果请求中没有该值,则该值为默认值。
注意: defaultValue 属性会使 required ="true" 失效,即将 required 属性自动设置为 false。

4. 通过实体类对象获取请求参数(推荐)

        在 Controller 控制器方法的形参中设置一个实体类形参,如果请求参数的参数名与实体类中的属性名一致,那么 Spring MVC 会自动将请求参数封装到该实体类对象中。此时我们就可以通过该实体类对象获取所需的请求参数了。
@Data
public class User {
    private String UserId;
    private String UserName;
    private Integer age;
}
@Controller
public class UserController {
    /**
     * 通过实体类获取请求参数
     *
     * @param user
     * @return
     */
    @RequestMapping("/getUser")
    public String getUser(User user) {
        System.out.println("userId:" + user.getUserId());
        System.out.println("userName:" + user.getUserName());
        System.out.println("password:" + user.getPassword());
        return "success";
    }
}

 5. 解决获取请求参数的乱码问题

当我们在 post 请求中传递的参数为中文时,控制器方法获取到的参数值会出现乱码的情况。
Spring MVC 默认提供了一个过滤器 CharacterEncodingFilter,我们只需要在 web.xml 中对该 Filter 进行简单的配置,即可解决请求和响应中的中文乱码问题。
<!--请求和响应的字符串过滤器-->
<filter>
     <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--设置请求的编码-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <!--设置响应的编码,这里我们可以省略-->
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
其他中文乱码: 
  • 在SpringMVC.xml文件中配置消息转换器:适用于异步请求
  • 方法中形参HttpServletResponse:适用于同步请求

6. List

SpringMVC不支持List的直接转换,需对List进行包装

7. map

8. JSON

五、域对象共享数据

        在 Spring MVC 中,控制器在接收到 DispatcherServlet 分发过来的请求后,会继续调用 Model 层对请求进行处理。Model 层处理完请求后的结果被称为模型数据,会将模型数据返回给 Controller。Controller 在接收到 Model 层返回的模型数据后,下一步就是将模型数据通过域对象共享的方式传递给 View 视图进行渲染,最终返回给客户端展示。

        域对象是服务器在内存上创建的一块存储空间,主要用不同动态资源之间的数据传递和数据共享。在 Spring MVC 中,常用的域对象有 request 域对象、session 域对象、application 域对象等

        常用的域对象共享数据的方式如下:

  • 使用 Servlet API 向 request 域对象中共享数据(不推荐)
  • 使用 ModelAndView 向 request 域对象中共享数据:方法内new对象调用函数

        model 负责数据共享,而 view 则主要用于设置视图,实现页面的跳转。

方法说明
 ModelAndView addObject(String attributeName, @Nullable Object attributeValue)添加模型数据
ModelAndView addObject(Object attributeValue)
ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap)
void setViewName(@Nullable String viewName) 设置视图
  • 使用 Model 向 request 域对象中共享数据:在 Controller 控制器方法中设置一个 Model 类型的形参
@RequestMapping("/testModel")
public String testModel(Model model) {
    model.addAttribute("testScope", "hello,Model");
    return "success";
}
  • 使用 Map 向 request 域对象中共享数据:在 Controller 控制器方法中设置一个 Map 类型的形参
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map) {
    map.put("testScope", "hello,Map");
    return "success";
}
  • 使用 ModelMap 向 request 域对象中共享数据:在 Controller 控制器方法中设置一个 ModelMap 类型的形参
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap) {
    modelMap.addAttribute("testScope", "hello,ModelMap");
    return "success";
}
  • 使用 Servlet API 向 session 域中共享数据:在控制器方法中设置一个 HttpSession 类型的形参
@RequestMapping("/testSession")
public String testSession(HttpSession session) {
    session.setAttribute("testSessionScope", "hello,session");
    return "success";
}
  • 使用 Servlet API 向 application 域中共享数据:在控制器方法中设置一个 HttpSession 类型的形参
@RequestMapping("/testApplication")
public String testApplication(HttpSession session) {
    ServletContext application = session.getServletContext();
    application.setAttribute("testApplicationScope", "hello,application");
    return "success";
}

详见:Spring MVC域对象共享数据

六、视图与视图解析器

未看,详见Spring MVC视图和视图解析器

七、转发(“forward:”)与重定向(“redirect:”)

1. 概念

实现页面的跳转有两种方式。
转发是由服务器端进行的页面跳转,是一种在服务器内部的资源跳转方式。是网络设备基于IP地址和端口号的决策来进行的,它是网络层或传输层的行为
重定向是将各种网络请求重新定个方向转到其它位置。是应用层的行为,通常由服务器根据HTTP协议实现,它涉及对请求的响应,改变请求的走向。

2. 请求转发

        在控制器方法指定逻辑视图名(View Name)时,使用“forward:”关键字进行请求转发操作。当控制器方法中所设置的逻辑视图名称以“forward:”为前缀时,该逻辑视图名称不会被 Spring MVC 配置的视图解析器解析,而是会将前缀“forward:”去掉,以剩余部分作为最终路径通过转发的方式实现跳转。

2.1 通过 String 类型的返回值实现转发

@RequestMapping("/testDispatcher")
public String testDispatcher() {
    return "forward:/login";
}
        Spring MVC 会将“forward:”识别为转发指示符,而剩余的“/login”则会被当做转发的 URL,即路径“/testDispatcher”请求最终会被转发到 “/login”上进行处理。

2.2 通过 ModelAndView 实现转发

@RequestMapping("/testDispatcher")
public ModelAndView testDispatcher() {
    ModelAndView modelAndView = new ModelAndView();
    //设置逻辑视图名
    modelAndView.setViewName("forward:/login");
    return modelAndView;
}

3. 重定向

3.1 通过 String 类型的返回值实现重定向

@RequestMapping("/testRedirect")
public String testRedirect() {
    return "redirect:/login";
}

3.2 通过 ModelAndView 实现重定向

@RequestMapping("/testRedirect")
public ModelAndView testDispatcher() {
    ModelAndView modelAndView = new ModelAndView();
    //设置逻辑视图名
    modelAndView.setViewName("redirect:/login");
    return modelAndView;
}

八、RESTful

1. 概念

        RESTful(REST 风格)是一种当前比较流行的互联网软件架构模式,它充分利用 HTTP 协议的特性,为我们规定了一套统一的资源获取方式,以实现不同终端之间(客户端与服务端)的数据访问与交互。

RESTFul 提倡我们使用统一的风格来设计 URL,其规则如下。
1. URL 只用来标识和定位资源,不得包含任何与操作相关的动词。例如访问与用户(user)相关的资源时,其 URL 可以定义成以下形式。 

http://localhost:8080/biancheng/user

2. 当请求中需要携带参数时,RESTFul 允许我们将参数通过斜杠(/)拼接到 URL 中,将其作为 URL 的一部分发送到服务器中,而不再像以前一样使用问号(?)拼接键值对的方式来携带参数,示例如下。

http://localhost:8080/biancheng/user/1

:我们在 URL 的末尾通过 “/1”的形式传递了一个取值为 1 的参数。
3. HTTP 协议中有四个表示操作方式的动词:GET、POST、PUT 和 DELETE,它们分别对应了四种与资源相关的基本操作: GET 用来获取资源, POST 用来新建资源, PUT 用来更新资源, DELETE 用来删除资源。客户端通过这四个动词,即可实现对服务器端资源状态转移的描述。

资源操作传统方式 URL RESTFul URLHTTP 请求方式
获取资源(SELECT)http://localhost:8080/biancheng/getUserById?id=1http://localhost:8080/biancheng/user/1GET
保存或新增资源(INSERT)http://localhost:8080/biancheng/saveUserhttp://localhost:8080/biancheng/userPOST
修改或更新资源(UPDATE)http://localhost:8080/biancheng/updateUserhttp://localhost:8080/biancheng/userPUT
删除资源(DELETE)http://localhost:8080/biancheng/deleteUser?id=1http://localhost:8080/biancheng/user/1DELETE

        REST 实际上是 Resource Representational State Transfer 的缩写,翻译成中文就是“表现层资源表述状态转移”。

  • Resource(资源):工程中的所有内容在都可以被称为这个服务器中的资源,可以是一个类、一个 HTML 文件、一个 CSS 文件、一个 JS 文件、数据库中的一张表、一段文本、一张图片、一段音频等,服务器则可以看作是由许许多多离散的资源组成的。这些资源都有一个共同的特征,那就是它们都可以通过一个 URI(统一资源标识符) 进行标识,任何对于该资源的操作都不能改变其 URI。想要获取这个资源,只要访问它的 URI 即可。
  • Representation(资源的表述):资源在某个特定时刻的状态的描述,即资源的具体表现形式,它可以有多种格式,例如 HTML、XML、JSON、纯文本、图片、视频、音频等。通常情况下,服务端与客户端资源的表述所有使用的格式往往是不同的,例如在服务端资源可能是数据库中的一段纯文本、一个 XML 文件、或者是数据库中的一张表,而客户端则可能是表现为 HTML 页面、JSON、甚至是音频和视频。
  • State Transfer(状态转移):客户端与服务端进行交互时,资源从一种表现形式转换到另一种表现形式的过程。但是 HTTP 协议是一种无状态协议,它是无法保存任何状态的,因此如果客户端想要获取服务器上的某个资源,就必须通过某种手段让资源在服务器端发生“状态转化”,而这种状态转化又是建立在应用的表现层(UI)上的。这就是“表现层资源状态转移”的含义。

        REST 实际上描述的是服务器与客户端的一种交互形式,REST 本身并不是一个实用的概念,真正实用的是如何设计 RESTFul(REST 风格)的接口,即我们到底通过什么样的手段让资源在服务器端发生状态转移

 2. 实现RESTful

通过 @RequestMapping +@PathVariable 注解的方式实现 RESTful 风格的请求。

2.1 通过@RequestMapping 注解的路径设置

        当请求中携带的参数是通过请求路径传递到服务器中时,我们就可以在 @RequestMapping 注解的 value 属性中通过占位符 {xxx} 来表示传递的参数。且value 属性中占位符的位置应当与请求 URL 中参数的位置保持一致,否则会出现传错参数的情况。

@RequestMapping("/testRest/{id}/{username}")

2.2 通过 @PathVariable 注解绑定参数

        在控制器方法的形参位置通过 @PathVariable 注解,将占位符 {xxx} 所表示的参数赋值给指定的形参。

@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username")
        String username) {
    System.out.println("id:" + id + ",username:" + username);
    return "success";
}

2.3 通过 HiddenHttpMethodFilter 对请求进行过滤

        由于浏览器默认只支持发送 GET 和 POST 方法的请求,因此我们需要在 web.xml 中使用 Spring MVC 提供的 HiddenHttpMethodFilter 对请求进行过滤。这个过滤器可以帮助我们将 POST 请求转换为 PUT 或 DELETE 请求

HiddenHttpMethodFilter 处理 PUT 和 DELETE 请求时,必须满足以下 2 个条件:

  • 当前请求的请求方式必须为 POST
  • 当前请求必须传输请求参数 _method

        在满足了以上条件后,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数 _method 的值,即请求参数 _method 的值才是最终的请求方式,因此我们需要在 POST 请求中携带一个名为 _method 的参数,参数值为 DELETE 或 PUT。

<!--来处理 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>

        若 web.xml 中同时存在 CharacterEncodingFilter 和 HiddenHttpMethodFilter 两个过滤器,必须先注册 CharacterEncodingFilter,再注册 HiddenHttpMethodFilter。

暂且如此!没学完!

参考:Spring MVC框架入门教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/494492.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Lua热更新(xlua)

发现错误时检查是否:冒号调用 只需要导入asset文件夹下的Plugins和Xlua这两个文件即可,别的不用导入 生成代码 和清空代码 C#调用lua using Xlua; 需要引入命名空间 解析器里面执行lua语法 lua解析器 LuaEnv 单引号是为了避免引号冲突 第二个参数是报错时显示什么提示…

docker 的网络管理

docker应用自带了三种类型的网络&#xff0c;然后我们自己也能自定义网络 roottest-virtual-machine:~# docker network ls NETWORK ID NAME DRIVER SCOPE 4c3e28760cff bridge bridge local afd1493dc119 host host local 5f200e2eaf22 n…

学透Spring Boot — 创建一个简单Web应用

从今天开始&#xff0c;我们将开始学习一个新的系列&#xff0c;那就是在项目中用得非常广泛的一个框架 —— Spring Boot&#xff0c;我们会循序渐进地介绍 Spring Boot 的方方面面&#xff0c;包括理论和实战&#xff0c;也会介绍和Spring Boot一些热点面试题。 概论 本文是…

js逆向之实例某宝热卖(MD5)爬虫

目录 正常写 反爬 逆向分析 关键字搜索 打断点&分析代码 得出 sign 的由来 确定加密方式 写加密函数了 补全代码 免责声明:本文仅供技术交流学习,请勿用于其它违法行为. 正常写 还是老规矩,正常写代码,该带的都带上,我这种方法发现数据格式不完整. 应该后面也是大…

Unity3d使用Jenkins自动化打包(Windows)(二)

文章目录 前言一、Unity工程准备二、Unity调取命令行实战一实战二实战三实战四实战五 总结 前言 自动化打包的价值在于让程序员更轻松地创建和管理构建工具链&#xff0c;提高编程效率&#xff0c;将繁杂的工作碎片化&#xff0c;变成人人&#xff08;游戏行业特指策划&#x…

JavaEE:网络原理——协议(应用层+传输层)

应用层 协议就是一种约定 应用层&#xff1a;对应应用程序&#xff0c;是程序员打交道最多的一层&#xff0c;调用系统提供的网络api写出的代码都是属于应用层的。应用层有很多现成的协议&#xff0c;但程序员一般用的还是自定义协议 自定义协议要约定好哪些内容&#xff1f…

PPT没保存怎么恢复?3个方法(更新版)!

“我刚做完一个PPT&#xff0c;正准备保存的时候电脑没电自动关机了&#xff0c;打开电脑后才发现我的PPT没保存。这可怎么办&#xff1f;还有机会恢复吗&#xff1f;” 在日常办公和学习中&#xff0c;PowerPoint是制作演示文稿的重要工具。我们会在各种场景下使用它。但有时候…

第18篇:4位二进制数到2位十进制数的转换

Q&#xff1a;上一篇我们是将4位二进制数转换为十六进制数在1个数码管显示&#xff0c;本期我们转换为2位十进制数显示在2个数码管上。 A&#xff1a;设计基本思路&#xff1a;4位二进制数转换后的十进制数小于10时&#xff0c;代表个位数的数码管显示0-9&#xff0c;代表十位…

R 药物经济学评价:Markov模型构建及markov轨迹图绘制

All models are wrong, but some are useful-Box,1976 前言 药物经济学评价中比较常用的模型包括决策树&#xff08;Decision tree&#xff09;模型、马尔科夫&#xff08;Markov&#xff09;模型、分区生存模型&#xff08;Partitioned Survival Model,PSM&#xff09;、微观…

IDEA MyBatisCodeHelper Pro最新版(持续更新)

目录 0. 你想要的0.1 包下载0.2 使用jh 1. 功能介绍2. 下载安装2.1 在idea中插件市场安装2.2 在jetbrains插件市场下载安装 3. 简单使用3.1 创建一个SpringBoot项目3.2 配置数据库3.3 一键生成实体类、mapper 0. 你想要的 0.1 包下载 测试系统&#xff1a;Windows&#xff08…

Python+selenium 初体验

PythonSelenium初体验&#xff1a;自动化网页测试与爬虫技术的新里程 引言 在Java领域久了, 偶然间接触到Pythonselenium还是感觉挺神奇的. 自己在这段时间也尝试了使用他们做一些自动化网页的测试. 觉得着实不错. 解放自己的双手, 可以做到网页自动点击,上传文件, 上传图片, …

接口自动化之 + Jenkins + Allure报告生成 + 企微消息通知推送

接口自动化之 Jenkins Allure报告生成 企微消息通知推送 在jenkins上部署好项目&#xff0c;构建成功后&#xff0c;希望可以把生成的报告&#xff0c;以及结果统计发送至企微。 效果图&#xff1a; 实现如下。 1、生成allure报告 a. 首先在Jenkins插件管理中&#x…

【QT】:基本框架

基本框架 一.创建程序二.初识函数1.main2.Widget.h3.Wight.cpp4.Wight.ui5.文件名.pro 三.生成的中间文件 本系列的Qt均使用Qt Creator进行程序编写。 一.创建程序 二.初识函数 1.main 2.Widget.h 3.Wight.cpp 4.Wight.ui 此时再点击编辑&#xff0c;就看到了ui文件的本体了。…

国内IP切换软件:解锁网络世界的新钥匙

在数字化快速发展的今天&#xff0c;互联网已成为我们生活中不可或缺的一部分。然而&#xff0c;伴随着网络使用的深入&#xff0c;许多用户逐渐意识到&#xff0c;不同的IP地址可能会带来截然不同的网络体验。为了应对这一问题&#xff0c;国内IP切换软件应运而生&#xff0c;…

Python(django)之单一接口展示功能前端开发

1、代码 建立apis_manage.html 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>测试平台</title> </head> <body role"document"> <nav c…

Django Cookie和Session

Django Cookie和Session 【一】介绍 【1】起因 HTTP协议四大特性 基于请求响应模式&#xff1a;客户端发送请求&#xff0c;服务端返回响应基于TCP/IP之上&#xff1a;作用于应用层之上的协议无状态&#xff1a;HTTP协议本身不保存客户端信息短链接&#xff1a;1.0默认使用短…

重塑未来:Web3如何改变我们的数字生活

引言 随着科技的飞速发展&#xff0c;Web3已经成为数字时代的新潮流&#xff0c;其革命性的变革正在渐渐改变着我们的数字生活。本文将深入探讨Web3如何改变我们的数字生活&#xff0c;涉及其意义、应用场景、对未来的影响&#xff0c;以及我们如何适应这一变革&#xff0c;为…

Vue 二次封装组件的艺术与实践

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

[flask]执行上下文的四个全局变量

flask上下文全局变量&#xff0c;程序上下文、请求上下文、上下文钩子 -- - 夏晓旭 - 博客园 (cnblogs.com) 执行上下文 执行上下文&#xff1a;即语境&#xff0c;语意&#xff0c;在程序中可以理解为在代码执行到某一行时&#xff0c;根据之前代码所做的操作以及下文即将要…

macos下 jupyter服务安装和vscode链接密码设置 .ipynb文件

最近收到了一些后缀为.ipynb的文件&#xff0c; 这个文件就是使用jupyter编辑的&#xff0c;于是就需要安装一个jupyter服务&#xff0c; 对于最新版本的jupyter 网上很多的资料都已经过期了&#xff0c;这里以最新版本的jupyter为例。 jupyter lab安装 jupyter 这个工具包含…