SpringMVC 控制层框架-上

一、SpringMVC简介


1. 介绍

Spring Web MVC 是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework 中。在控制层框架经历Srust、WebWork、Strust2等诸多产品的历代更迭之后,目前业界普遍选择了SpringMVC 作为Java EE项目表述层开发的首选方案。之所以能做到这一点,是因为SpringMVC 具备以下优势:

  • Spring 家族原生产品,与IOC容器等基础设施无缝对接
  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
  • 代码清新简洁,大幅度提升开发效率
  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
  • 性能卓著,尤其适合现代大型、超大型互联网项目要求
2. 主要作用

SSM框架构建起单体项目的技术栈需求,其中的SpringMVC负责表述层(控制层)实例简化

SpringMVC的作用主要覆盖的是表述层,例如:请求映射、数据输入、视图界面、请求分发、表单、回显、会话控制、过滤拦截、异步交互、文件上传、文件下载、数据校验、类型转换等等

最终总结:

  1. 简化前端参数接收(形参列表)
  2. 简化后端数据响应(返回值)

3. 核心组件和调用流程理解

SpringMVC 与许多其他Web框架一样,是围绕前端控制器模拟设计的,其中中央Servlet DispatcherServlet 做整体请求处理调度,除了DispatcherServlet SpringMVC其他特殊组件协作完成请求处理和响应呈现。

 SpringMVC涉及组件理解:

  1. DispatcherServlet:SpringMVC提供,我们需要使用web.xml 配置时其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发!(CEO)
  2. HandlerMapping:SpringMVC提供,我们需要进行 IoC配置使其加入 IoC容器方可生效,它内部缓存 handler(Controller方法)和 handler访问路径数据,被DispathcherServlet调用,用于查找路径对应的 handler。(秘书)
  3. HandlerAdapter:SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它可以处理请求参数和处理响应数据,每次DispatcherServlet都是通过handlerAdapeter间接调用handler,他是handler和DisopatcherServlet之间的适配器。(经理)
  4. Handler:handler又称处理器,他是Controller类内部的方法简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果。(打工人)
  5. ViewResolver:SpringMVC提供,我们需要进行 IoC 配置使其加入  IoC 容器方可生效,视图解析器主要作用简化模板视图页面查找的,但是需要注意,前后端分离项目,后端只返回JSON 数据,不返回页面,那就不需要视图解析器,所以,视图解析器相对其他的组件不是必须的。(财务)

二、SpringMVC接收数据


1. 访问路径设置

@RequestMapping  注解的作用就是将请求的 URL 地址和处理请求的方式(handler 方法)关联起来,建立映射关系。SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求。

1.1 精准路径匹配

在 @RequestMapping 注解指定 URL 地址时,不使用任何通配符,按照请求地址进行精准匹配。

@Controller
public class UserController {/*** 精准设置访问地址 /user/login*/@RequestMapping(value = {"/user/login"})@ResponseBodypublic String login(){System.out.println("UserController.login");return "login success!!";}/*** 精准设置访问地址 /user/register*/@RequestMapping(value = {"/user/register"})@ResponseBodypublic String register(){System.out.println("UserController.register");return "register success!!";}    
}
1.2 模糊路径匹配

在 @RequestMapping 注解指定 URL 地址时,通过使用通配符,匹配多个类似的地址。

