3. SpringMVC Rest 风格
1. REST 简介
REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格。
当要表示一个网络资源的时候,可以使用两种方式:
- 传统风格资源描述形式
http://localhost/user/getById?id=1查询 id 为 1 的用户信息
http://localhost/user/saveUser保存用户信息 - REST风格描述形式
http://localhost/user/1查询 id 为 1 的用户信息
http://localhost/user保存用户信息
传统方式一般是一个请求 url 对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读了请求 url 地址,就大概知道该 url 实现的是什么操作。
查看 REST 风格的描述,会发现请求地址变简单了,并且只看请求 URL 并不能轻易猜出该 URL 的具体功能。
所以 REST 的优点有:
- 隐藏资源的访问行为,无法通过地址得知对资源是何种操作。
- 书写简化。
但是问题也随之而来,一个相同的 url 地址既可以是新增也可以是修改或者查询,该如何区分该请求到底是什么操作呢?
按照 REST 风格访问资源时使用请求动作区分对资源进行了何种操作:

请求的方式比较多,但是比较常用的就 4 种,分别是 GET、POST、PUT、DELETE。不同的请求方式代表不同的操作类型:
- 发送 GET 请求是用来做查询
- 发送 POST 请求是用来做新增
- 发送 PUT 请求是用来做修改
- 发送 DELETE 请求是用来做删除
上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范。可以不这样做,但不建议。
描述模块的名称通常使用复数,也就是加 “s”。这样表示此类资源,而非单个资源,例如:users、books、accounts…
根据 REST 风格对资源进行访问称为 RESTful。
在开发过程中,大多都遵从 REST 风格来访问后台服务,所以可以说以后都是基于 RESTful 来进行开发。
2. RESTful 入门案例
@PathVariable 注解绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应。
public class BookController {//用postman发post请求,请求路径:http://localhost/books@RequestMapping(value = "/books",method = RequestMethod.POST)@ResponseBodypublic String save(@RequestBody Book book){System.out.println("book save..." + book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id@RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)@ResponseBody//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books@RequestMapping(value = "/books",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1@RequestMapping(value = "/books/{id}",method = RequestMethod.GET)@ResponseBody//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books@RequestMapping(value = "/books",method = RequestMethod.GET)@ResponseBodypublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}



@RequestBody、@RequestParam、@PathVariable 三个注解之间的区别和应用分别是什么?
区别:
- @RequestParam 用于接收 url 地址传参或表单传参。
- @RequestBody 用于接收 json 数据。
- @PathVariable 用于接收路径参数,使用 {参数名称} 描述路径参数。
应用:
- 后期开发中,发送请求参数超过 1 个时,以 json 格式为主,@RequestBody 应用较广。
- 如果发送非 json 格式数据,选用 @RequestParam 接收请求参数。
- 采用 RESTful 进行开发,当参数数量较少时,例如 1 个,可以采用 @PathVariable 接收请求路径变量,通常用于传递 id 值。
3. RESTful 快速开发
在前面基础上,
- 可以把相同的路径前缀写在类上,即:把
@RequestMapping("/books")提到类上。 - 由于之前每个方法上都有
@ResponseBody注解,所以可以统一写在类上。
得到如下代码:
@Controller
@ResponseBody
@RequestMapping("/books")
public class BookController {//用postman发post请求,请求路径:http://localhost/books@RequestMapping(method = RequestMethod.POST)public String save(@RequestBody Book book){System.out.println("book save..."+ book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books@RequestMapping(method = RequestMethod.PUT)public String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1@RequestMapping(value = "/{id}",method = RequestMethod.GET)//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books@RequestMapping(method = RequestMethod.GET)public String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}
在上面代码的基础上,@Controller和@ResponseBody注解可以用一个注解@RestController替代。
请求动作也可以用更简单的注解表示。
// @Controller
// @ResponseBody
@RestController
@RequestMapping("/books")
public class BookController {//用postman发post请求,请求路径:http://localhost/books// @RequestMapping(method = RequestMethod.POST)@PostMappingpublic String save(@RequestBody Book book){System.out.println("book save..."+ book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id// @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)@DeleteMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books// @RequestMapping(method = RequestMethod.PUT)@PutMappingpublic String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1// @RequestMapping(value = "/{id}",method = RequestMethod.GET)@GetMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books// @RequestMapping(method = RequestMethod.GET)@GetMappingpublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}
上面的代码去掉注释后:
@RestController
@RequestMapping("/books")
public class BookController {//用postman发post请求,请求路径:http://localhost/books@PostMappingpublic String save(@RequestBody Book book){System.out.println("book save..."+ book);return "{'module':'book save'}";}//用postman发delete请求,请求路径:http://localhost/books/1//请求路径中的“1”传给id@DeleteMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String delete(@PathVariable Integer id){System.out.println("book delete..." + id);return "{'module':'book delete'}";}//用postman发put请求,请求路径:http://localhost/books@PutMappingpublic String update(@RequestBody Book book){System.out.println("book update..." + book);return "{'module':'book update'}";}//用postman发get请求,请求路径:http://localhost/books/1@GetMapping("/{id}")//@PathVariable:把请求路径中的变量值传给形参public String getById(@PathVariable Integer id){System.out.println("book getById..." + id);return "{'module':'book getById'}";}//用postman发get请求,请求路径:http://localhost/books@GetMappingpublic String getAll(){System.out.println("book getAll...");return "{'module':'book getAll'}";}
}
4. 基于 RESTful 的页面数据交互
4.1 需求分析

需求一:图片列表查询,从后台返回数据,将数据展示在页面上。
需求二:新增图书,将新增图书的数据传递到后台,并在控制台打印。
说明:此次案例的重点是在 SpringMVC 中使用 RESTful 实现前后台交互,所以并没有和数据库进行交互,所有数据使用假数据来完成开发。
4.2 后台接口开发
@RestController
@RequestMapping("/books")
public class BookController {//保存图书@PostMappingpublic String save(@RequestBody Book book){System.out.println("保存图书:"+book);return "{'module':'save book success'}";}//查询所有图书@GetMappingpublic List<Book> getAll(){System.out.println("查询所有图书...");List<Book> bookList = new ArrayList<>();Book book1 = new Book();book1.setType("计算机");book1.setName("SpringMVC入门教程");book1.setDescription("小试牛刀");bookList.add(book1);Book book2 = new Book();book2.setType("计算机");book2.setName("SpringMVC实战教程");book2.setDescription("一代宗师");bookList.add(book2);return bookList;}
}
postman 测试:
① 测试新增

② 测试查询

4.2 页面访问处理
(1) 拷贝静态页面:将资料\功能页面下的所有内容拷贝到项目的 webapp 目录下。

(2) 访问 pages 目录下的 books.html
打开浏览器输入http://localhost/pages/books.html

为什么会出现错误?

SpringMVC 拦截了静态资源,根据 /pages/books.html去 controller 找对应的方法,找不到所以会报 404 的错误。
SpringMVC 为什么会拦截静态资源呢?

解决方案:SpringMVC 需要将静态资源放行。
//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {// 当访问/pages/...的时候,从/pages目录下查找内容registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
}
该配置类在 config 目录下,SpringMVC 当前扫描的是 controller 包,所以该配置类还未生效,要想生效需要修改 SpringMvcConfig 配置类的扫描范围。
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc//开启将JSON转换成对象的功能
public class SpringMvcConfig {
}//或者@Configuration
@ComponentScan("com.itheima")
@EnableWebMvc
public class SpringMvcConfig {
}
(3) 修改 books.html 页面

页面完整代码:
<!DOCTYPE html><html><head><!-- 页面meta --><meta charset="utf-8"><title>SpringMVC案例</title><!-- 引入样式 --><link rel="stylesheet" href="../plugins/elementui/index.css"><link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css"><link rel="stylesheet" href="../css/style.css"></head><body class="hold-transition"><div id="app"><div class="content-header"><h1>图书管理</h1></div><div class="app-container"><div class="box"><div class="filter-container"><el-input placeholder="图书名称" style="width: 200px;" class="filter-item"></el-input><el-button class="dalfBut">查询</el-button><el-button type="primary" class="butT" @click="openSave()">新建</el-button></div><el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row><el-table-column type="index" align="center" label="序号"></el-table-column><el-table-column prop="type" label="图书类别" align="center"></el-table-column><el-table-column prop="name" label="图书名称" align="center"></el-table-column><el-table-column prop="description" label="描述" align="center"></el-table-column><el-table-column label="操作" align="center"><template slot-scope="scope"><el-button type="primary" size="mini">编辑</el-button><el-button size="mini" type="danger">删除</el-button></template></el-table-column></el-table><div class="pagination-container"><el-paginationclass="pagiantion"@current-change="handleCurrentChange":current-page="pagination.currentPage":page-size="pagination.pageSize"layout="total, prev, pager, next, jumper":total="pagination.total"></el-pagination></div><!-- 新增标签弹层 --><div class="add-form"><el-dialog title="新增图书" :visible.sync="dialogFormVisible"><el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right" label-width="100px"><el-row><el-col :span="12"><el-form-item label="图书类别" prop="type"><el-input v-model="formData.type"/></el-form-item></el-col><el-col :span="12"><el-form-item label="图书名称" prop="name"><el-input v-model="formData.name"/></el-form-item></el-col></el-row><el-row><el-col :span="24"><el-form-item label="描述"><el-input v-model="formData.description" type="textarea"></el-input></el-form-item></el-col></el-row></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogFormVisible = false">取消</el-button><el-button type="primary" @click="saveBook()">确定</el-button></div></el-dialog></div></div></div></div></body><!-- 引入组件库 --><script src="../js/vue.js"></script><script src="../plugins/elementui/index.js"></script><script type="text/javascript" src="../js/jquery.min.js"></script><script src="../js/axios-0.18.0.js"></script><script>var vue = new Vue({el: '#app',data:{dataList: [],//当前页要展示的分页列表数据formData: {},//表单数据dialogFormVisible: false,//增加表单是否可见dialogFormVisible4Edit:false,//编辑表单是否可见pagination: {},//分页模型数据,暂时弃用},//钩子函数,VUE对象初始化完成后自动执行created() {this.getAll();},methods: {// 重置表单resetForm() {//清空输入框this.formData = {};},// 弹出添加窗口openSave() {this.dialogFormVisible = true;this.resetForm();},//添加saveBook () {axios.post("/books",this.formData).then((res)=>{});},//主页列表查询getAll() {axios.get("/books").then((res)=>{this.dataList = res.data;});},}})</script>
</html>
相关文章:
3. SpringMVC Rest 风格
1. REST 简介 REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格。 当要表示一个网络资源的时候,可以使用两种方式: 传统风格资源描述形式 http://localhost/user/getById?…...
Python3简介
Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。 Python 是面向对象语言: 这意味着P…...
如何学习PMP?
★基础要打牢 方法:“基础不牢,地动山摇”,如果基础不牢那么就很难拿高分,因为连最基础的题目分都不一定能拿到。 可以在针对基础知识,把PMBOK看一两遍,再次加深印象,再把平时做章节练习、每日5…...
【DSP视频教程】第11期:插补算法,曲线拟合丝滑顺畅,统计函数和基础函数加速实现,汇集SIMD,饱和和MAC乘累加应用实战(2023-02-12)
视频教程汇总帖:https://www.armbbs.cn/forum.php?modviewthread&tid110519 DSP视频教程有段时间没有更新了。 当前DSP库从CMSIS软件包里面独立出来,并且更新非常频繁,所以本期视频教程优先给大家简单介绍下新版DSP, 然后为…...
分类模型评估:混淆矩阵、准确率、召回率、ROC
1. 混淆矩阵 在二分类问题中,混淆矩阵被用来度量模型的准确率。因为在二分类问题中单一样本的预测结果只有Yes or No,即:真或者假两种结果,所以全体样本的经二分类模型处理后,处理结果不外乎四种情况,每种…...
算法 ——世界 一
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。个人爱好: 编程,打篮球,计算机知识个人名言:海不辞水,故能成其大;山不辞石…...
2023年3月AMA-CDGA/CDGP数据治理认证考试这些城市可以报名
目前2023年3月5日CDGA&CDGP开放报名的城市有:北京、上海、广州、深圳、杭州、重庆,西安,成都,长沙,济南,更多考场正在增加中… DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业…...
Java变量和数据类型,超详细整理,适合新手入门
目录 一、什么是变量? 二、变量 变量值互换 三、基本数据类型 1、八种基本数据类型 2、布尔值 3、字符串 四、从控制台输入 一、什么是变量? 变量是一种存储值的容器,它可以在程序的不同部分之间共享;变量可以存储数字、字…...
Echarts 设置折线图拐点的颜色,边框等样式,hover时改变颜色
第014个点击查看专栏目录上一篇文章我们讲到了如何设置拐点大小,图形类型,旋转角度,缩放同比,位置偏移等,这篇文章介绍如何设置拐点的颜色、边框大小颜色等样式。hover轴线时候,拐点的填充颜色改变文章目录示例效果示例…...
做 SQL 性能优化真是让人干瞪眼
很多大数据计算都是用SQL实现的,跑得慢时就要去优化SQL,但常常碰到让人干瞪眼的情况。 比如,存储过程中有三条大概形如这样的语句执行得很慢: select a,b,sum(x) from T group by a,b where …; select c,d,max(y) from T grou…...
SpringBoot(3)之包结构
根据spring可知道,注解之所以可以使用,是因为通过包扫描器,扫描包,然后才能通过注解开发。 那么springboot需要扫描哪里呢? springboot的默认包扫描器,扫描的是自己所在的包和子包,例子如下 我…...
test2
物理层故障分析 一、传输介质故障 a.主要用途简述 传输介质主要分为 导向传输介质和非导向传输介质。前者包括双绞线(两根铜线并排绞合,距离过远会失真)、同轴电缆(铜质芯线屏蔽层,抗干扰性强,传输距离更…...
LoadRunner安装教程
备注:电脑最好安装有IE浏览器或者360极速版浏览器 一、下载安装包 提前下载安装文件,必须下载。 链接: https://pan.baidu.com/s/1blFiMIJcoE8s3uVhAxdzdA?pwdqhpt 提取码: qhpt 包含的文件有: 二、安装loadrunner 注意,以…...
VHDL语言基础-Testbech
目录 VHDL仿真概述: 基本结构: VHDL一般仿真过程: 仿真测试平台文件: 编写测试平台文件的语言: 一个测试平台文件的基本结构如下: 测试平台文件包含的基本语句: 产生激励信号的方式: 时钟信号: 复位信号: 周期信性信号: 使用延迟DELAYD: 一般的激励信号…...
机器学习基础总结
一,机器学习系统分类 机器学习系统分为三个类别,如下图所示: 二,如何处理数据中的缺失值 可以分为以下 2 种情况: 缺失值较多:直接舍弃该列特征,否则可能会带来较大噪声,从而对结果造成不良影…...
linux的三权分立设计思路和用户创建(安全管理员、系统管理员和审计管理员)
目录 一、三权分立设计思路 1、什么是三权 2、三员及权限的理解 3、三员之三权 4、权限划分 5、“三员”职责 6、“三员”配置要求 二、linux三权分立的用户创建 1、系统管理员 2、安全管理员 3、审计管理员 一、三权分立设计思路 1、什么是三权 三权指的是配置、…...
revit中如何创建有坡度的排水沟及基坑?
一、revit中如何创建有坡度的排水沟? 先分享一张有坡度排水沟的族的照片给大家加深一下印象,有了一个粗略的直观认识,小编就来说说做这个族的前期思路吧。 一、前期思路: 1、 用拼接的方式把这个族形状拼出来,先用放样࿰…...
Web自动化测试——selenium篇(一)
文章目录一、环境准备二、Web 自动化测试 Demo三、元素定位常用方法四、元素定位失败可能原因五、测试对象操作六、等待操作七、信息打印在学习 Web 自动化测试的过程中,selenium 是其中的常用工具。除了其开源免费,包含丰富的 API 以外,它还…...
认识 CSS pointer-events 属性
pointer-events 的基本信息 pointer-events 属性用来控制一个元素能否响应鼠标操作,常用的关键字有 auto 和 none pointer-events: none; // 让一个元素忽略鼠标操作 pointer-events: auto; // 还原浏览器设定的默认行为 规范定义 条目状态初始值auto可用值适用所…...
【java】springboot和springcloud区别
文章目录1、含义不同2、作用不同3、使用方式不同4、特征不同5、注释不同6、优势不同7、组件不同8、设计目的不同1、含义不同 springboot:一个快速开发框架,它简化了传统MVC的XML配置,使配置变得更加方便、简洁。 springcloud:是…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
