3. SpringMVC Rest 风格

news2024/9/23 7:26:45

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)
    @ResponseBody
    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 = "/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)
    @ResponseBody
    public 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)
    @ResponseBody
    public 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)
    @PostMapping
    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)
    @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)
    @PutMapping
    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)
    @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)
    @GetMapping
    public String getAll(){
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}

上面的代码去掉注释后:

@RestController
@RequestMapping("/books")
public class BookController {
    //用postman发post请求,请求路径:http://localhost/books
    @PostMapping
    public 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
    @PutMapping
    public 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
    @GetMapping
    public 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 {
    //保存图书
    @PostMapping
    public String save(@RequestBody Book book){
        System.out.println("保存图书:"+book);
        return "{'module':'save book success'}";
    }
    //查询所有图书
    @GetMapping
    public 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 {
    @Override
    protected 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-pagination
                            class="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>

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

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

相关文章

ts快速上手之实现hello world 常见的踩坑排除

前言 大家新年快乐&#xff0c;刚过了一个年又快要到情人节了&#xff0c;提前祝各位同行有女朋友的情人节快乐&#xff0c;没有对象那就new一个对象吧[滑稽] 关于TypeScript 闲话少说&#xff0c;相信大家在这个平台上看到的文章好多开头都会说一些介绍是多久诞生的&#x…

Java面试——MyBatis篇

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Flutter(一)介绍、Dart语言简介

Flutter介绍 纯原生开发主要面临动态化更新和开发成本两个问题&#xff0c;而针对这两个问题&#xff0c;诞生了一些跨平台的动态化框架 跨平台技术简介 Flutter 是 Google 推出并开源的移动应用开发框架&#xff0c;主打跨平台、高保真、高性能。开发者可以通过 Dart 语言开…

【云原生kubernetes】k8s service使用详解

一、什么是服务service&#xff1f; 在k8s里面&#xff0c;每个Pod都会被分配一个单独的IP地址,但这个IP地址会随着Pod的销毁而消失&#xff0c;重启pod的ip地址会发生变化&#xff0c;此时客户如果访问原先的ip地址则会报错 &#xff1b; Service (服务)就是用来解决这个问题的…

Django设计模式以及模板层介绍

MVC和MTV 传统的MVC作用&#xff1a;降低模块间的耦合度&#xff08;解耦&#xff09;Django的MTV模式 作用&#xff1a;降低模块间的耦合度&#xff08;解耦&#xff09;什么是模板 1、模板是可以根据字典数据动态变化的html网页2、模板可以根据视图中传递的字典数据动态生成相…

AtCoder Grand Contest 061(题解)

A - Long Shuffle 这道题本质是一个找规律的题 既然是打表题&#xff0c;我们先暴力把他打出来 (盗一张图.jpg) 接下来就是在这张图中挖掘答案 我们可以明显的看到偶数行是有一些规律的 要么是相邻对的互换&#xff0c;要么不变 不变和互换的位置也有讲究&#xff0c;在二进制…

DS期末复习卷(四)

一、选择题(每题1分共 20分) 1&#xff0e;设一维数组中有n个数组元素&#xff0c;则读取第i个数组元素的平均时间复杂度为&#xff08;C &#xff09;。 (A) O(n) (B) O(nlog2n) © O(1) (D) O(n2) 数组读取元素的时间复杂度为O&#xff08;1&#xff09; 2&#xff0e;设…

SpringCloud Alibaba

文章目录&#x1f68f; 第十七章 SpringCloud Alibaba入门简介&#x1f6ac; 一、为什么使用Alibaba&#x1f6ad; 1、spring netflix进入维护模式&#x1f6ad; Spring cloud alibaba&#x1f6ac; 二、如何使用&#xff1f;&#x1f6ac; 三、版本对应&#x1f68f; 第十八章…

Jmeter接口测试+压力测试

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是免…

朴素贝叶斯算法和拉普拉斯平滑详细介绍及其原理详解

相关文章 K近邻算法和KD树详细介绍及其原理详解朴素贝叶斯算法和拉普拉斯平滑详细介绍及其原理详解 文章目录相关文章前言一、朴素贝叶斯算法二、拉普拉斯平滑总结前言 今天给大家带来的主要内容包括&#xff1a;朴素贝叶斯算法、拉普拉斯平滑。这些内容也是机器学习的基础内容…

AXI-Lite 学习笔记

AXI-Lite 学习笔记 参考 FPGA&#xff1a;AXI_Lite总线基础2-1]、第二节 AXI总线介绍、ZYNQ PL与PS交互专题_哔哩哔哩_bilibili AXI-Lite总线系列1 - 基础知识_哔哩哔哩_bilibili AXI4 介绍 AXI4 是ARM公司提出的一种片内总线&#xff0c;描述了主从设备之间的数据传输方式。主…

深入浅出原核基因表达调控(乳糖操纵子、色氨酸操纵子)

原核基因表达调控 前言 自然界里&#xff0c;能量时有时无&#xff0c;各种生命为了让自己能够活下去&#xff0c;需要适应环境&#xff0c;在不同的环境合成不同的蛋白质。 原核生物体内有很多细胞&#xff0c;细胞里面有很多蛋白质&#xff0c;但是这些蛋白质在这些细胞里…

React Draggable插件实现拖拽功能

React Draggable插件实现拖拽功能1.下载Draggable插件2.引入Draggable插件3.设置一个div&#xff0c;并设置样式&#xff0c;并用Draggable包裹起来4.设置拖拽的范围5.Draggable常用props1.下载Draggable插件 npm install react-draggable2.引入Draggable插件 // 引入拖拽插件…

浅谈指向二维数组元素的指针变量

(1)指向数组元素的指针变量 例1.有一个3X4的二维数组,要求用指向元素的指针变量输出二维数组各元素的值. 编写程序 1 #include <stdio.h>2 int main()3 {4 int a[3][4] { 1,3,5,7,9,11,13,15,17,19,21,23 };5 int *p;6 for (p a[0]; p < a[0] 12; p) …

sni+tomcat漏洞复现

sni SNI产生背景 SSL以及TLS&#xff08;SSL的升级版&#xff09;为客户端与服务器端进行安全连接提供了条件。但是&#xff0c;由于当时技术限制&#xff0c;SSL初期的设计顺应经典的公钥基础设施 PKI(Public Key Infrastructure)设计&#xff0c;PKI 认为一个服务器只为一个…

SpringBoot简单集成OpenFeign

问题 在SpringBoot中简单集成Feign&#xff0c;不想使用Rest Temple了。 步骤 Maven <properties><spring.cloud-version>2022.0.1</spring.cloud-version></properties> <dependencyManagement><dependencies><dependency><g…

javaEE 初阶 — 连接管理机制

文章目录连接管理机制1. 建立连接&#xff08;三次握手&#xff09;2. 断开连接&#xff08;四次挥手&#xff09;TCP 的工作机制确认应答机制 超时重传机制 连接管理机制 比如 主机A 的空间存储了 主机B 的 ip 和 端口&#xff0c;主机B 的空间存储了 主机A 的 ip 和 端口。…

autoCAD2022 - 设置新的原点

文章目录autoCAD2022 - 设置新的原点概述笔记UCS原点设置功能的菜单位置ENDautoCAD2022 - 设置新的原点 概述 上次整板子的dxf时, 原来的原点不合适, 想调整一下. 当时整完了, 没记录. 这次用的时候, 又找半天… 设置新原点的功能, 不在顶部菜单中, 而是在视图右上角的UCS图标…

微服务网关(十二)redis流量统计

微服务网关&#xff08;十二&#xff09;redis流量统计中间件 redis流量统计中间件 redis详细&#xff1a; redis.go: // RedisConfPipline redis连接的设置方法&#xff0c;例如在流量统计中间件中设置数据和超时时间 func RedisConfPipline(pip ...func(c redis.Conn)) e…

Linux 内核定时器实验

目录 一、内核时间管理简介 二、内核定时器简介 三、驱动编写 1、修改makefile 2、添加定义 3、初始化led函数 4、添加调用 5、初始化定时器与定时器处理函数 这部分代码如下 四、ioctl函数 五、内核添加unlocked_ioctl 函数 1、添加设备操作集unlocked_ioctl成员 2…