@Controller
public class ProductController {/***  路径设置为 /product/*  *    /* 为单层任意字符串  /product/a  /product/aaa 可以访问此handler  *    /product/a/a 不可以*  路径设置为 /product/** *   /** 为任意层任意字符串  /product/a  /product/aaa 可以访问此handler  *   /product/a/a 也可以访问*/@RequestMapping("/product/*")@ResponseBodypublic String show(){System.out.println("ProductController.show");return "product show!";}
}
单层匹配和多层匹配:/*:只能匹配URL地址中的一层,如果想准确匹配两层,那么就写“/*/*”以此类推。/**:可以匹配URL地址中的多层。
其中所谓的一层或多层是指一个URL地址字符串被“/”划分出来的各个层次
这个知识点虽然对于@RequestMapping注解来说实用性不大,但是将来配置拦截器的时候也遵循这个规则。
1.3 类和方法级别区别

@RequestMapping 注解可以用于类级别和方法级别,它们之间的区别:

  1.  设置到类级别:@RequestMapping 注解可以设置在控制器类上,用于映射整个控制器的通用请求路径。这样,如果控制器中的多个方法都需要映射同一请求路径,就不需要在每个方法上添加映射路径。
  2. 设置到方法级别:@RequestMapping 注解也可以单独设置在控制器方法上,用于更细粒度地映射请求路径和处理方法。当多个方法处理同一个路径的不同操作时,可以使用方法级别的 @RequestMapping 注解进行更精细的映射。
//1.标记到handler方法
@RequestMapping("/user/login")
@RequestMapping("/user/register")
@RequestMapping("/user/logout")
//2.优化标记类+handler方法
//类上
@RequestMapping("/user")
//handler方法上
@RequestMapping("/login")
@RequestMapping("/register")
@RequestMapping("/logout")
 1.4 附带请求方式限制

HTTP 协仪定义了八种请求方式,在SpringMVC 中封装了下面这个枚举类:

public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}

默认情况下:@RequestMapping("/logout") 任何请求方式都可以访问。

如果需要特定指定:

@Controller
public class UserController {/*** 精准设置访问地址 /user/login* method = RequestMethod.POST 可以指定单个或者多个请求方式!* 注意:违背请求方式会出现405异常!*/@RequestMapping(value = {"/user/login"} , method = RequestMethod.POST)@ResponseBodypublic String login(){System.out.println("UserController.login");return "login success!!";}/*** 精准设置访问地址 /user/register*/@RequestMapping(value = {"/user/register"},method = {RequestMethod.POST,RequestMethod.GET})@ResponseBodypublic String register(){System.out.println("UserController.register");return "register success!!";}
}

注意:违背请求方式,会出现405异常。

1.5 进阶注解

还有 @RequestMapping 的 HTTP 方法特定快捷方式变体:

@GetMapping 、@PostMapping 、@PutMapping  、@DeleteMapping 、@PatchMapping

@RequestMapping(value="/login",method=RequestMethod.GET)
||
@GetMapping(value="/login")

 注意:进阶注解只能添加到 handler 方法上,无法添加到类上。

1.6 常见配置问题

出现原因:多个handler 方法映射了同一个地址,导致 SpringMVC 在接收到这个地址的请求时该找哪个 handler 方法处理。

There is already 'demo03MappingMethodHandler' bean method com.atguigu.mvc.handler.Demo03MappingMethodHandler#empGet() mapped.

 2. 接收参数(重点)
2.1 param 和 json参数比较

在HTTP 请求中,我们可以选择不同的参数类型,如 param类型和JSON 类型。两种参数的区别和对比:

  1. 参数编码:param 类型的参数会被编码为 ASCII 码。而JSON 类型的参数会被编码为  UTF-8。
  2. 参数顺序:param 类型的参数没有顺序限制。JSON类型的参数是有序的。JSON采用键值对的形式进行传递,其中键值对是有序排列的。
  3. 数据类型:param 类型的参数仅支持字符串类型、数值类型和布尔类型等简单数据类型。而JSON类型的参数则支持更复杂的数据类型,如数组、对象等。
  4. 嵌套性:param 类型的参数不支持嵌套。JSON类型的参数支持嵌套,可以传递更复杂的数据结构。
  5. 可读性:param 类型的参数格式比JSON类型的参数更加简单、易读。JSON格式在传递嵌套数据结构时更加清晰易懂。

总的来说,param 类型的参数适用于单一的数据传递,而JSON 类型的参数则更适用于更复杂的数据结构传递。根据具体的业务需求,需要选择合适的参数类型。在实际开发中,常见的做法是:在GET 请求中采用 param 类型的参数,而在 POST 请求中采用 JSON 类型的参数传递。

2.2 param参数接收

1)直接接值

客户端请求

 handler接收参数只要形参名和类型与传递参数相同,即可自动接收。

@Controller
@RequestMapping("param")
public class ParamController {/*** 前端请求: http://localhost:8080/param/value?name=xx&age=18** 可以利用形参列表,直接接收前端传递的param参数!*    要求: 参数名 = 形参名*          类型相同* 出现乱码正常,json接收具体解决!!* @return 返回前端数据*/@GetMapping(value="/value")@ResponseBodypublic String setupForm(String name,int age){System.out.println("name = " + name + ", age = " + age);return name + age;}
}

2)@RequestParam注解

可以使用 @RequestParam 注解将 Servlet 请求参数(即查询参数或表单数据)绑定到控制器中的方法参数。

@RequestParam使用场景:

  • 指定绑定的请求参数名
  • 要求请求参数必须传递
  • 为请求参数提供默认值 
 /*** 前端请求: http://localhost:8080/param/data?name=xx&stuAge=18* *  使用@RequestParam注解标记handler方法的形参*  指定形参对应的请求参数@RequestParam(请求参数名称)*/
