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:是…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...