@GetMapping(value="/data")
@ResponseBody
public Object paramForm(@RequestParam("name") String name, @RequestParam("stuAge") int age){System.out.println("name = " + name + ", age = " + age);return name+age;
}

默认情况下,使用此批注方法参数是必需的,但你可以通过将 @RequestParam 批注的 required 属性设置为  false。如果没有设置非必须,也没有传递参数会出现 400 状态码。

将参数设置非必须,并且设置默认值:

@GetMapping(value="/data")
@ResponseBody
public Object paramForm(@RequestParam("name") String name, @RequestParam(value = "stuAge",required = false,defaultValue = "18") int age){System.out.println("name = " + name + ", age = " + age);return name+age;
}

3)特殊场景接值

① 一名多值

多选框,提交的数据的时候一个key对应多个值,我们可以使用集合进行接收。

  /*** 前端请求: http://localhost:8080/param/mul?hbs=吃&hbs=喝**  一名多值,可以使用集合接收即可!但是需要使用@RequestParam注解指定*/@GetMapping(value="/mul")@ResponseBodypublic Object mulForm(@RequestParam List<String> hbs){System.out.println("hbs = " + hbs);return hbs;}

② 实体接收

Spring MVC 是Spring 框架提供的 Web 框架,它允许开发者使用实体对象来接收 HTTP 请求中的参数。通过这种方式,可以在方法内部直接使用对象的属性来访问请求参数,而不需要每个参数都写一遍。

public class User {private String name;private int age = 18;// getter 和 setter 略
}@Controller
@RequestMapping("param")
public class ParamController {@RequestMapping(value = "/user", method = RequestMethod.POST)@ResponseBodypublic String addUser(User user) {// 在这里可以使用 user 对象的属性来接收请求参数System.out.println("user = " + user);return "success";}
}

上述代码中,将请求参数 name 和 age 映射到实体类属性上,要求属性名必须等于参数名,否则无法映射。

使用postman传递参数测试:

 2.3 路径参数接收

路径传递参数是一种在 URL 路径中传递参数的方式,在RESTFUL的 Web 应用程序中,经常使用路径传递参数来表资源的唯一标识符或更复杂的标识方式。而Spring MVC 框架提供了 @PathVariable 注解来处理路径传递参数。

@PathVariable 注解允许将 URL 中的占位符映射到控制器方法中的参数。

 /*** 动态路径设计: /user/{动态部分}/{动态部分}   动态部分使用{}包含即可! {}内部动态标识!* 形参列表取值: @PathVariable Long id  如果形参名 = {动态标识} 自动赋值!*              @PathVariable("动态标识") Long id  如果形参名 != {动态标识} 可以通过指定动态标识赋值!** 访问测试:  /param/user/1/root  -> id = 1  uname = root*/
@GetMapping("/user/{id}/{name}")
@ResponseBody
public String getUser(@PathVariable Long id, @PathVariable("name") String uname) {System.out.println("id = " + id + ", uname = " + uname);return "user_detail";
}
2.4 json参数

前端传递 JSON 数据时,Spring MVC 框架可以使用 @RequestBody 注解来将 JSON 数据转换为 java 对象。@RequestBody 注解表示当前方法参数的值应该从请求体中获取,并且需要指定 value 属性来指示请求体应该映射到哪个参数上。

1)前端发送 JSON 数据的示例:(使用postman 测试)

{"name": "张三","age": 18,"gender": "男"
}

2)定义一个用于接收 JSON 数据的 java类。

public class Person {private String name;private int age;private String gender;// getter 和 setter 略
}

3)在控制器中,使用 @RequestBody 注解来接收 JSON 数据,并将其转换为 Java对象。

@PostMapping("/person")
@ResponseBody
public String addPerson(@RequestBody Person person) {// 在这里可以使用 person 对象来操作 JSON 数据中包含的属性return "success";
}

在上述代码中,@RequestBody 注解将请求体中的 JSON 数据映射到 Person 类型的 person参数并将其作为一个对象来传递给 addPerson() 方法处理。

注意:<mvc:annotation是一个整合配置标签,一个标签将springmvc必备组件都加入到ioc容器中!其中包含handlerMapping和handlerAdapter以及json转化器等等!

 <!-- 注意: 导入mvc命名空间!mvc:annotation-driven 是一个整合标签他会导入handlerMapping和handlerAdapter他会导入json数据格式转化器等等!
--><mvc:annotation-driven />
 3. 接收Cookie 数据

可以使用 @CookieValue 注释将 HTTP Cookie 的值绑定到控制器中的方法参数。

 考虑使用以下 cookie 的请求:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
@Controller
@RequestMapping("/ck")
public class CookieController {@GetMapping("/cookie")@ResponseBodypublic String getSessionId(@CookieValue("JSESSIONID") String sessionId ){System.out.println("sessionId = " + sessionId);return "sessionId"+sessionId;}
}
4. 接收请求头数据

可以使用 @RequestHeader 批注将请求标头绑定到控制器中的方法参数。

考虑以下带有标头的请求:

Host                    localhost:8080
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language         fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding         gzip,deflate
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive              300

 实例获取 Accept 标头的值:

@Controller
@RequestMapping("/header")
public class HeaderController {@GetMapping("/accept")@ResponseBodypublic String getAccept(@RequestHeader("Accept") String accept){System.out.println("accept = " + accept);return  accept;}
}
 5. 原生Api对象操作

下表描述了支持的控制器方法参数:

Controller method argument 控制器方法参数Description
jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse请求/响应对象
jakarta.servlet.http.HttpSession强制存在会话。因此,这样的参数永远不会为 null
java.io.InputStream, java.io.Reader用于访问由 Servlet API 公开的原始请求正文。
java.io.OutputStream, java.io.Writer用于访问由 Servlet API 公开的原始响应正文。
@PathVariable接收路径参数注解
@RequestParam用于访问 Servlet 请求参数,包括多部分文件。参数值将转换为声明的方法参数类型。
@RequestHeader用于访问请求标头。标头值将转换为声明的方法参数类型。
@CookieValue用于访问Cookie。Cookie 值将转换为声明的方法参数类型。
@RequestBody用于访问 HTTP 请求正文。正文内容通过使用 HttpMessageConverter 实现转换为声明的方法参数类型。
java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap共享域对象,并在视图呈现过程中向模板公开。
Errors, BindingResult验证和数据绑定中的错误信息获取对象!

获取原生对象示例:

/*** 如果想要获取请求或者响应对象,或者会话等,可以直接在形参列表传入,并且不分先后顺序!* 注意: 接收原生对象,并不影响参数接收!*/
@GetMapping("api")
@ResponseBody
public String api(HttpSession session , HttpServletRequest request,HttpServletResponse response){String method = request.getMethod();System.out.println("method = " + method);return "api";
}
6. 共享域对象操作
6.1 属性(共享)域作用回顾

在JavaWeb中,共享域指的是在 Servlet 中存储数据,以便在同一 Web 应用程序的多个组件中进行共享和访问。常见的共享域有四种:ServletContext、HttpSession、HttpServletRequest、PageContext.

  1. ServletContext 共享域:ServletContext 对象可以在整个Web 应用程序中共享数据,是最大的共享域。一般可以用于保存整个Web 应用程序的全局配置信息,以及所有用户都共享的数据。在 ServletContext  中保存的数据是线程安全的。
  2. HttpSession 共享域:HttpSession 对象可以在同一用户发出的多个请求之间共享数据,但只能在同一个会话中使用。比如,可以将用户登录状态保存在 HttpSession中,让用户在多个页面间保持登录状态。
  3. HttpServletRequest 共享域:HttpServletRequest 对象可以在同一个请求的多个处理方法之间共享数据。比如,可以将请求的参数和属性存储在HttpServletRequest 中,让处理器方法之间可以访问这些数据。
  4. PageContext 共享域:PageContext 对象是在JSP 页面Servlet 创建时自动创建的。它可以在JSP 的各个作用域中共享数据,包括pageScope 、requestScope、sessionScope、applicationScope 等作用域。

共享域的作用是提供了方便实用的方法在同一 Web 应用程序的多个组件之间传递数据,并且可以将数据保存在不同的共享域中,根据需要进行选择和使用。

6.2 Request 级别属性(共享)域
6.3 Session 级别属性(共享)域
6.4 Application 级别属性(共享)域

三、SpringMVC 响应数据


1. handler 方法分析

理解handler 方法的作用和组成:

/*** TODO: 一个controller的方法是控制层的一个处理器,我们称为handler* TODO: handler需要使用@RequestMapping/@GetMapping系列,声明路径,在HandlerMapping中注册,供DS查找!* TODO: handler作用总结:*       1.接收请求参数(param,json,pathVariable,共享域等) *       2.调用业务逻辑 *       3.响应前端数据(页面(不讲解模版页面跳转),json,转发和重定向等)* TODO: handler如何处理呢*       1.接收参数: handler(形参列表: 主要的作用就是用来接收参数)*       2.调用业务: { 方法体  可以向后调用业务方法 service.xx() }*       3.响应数据: return 返回结果,可以快速响应前端数据*/
@GetMapping
public Object handler(简化请求参数接收){调用业务方法return 简化响应前端数据;
}

总结:请求数据接收我们都是通过handler 的形参列表

前端数据响应,我们都是通过handler 的 return 关键字快速处理。

SpringMVC 简化了参数接收和响应。

2. 页面跳转控制
2.1 快速返回 jsp 视图

1)开发模式回顾

在Web 开发中,有两种主要的开发模式:前后端分离和混合开发。

2)jsp技术了解

JSP(javaServer Pages)是一种动态网页开发技术,它是由sun 公司提出的一种基于 java 技术的 Web 页面制作技术,可以在HTML 文件种嵌入 java 代码,使得生成动态内容的编写更简单。

3)准备 jsp 页面和依赖

pom.xml 依赖

<!-- jsp需要依赖! jstl-->
<dependency><groupId>jakarta.servlet.jsp.jstl</groupId><artifactId>jakarta.servlet.jsp.jstl-api</artifactId><version>3.0.0</version>
</dependency>

jsp页面创建

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>Title</title></head><body><!-- 可以获取共享域的数据,动态展示! jsp== 后台vue -->${msg}</body>
</html>

4)快速响应模板页面

① 配置jsp 视图解析器

spring-mvc.xml

<!-- 配置动态页面语言jsp的视图解析器,快速查找jsp-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/>
</bean>

② handler 返回视图

/***  跳转到提交文件页面  /save/jump*  *  如果要返回jsp页面!*     1.方法返回值改成字符串类型*     2.返回逻辑视图名即可    *         <property name="prefix" value="/WEB-INF/views/"/>*            + 逻辑视图名 +*         <property name="suffix" value=".jsp"/>*/
@GetMapping("jump")
public String jumpJsp(Model model){System.out.println("FileController.jumpJsp");model.addAttribute("msg","request data!!");return "home";
}
2.2 转发和重定向 

在 SpringMVC 中,Handler 方法返回值来实现快速转发,可以使用 redirect 或者 forward 关键字来实现重定向。

@RequestMapping("/redirect-demo")
public String redirectDemo() {// 重定向到 /demo 路径 return "redirect:/demo";
}
@RequestMapping("/forward-demo")
public String forwardDemo() {// 转发到 /demo 路径return "forward:/demo";
}//注意: 转发和重定向到项目下资源路径都是相同,都不需要添加项目根路径!填写项目下路径即可!

 总结:

  • 将方法的返回值,设置String 类型
  • 转发使用 forward 关键字,重定向使用 redirect 关键字
  • 关键 :/  路径
  • 注意:如果是项目下的资源,转发和重定向都是一样都是项目下的路径,都不需要添加项目根路径。
3. 返回JSON 数据(重点)
3.1 前置准备

导入 jackson 依赖

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.0</version>
</dependency>

添加数据转化器

 <!-- 注意: 导入mvc命名空间!mvc:annotation-driven 是一个整合标签他会导入handlerMapping和handlerAdapter他会导入json数据格式转化器等等!
-->
<mvc:annotation-driven />
3.2 @ResponseBody

1)方法上使用 @ResponseBody

可以在方法上使用 @ResponseBody 注解,用于将方法返回的对象序列化为 JSON 或 XML 格式的数据,并发送给客户。在前后端分离的项目中使用。

测试方法:

@GetMapping("/accounts/{id}")
@ResponseBody
public Object handle() {// ...return obj;
}

具体来说,@ResponseBody 注解可以用来标识方法或者方法返回值,表示方法的返回值是要直接返回给客户端的数据,而不是由视图解析器来解析并渲染生成响应体(viewResolver 没用)。

测试方法:

@RequestMapping(value = "/user/detail", method = RequestMethod.POST)
@ResponseBody
public User getUser(@RequestBody User userParam) {System.out.println("userParam = " + userParam);User user = new User();user.setAge(18);user.setName("John");//返回的对象,会使用jackson的序列化工具,转成json返回给前端!return user;
}

返回结果:

2. 类上使用 @ResponseBody,如果类中每个方法上都标记了 @ResponseBody 注解,那么这些注解就可以提取到类上。

@ResponseBody  //responseBody可以添加到类上,代表默认类中的所有方法都生效!
@Controller
@RequestMapping("param")
public class ParamController {
}
 3.3 @RestController

类上的 @ResponseBody 注解可以和 @Controller 注解合并为 @RestController 注解。所以使用了 @RestController 注解就相当于给类中的每个方法都加了 @ResponseBody注解。

4. 返回静态资源处理

四、RESTFul 风格设计


1. RESTFul 风格概述
1.1 RESTFul 风格简介

RESTFul (Representational State Transfer)是一种软件架构风格,用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量级的通信协议,广泛应用于现代的 Web 服务开发。

通过遵循 RESTFul 架构的设计原则,可以建设出易于理解、可扩展、松耦合和可重用的 Web 服务。RESTFul API 的特点是简单、清晰,并且易于使用和理解,它们使用标准的 HTTP 方法和状态码进行通信,不需要额外的协议和中间件。

RESTFul 架构通常用于构建 Web API,提供数据的传输和操作。它可以用于各种应用场景,包括客户端应用、页面应用(SPA)、移动应用程序和微服务架构等。

总之,RESTFul是一种基于 HTTP 和标准化的设计原则的软件架构风格,用于设计和实现可靠、可扩展和易于集成的 Web 服务和应用程序。

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

1)HTTP 协议请求方式要求

REST 风格主张在项目设计、开发过程中,具体的操作符合HTTP 协议定义的请求方式的语义

操作请求方式
查询操作GET
保存操作POST
删除操作DELETE
更新操作PUT

2)URL 路径风格要求

REST风格下每个资源都应该有一个唯一的标识符,例如一个URI (统一资源标识符)或者一个 URL(统一资源定位符)。资源的标识符应该能明确地说明该资源的信息,同时也应该是可被理解和解释的!

使用 URL + 请求方式确定具体的动作,他也是一种标准的 HTTP 协议请求

操作传统风格REST 风格
保存/CRUD/saveEmpURL 地址:/CRUD/emp 请求方式:POST
删除/CRUD/removeEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:DELETE
更新/CRUD/updateEmpURL 地址:/CRUD/emp 请求方式:PUT
查询/CRUD/editEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:GET
  • 总结

根据接口的具体动作,选择具体的 HTTP 协议请求方式

路径设计从原来携带动标识,改成名词,对应资源的唯一标识即可。

1.4 RESTFul 风格好处
  • 含蓄安全:

使用问号键值对的方式给服务器传递数据太明显,容易被人利用来对系统进行破坏。使用 REST 风格携带数据不再明显的暴露数据的名称。

  • 风格统一

URL 地址整体格式统一,从前到后始终都使用斜杠划分各个单词,用简单一致的格式表达语义。

  • 无状态

在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了系统设计的复杂度。

  • 严谨、规范

严格按照 HTTP1.1  协议中定义的请求方式本身的语义进行操作

  • 简介、优雅

过去做增删改查操作需要设计4个不同的URL,现在一个就够了。

2. RESTFul 风格实战
2.1  需求分析
  • 数据结构:User{id 唯一标识,name 用户名,age 用户年龄}
  • 功能分析
    • 用户数据分页展示功能(条件:page 页数 默认1,size 每页数量 默认 10)
    • 保存用户功能
    • 根据用户 id 查询用户详情功能
    • 根据用户 id 更新用户数据功能
    • 根据用户 id 删除用户数据功能
    • 多条件模糊查询用户功能(条件:keyword 模板关键字,page 页数 默认1,size 每页数量 默认 10)
2.2 RESTFul 风格接口设计

1)接口设计

功能接口和请求方式请求参数返回值
分页查询GET /userpage=1&size=10 param{ 响应数据 }
用户添加POST /user{ user 数据 }{响应数据}
用户详情GET /user/1路径参数{响应数据}
用户更新PUT /user{ user 更新数据}{响应数据}
用户删除DELETE /user/1路径参数{响应数据}
条件模糊GET /user/searchpage=1&size=10&keywork=关键字{响应数据}

2)问题讨论

为什么查询用户详情,就使用路径传递参数,多条件模糊查询,就可以请求参数传递?

误区:RESTFul 风格下,不是所有请求参数都是路径传递,可以使用其他方式传递。

在RUSTFul API 的设计中,路径、请求参数、请求体都是用来向服务器传递信息的方式。

  • 对于查询用户详情,使用路径传递参数是因为这是一个单一资源的查询,即查询一条用户记录。使用路径参数可以明确指定所请求的资源,便于服务器定位并返回对应的资源,也符合 RESTFul 风格的要求。
  • 而对于多条模糊查询,使用请求参数传递是因为这是一个资源集合的查询,即查询多条用户记录。使用请求参数可以通过组合不同参数来限制查询结果,路径参数的组合和排列可能会很多,不如使用请求参数更加灵活和简洁。
2.3 后台接口实现

准备用户实体类:

/*** projectName: com.atguigu.pojo* 用户实体类*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private Integer id;private String name;private Integer age;
}

准备Controller:

/*** projectName: com.atguigu.controller** description: 用户模块的控制器*/
@RequestMapping("user")
@RestController
public class UserController {/*** 模拟分页查询业务接口*/@GetMappingpublic Object queryPage(@RequestParam(name = "page",required = false,defaultValue = "1")int page,@RequestParam(name = "size",required = false,defaultValue = "10")int size){System.out.println("page = " + page + ", size = " + size);System.out.println("分页查询业务!");return "{'status':'ok'}";}/*** 模拟用户保存业务接口*/@PostMappingpublic Object saveUser(@RequestBody User user){System.out.println("user = " + user);System.out.println("用户保存业务!");return "{'status':'ok'}";}/*** 模拟用户详情业务接口*/@PostMapping("/{id}")public Object detailUser(@PathVariable Integer id){System.out.println("id = " + id);System.out.println("用户详情业务!");return "{'status':'ok'}";}/*** 模拟用户更新业务接口*/@PutMappingpublic Object updateUser(@RequestBody User user){System.out.println("user = " + user);System.out.println("用户更新业务!");return "{'status':'ok'}";}/*** 模拟条件分页查询业务接口*/@GetMapping("search")public Object queryPage(@RequestParam(name = "page",required = false,defaultValue = "1")int page,@RequestParam(name = "size",required = false,defaultValue = "10")int size,@RequestParam(name = "keyword",required= false)String keyword){System.out.println("page = " + page + ", size = " + size + ", keyword = " + keyword);System.out.println("条件分页查询业务!");return "{'status':'ok'}";}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解读|http和https的区别,谁更好用

在日常我们浏览网页时&#xff0c;有些网站会看到www前面是http&#xff0c;有些是https&#xff0c;这两种有什么区别呢&#xff1f;为什么单单多了“s”&#xff0c;会有人说这个网页会更安全些&#xff1f; HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;…

[Labview] 表格单元格外边框 二维图片叠加绘图

最终效果如下所示 转行做Labview都没到三个月&#xff0c;主程居然让我做这么复杂的功能&#xff0c;真是看得起我/(ㄒoㄒ)/~~ 思路大致分为两步 1、确定每个框体的左上/右下单元格位置&#xff0c;转换为表格表格坐标并在二维图片上绘制生成&#xff1b; 2、为二维图片添加…

权威认可 | 海云安开发者安全助手系统通过信通院支撑产品功能认证并荣获信通院2024年数据安全体系建设优秀案例

近日&#xff0c;2024全球数字经济大会——数字安全生态建设专题论坛&#xff08;以下简称“论坛”&#xff09;在京成功举办。由全球数字经济大会组委会主办&#xff0c;中国信息通信研究院及公安部第三研究所共同承办&#xff0c;论坛邀请多位专家和企业共同参与。 会上颁发…

android预置apk

在framework开发中&#xff0c;有一些需求是需要预装应用的&#xff0c;有些是预置应用源码&#xff0c;有些是预置apk。今天我们就分享下怎样预置apk 一般系统有自定义的目录&#xff0c;比如我的项目中根目录下有一个文件夹vendor&#xff0c;这里没都是自定义的一些功能。预…

Unity动画系统(3)---融合树

6.1 动画系统基础2-6_哔哩哔哩_bilibili Animator类 using System.Collections; using System.Collections.Generic; using UnityEngine; public class EthanController : MonoBehaviour { private Animator ani; private void Awake() { ani GetComponen…

二百四十四、Hive——Hive中解析复杂JSON,既有对象还有数组,而且数组中包含数组

一、目的 由于协议修改&#xff0c;修改后的原始数据JSON更加复杂&#xff0c;导致Hive中解析的难度更大&#xff0c;搞了一天&#xff0c;还好同事发了篇知乎文章&#xff0c;终于得以解决&#xff0c;天哪&#xff0c;太不容易了 二、数据协议案例 { "deviceNo&qu…

使用 Python 爬虫实现自动获取天气信息并语音播报

简介 在本文中&#xff0c;我将介绍如何使用 Python 编写一个简单的爬虫程序&#xff0c;该程序可以自动获取某个城市的天气信息&#xff0c;并使用语音库将这些信息播报出来。我们将使用 pyttsx3 库进行语音播报&#xff0c;以及 requests 和 lxml 库来获取和解析网页数据。 …

在GPU上运行PyTorch

文章目录 1、查看GPU的CUDA版本2、下载CUDA版本3、安装cuDNN4、配置CUDA环境变量5、安装配置Anaconda6、使用Anaconda7、pycharm导入虚拟环境8、安装带GPU的PyTorch⭐9、总结 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#x…

抖音seo短视频矩阵源码系统开发搭建----开源+二次开发

抖音seo短视频矩阵源码系统开发搭建 是一项技术密集型工作&#xff0c;需要对大数据处理、人工智能等领域有深入了解。该系统开发过程中需要用到多种编程语言&#xff0c;如Java、Python等。同时&#xff0c;需要使用一些框架和技术&#xff0c;如Hadoop、Spark、PyTorch等&am…

verilog刷题笔记

1、选择器实现方式 &#xff08;1&#xff09;case语句&#xff0c;注意default &#xff08;2&#xff09;if-else语言&#xff0c;注意else&#xff0c;有优先级 &#xff08;3&#xff09;三元运算符 &#xff1f; &#xff1a; 2、阻塞赋值/非阻塞赋值都是过程性赋值&a…

1千多看图猜成语游戏ACCESS\EXCEL数据库

今天闲来无事想写个代码自己搞定&#xff0c;我不写代码已经很久了&#xff0c;主要是年纪不小了对新技术的学习比较吃力&#xff0c;兴趣也被生活打磨的体无完肤。今天又捡起VB&#xff08;暴露了年纪&#xff09;搞了一下。 当然&#xff0c;很多事情都是这样&#xff0c;自己…

Docker容器——初识Docker,安装以及了解操作命令

一、Docker是什么? 是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源&#xff0c;用来管理容器和镜像的工具是在Linux容器里驱动运行应用的开源工具是一种轻量级的“虚拟机” 基于linux内核运行Docker的容器技术可以在一台主机上轻松为任何应用…

【AI教程-吴恩达讲解Prompts】第1篇 - 课程简介

文章目录 简介Prompt学习相关资源 两类大模型原则与技巧 简介 欢迎来到面向开发者的提示工程部分&#xff0c;本部分内容基于吴恩达老师的《Prompt Engineering for Developer》课程进行编写。《Prompt Engineering for Developer》课程是由吴恩达老师与 OpenAI 技术团队成员 I…

CentOS 7 网络配置

如想了解请查看 虚拟机安装CentOS7 第一步&#xff1a;查看虚拟机网络编辑器、查看NAT设置 &#xff08;子网ID&#xff0c;网关IP&#xff09; 第二步&#xff1a;配置VMnet8 IP与DNS 注意事项&#xff1a;子网掩码与默认网关与 第一步 保持一致 第三步&#xff1a;网络配置…

用Pytorch实现线性回归(Linear Regression with Pytorch)

使用pytorch写神经网络的第一步就是需要准备好数据集&#xff0c;设计模型&#xff08;用于计算y_hat&#xff08;y的预测值&#xff09;&#xff09;&#xff0c;构造损失函数和优化器&#xff08;使用PyTorch API&#xff09;&#xff0c;写训练周期&#xff08;前馈&#xf…

Centos7 rpm 安装 Mysql 8.0.28

Centos7 rpm 安装 Mysql 8.0.28 一、检查系统是否已经安装了Mysql 如果安装了则卸载 [rootiZbp1byzaznzn9jncxr010Z /]# rpm -qa | grep mysql[rootiZbp1byzaznzn9jncxr010Z /]# rpm -qa | grep mariadb mariadb-libs-5.5.68-1.el7.x86_64如果安装了 mysql &#xff0c;maria…

2-36 基于matlab的流行学习算法程序

基于matlab的流行学习算法程序。通过GUI的形式将MDS、PCA、ISOMAP、LLE、Hessian LLE、Laplacian、Dissusion MAP、LTSA八种算法。程序以可视化界面进行展示&#xff0c;可直接调用进行分析。多种案例举例说明八种方法优劣&#xff0c;并且可设置自己数据进行分析。程序已调通&…

鸿蒙语言基础类库:【@system.brightness (屏幕亮度)】

屏幕亮度 说明&#xff1a; 从API Version 7 开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口[ohos.brightness]。本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import brightness from sy…

【算法】LRU缓存

难度&#xff1a;中等 题目&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;…

多级表头固定列问题

父级的width&#xff0c;是需要固定的列的width的总和 参考&#xff1a; el-table 多级表头下对应列的固定