SpringMVC(三)【REST 风格】

1、REST 风格

1.1、REST 简介

  • REST(Representational State Transfer),表现形式状态转换

        在开发中,它其实指的就是访问网络资源的格式

1.1.1、传统风格资源描述形式

  • http://localhost/user/getById?id=1
  • http://localhost/user/saveUser

1.1.2、REST 风格描述形式

在 REST 风格中,一般用 模块名 + s 的格式描述资源,表示这是一类资源,而不是单个资源。

4 个常用的 REST 风格请求行为

  • http://localhost/users        查询所有用户信息        GET (查询)
  • http://localhost/users/1        查询指定用户信息        GET (查询)
  • http://localhost/users        添加用户信息        POST (新增)
  • http://localhost/users        修改用户信息        PUT (更新)
  • http://localhost/users/1        删除用户信息        DELETE (删除)

        REST 风格下,对于同一个路径,不同的请求代表对资源不同的操作。也就是说,我们只需要一个路径和一个请求方式就可以确定一个访问行为

        根据 REST 风格对资源进行访问称为 RESTful 。

优点

  1. 最大在优点就是隐藏资源的访问行为,无法通过地址得到对资源是如何操作的

注意:REST 风格只是一种风格,并不是一种规范,可以打破。也就是说我们想怎么写就怎么写,但是我们只是希望大家都遵守这种风格,方便开发。

1.2、RESTful 入门案例

        RESTful 就是指使用 REST 风格开发项目。

1.2.1、设定 http 请求动作

        REST 风格下,我们对资源的不同操作由路径请求动作决定,这里的路径我们统一为 模块名 + s,所以我们需要把 Controller 类上面的 @RequsetMapping 中指定的该模块资源的统一前缀去掉。

        添加请求动作只需要先把原本 Controller 类的方法上 RequsetMapping 注解的参数改为 模块名 + s  ,然后通过 method 属性来给方法添加请求动作。

        查询都是 GET、新增是 POST 、修改是 PUT、删除是 DELETE

    @RequestMapping(value = "/users",method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody User user){
        System.out.println("user save,  name = " + user.getName() + " , age = " + user.getAge());
        return "{'module':'user save'}";
    }

         这里的新增用户请求需要传递用户参数,这里我们通过 @RequestBody 注解来表示从请求体中获取参数,也就是通过 json 来传递

1.2.2、设定请求路径参数

        也就是我们控制器类方法上面的注解 @RequsetMapping 中的 value 参数,这里需要根据需求决定需不需要带参数(比如删除 name 为 'zs' 的用户,那就需要指定 value="/users/name" 而不只是模块名+s)。

        此外,对于带有路径变量的请求参数需要给形参前面添加注解 @PathVariable ,表示从请求路径中解析出该变量当做形参的值。

    @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id){
        System.out.println("user deleted ... user id => " + id);
        return "{'module': 'user delete'}";
    }

 完整代码:

@Controller
public class UserController {

    @RequestMapping(value = "/users",method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody User user){
        System.out.println("user save,  name = " + user.getName() + " , age = " + user.getAge());
        return "{'module':'user save'}";
    }

    @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id){
        System.out.println("user deleted ... user id => " + id);
        return "{'module': 'user delete'}";
    }

    @RequestMapping(value = "/users",method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody User user){
        System.out.println("user deleted ... user => " + user.toString());
        return "{'module': 'user update'}";
    }

    @RequestMapping(value = "/users/{id}",method = RequestMethod.GET)
    @ResponseBody
    public String getById(@PathVariable Integer id){
        System.out.println("user get ... user id => " + id);
        return "{'module': 'user get'}";
    }

    @RequestMapping(value = "/users",method = RequestMethod.GET)
    @ResponseBody
    public String getAll(){
        System.out.println("user get all ...");
        return "{'module': 'user get all'}";
    }
}

测试结果:

查询所有用户:

查询 id 为 1 的用户:

新增用户:

 

注意新增用户时我们需要给控制器方法传递一个 User 类型创参数,因为需要使用 jackson 把我们的 json 转为 java 对象,这里要求该对象必须要有无参构造器,不然会报错!

删除用户:

修改用户:
 

1.2.3、请求参数总结

到现在我们共学习了三种请求参数的传递方法:

  1. @RequestBody
  2. @RequestParam(用的比较少)
  3. @PathVariable

1.3、RESTful 快速开发

        这一节我们来对上面的代码进行简化开发,比如所有的控制器方法的前缀都是 "/users" ,所有的控制器方法上面都有一个 @ResponseBody (因为我们不需要返回页面)。

1.3.1、统一路径前缀

        上一节使用 REST 风格后,我们发现所有的请求路径的前缀都是 "/users" + 路径变量,所以既然都有一个前缀 "/users" ,那么为什么不可以都踢出来呢:

@RequestMapping("/users")
public class UserController {
    // ...
}

        这样,对于那些在 REST 风格下路径本来就是 模块名+s("/users")的方法,直接就可以直接省去 @RequestMapping 中的 value 属性,对于请求路径包含路径变量的方法,可以省去前缀,就像这样:

    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    public String delete(@PathVariable Integer id){
        System.out.println("user deleted ... user id => " + id);
        return "{'module': 'user delete'}";
    }

1.3.2、@RestController

        从上一节我们的代码中可以发现,控制器类的方法都带有一个 @ResponseBody ,这是因为因为我们不需要返回页面。所以这里我们可以直接简化把它提到控制器类上面:

@Controller
@ResponseBody
@RequestMapping("/users")
public class UserController {
    // ...
}

        但是 SpringMVC 还是觉得不够简化,它又提供了一个注解 @RestController ,它就相当于同时包含了 @ResponseBody 和 @Controller 两个注解,毕竟控制器类上面肯定是由 @Controller 注解的。所以以后我们直接这么写就行了:

@RestController
@RequestMapping("/users")
public class UserController {
    // ...
}

1.3.2、标准请求动作注解

        经过上一步的简化,我们的 UserController 现在变成了这样:

@RestController
@RequestMapping("/users")
public class UserController {

    @RequestMapping(method = RequestMethod.POST)
    public String save(@RequestBody User user){
        System.out.println("user save,  name = " + user.getName() + " , age = " + user.getAge());
        return "{'module':'user save'}";
    }

    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    public String delete(@PathVariable Integer id){
        System.out.println("user deleted ... user id => " + id);
        return "{'module': 'user delete'}";
    }

    @RequestMapping(method = RequestMethod.PUT)
    public String update(@RequestBody User user){
        System.out.println("user deleted ... user => " + user.toString());
        return "{'module': 'user update'}";
    }

    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    public String getById(@PathVariable Integer id){
        System.out.println("user get ... user id => " + id);
        return "{'module': 'user get'}";
    }

    @RequestMapping(method = RequestMethod.GET)
    public String getAll(){
        System.out.println("user get all ...");
        return "{'module': 'user get all'}";
    }
}

        现在看起来还是很冗余,我们可以对这些方法的请求行为进行进一步简化,现在这么长的参数太扎眼了,现在我们的代码就变成了这样(把 value =  "/{param}" 和  method = RequestMethpd.X 合并到一个注解中):

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public String save(@RequestBody User user){
        System.out.println("user save,  name = " + user.getName() + " , age = " + user.getAge());
        return "{'module':'user save'}";
    }

    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id){
        System.out.println("user deleted ... user id => " + id);
        return "{'module': 'user delete'}";
    }

    @PutMapping
    public String update(@RequestBody User user){
        System.out.println("user deleted ... user => " + user.toString());
        return "{'module': 'user update'}";
    }

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("user get ... user id => " + id);
        return "{'module': 'user get'}";
    }

    @GetMapping
    public String getAll(){
        System.out.println("user get all ...");
        return "{'module': 'user get all'}";
    }
}

显然一下子变得清新脱俗!舒服多了。

1.4、基于 RESTful 页面数据交互

  实体类

package com.lyh.domain;

public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;

    public Book(){}

    public Book(Integer id, String type, String name, String description) {
        this.id = id;
        this.type = type;
        this.name = name;
        this.description = description;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", type='" + type + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

SpringMVC 配置类

@Configuration
@ComponentScan("com.lyh.controller") // 扫描
@EnableWebMvc // 开启 json 转对象的功能等各种格式转换
public class SpringMvcConfig {

}

Sevlet 容器配置类

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // 乱码处理
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

BookController 控制器类

@RestController
@RequestMapping("/books")
public class BookController {


    @PostMapping
    public String save(@RequestBody Book book){
        System.out.println("book save ... book => " + book.toString());
        return "{'module':'book save'}";
    }

    @GetMapping
    public List<Book> getAll(){
        List<Book> list = new ArrayList<Book>();
        list.add(new Book(1,"编程","《图解Spark》","大数据技术"));
        list.add(new Book(2,"小说","《黄金时代》","王小波著作"));
        return list;
    }
}

测试

        导入静态资源后访问 localhost:85/pages/boos.html 发现报错找不到映射:No Mapping for GET /pages/books.html 这是因为我们现在的请求都被 SpringMVC 拦截走了,其实这些静态资源应该是由 Tomcat 处理的。

1.4.1、放行非 SpringMVC 请求

        上面的问题是对于静态资源的访问,本该是由 Tomcat 处理,但是前面我们在 Servlet 配置类中设置了所有请求都由 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/");
        }
}

        然后,我们需要让 SpringMVC 去加载这个新的配置类:

这样就可以访问到了:

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

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

相关文章

18 统计网站每日的访问次数

1.将竞赛的数据上传HDFS,查看数据的格式 通过浏览器访问hdfs,查看该文档前面的部分数据 每条数据的字段值之间使用逗号隔开的 &#xff0c;最终时间是第五个自动&#xff0c;获取第五个字段值的中的年月日。 2.通过Idea创建项目mr-raceData ,基础的配置 修改pom.xml,添加依赖 …

一文读懂uniapp中的tabBar底部导航

目录 1. 基本知识2. Demo 1. 基本知识 UniApp 中的 tabBar 是用来在应用程序底部显示可切换的选项卡的组件&#xff0c;通常用于实现底部导航栏 允许用户通过点击不同的选项卡来切换应用程序的不同页面或功能模块 其代码如下&#xff1a; "tabBar":{"color&q…

HoloLens2的Unity应用在电脑上发布成安装包,然后通过wifi安装到设备

一、VS工程中的鼠标右键 二、发布——>创建应用程序包 三、选择【旁加载】 四、选择签名方法&#xff1a; 五、选择和配置包 六、创建完毕 七、网络连接设备 八、登录设备 九、安装app

spring高级篇(二)

1、Aware和InitializingBean Aware和InitializingBean都与Bean的生命周期管理相关。 Aware接口: 概念: Aware接口是Spring框架中的一个标记接口&#xff0c;它表示一个类能够感知到&#xff08;aware of&#xff09;Spring容器的存在及其特定的环境。Spring框架提供了多个Awar…

Android自带模拟器如何获得ROOT权限

如果在模拟器中不能切换到root权限&#xff0c;很可能是镜像使用的不对。 一.选择镜像标准&#xff1a; 1.运行在PC端选X86_64镜像&#xff0c;才能流畅运行 2.不带google api的镜像 二.步骤 在虚拟机管理器中新建AVD&#xff0c;并下载符合要求的镜像文件 三.验证

shell脚本编程的例子(55例子)-3

第三部分&#xff1a;eg32-eg50shell例子。开放一周后启用vip阅读了。…… ^v^ Eg32、while/until/for经典例子 #!/bin/bash ## filename: while-infinite_loops.sh while true; do sleep 5 echo "infinite loops [ hit CTRLC to stop]" done Eg33、while/…

Rokid AR Lite空间计算套装发布,软硬件全面升级推动居家、出行、户外场景大规模应用

4月20日&#xff0c;以“好玩、好看、好上头”为主题的Rokid Open Day 2024发布会在杭州举行&#xff0c;Rokid对外正式发布新一代AR Lite空间计算套装&#xff0c;分享了近期Rokid在AR开发者生态和数字文化领域的进展和成果&#xff0c;并宣布了多项跨行业重磅合作。作为中国代…

PS-ZB转座子分析流程2-重新分析并总结

数据处理 数据质控 随机挑出九个序列进行比对&#xff0c;结果如下&#xff1a; 所有序列前面的部分序列均完全相同&#xff0c;怀疑是插入的转座子序列&#xff0c;再随机挑选9个序列进行比对&#xff0c;结果如下&#xff1a; 结果相同&#xff0c;使用cutadapt将该段序列修…

OerOerlikonTCO1200欧瑞康LPCVD system操作使用说明

OerOerlikonTCO1200欧瑞康LPCVD system操作使用说明

常见的经典目标检测算法

目标检测是计算机视觉领域的一个核心任务&#xff0c;它涉及到识别图像中的物体并确定它们的位置。以下是一些常见的经典目标检测算法&#xff1a; R-CNN系列 R-CNN&#xff08;Region-based Convolutional Neural Network&#xff09;是一种用于目标检测的算法&#xff0c;它…

PyQt5开发的DSP信号仿真系统

PyQt5开发的DSP信号仿真系统 1、效果图 2、功能 具备的功能: 1、生成基础信号波形[正弦波,脉冲函数,阶跃函数,斜坡函数, 锯齿波,方波,常见非周期波形,sinc函数] 2、各基础波形可以叠加 3、可展示FFT频谱、信号卷积、功率频谱密度估计 4、可以读取音频信号及分析 5、各…

第23天:安全开发-PHP应用后台模块SessionCookieToken身份验证唯一性

第二十三天 一、PHP后台身份验证模块实现 二、Cookie&Session技术&差异 1.生成cookie的原理图过程&#xff1a;见上图 客户端向服务器发送HTTP请求。服务器检查请求头中是否包含cookie信息。如果请求头中包含cookie信息&#xff0c;则服务器使用该cookie来识别客户端…

Android Studio Iguana | 2023.2.1配置优化

一. 前言 本篇文章记录最新版本的Android Studio的配置优化&#xff0c;写这篇文章的是由于电脑中的AS工具更新版本覆盖安装后&#xff0c;AS会经常卡死&#xff0c;Debug的时候也经常莫名其妙的断掉&#xff0c;非常影响工作效率&#xff0c;所以重新把配置环境整理一下&#…

保姆级教程!QRCNN-BiLSTM一键实现多变量回归区间预测!区间预测全家桶再更新!

​ 声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 今天对我们之前推出的区间预测全家桶进行…

详解数据在内存中的存储

系列文章目录 第一章 C语言基础知识 第二章 C语言控制语句 第三章 C语言函数详解 第四章 C语言数组详解 第五章 C语言操作符详解 第六章 C语言指针详解 第七章 C语言结构体详解 文章目录 1. 数据类型 1.1 基本数据类型 1.2 派生数据类型 2. 整形在内存中的存储 2.1 …

AOP基础-动态代理

文章目录 1.动态代理1.需求分析2.动态代理的核心3.代码实例1.Vehicle.java2.Car.java3.Ship.java4.VehicleProxyProvider.java(动态代理模板)5.测试使用 2.动态代理深入—横切关注点1.需求分析2.四个横切关注点3.代码实例1.Cal.java2.CalImpl.java3.VehicleProxyProvider02.jav…

第 2 章:FFmpeg简介

2.1 历史 历史 一些相关术语介绍&#xff1a; 容器&#xff08;Container&#xff09;格式&#xff1a;一种文件封装格式&#xff0c;里边主要包含了流&#xff0c;一般会使用一个特定的后缀名标识&#xff0c;例如.mov、.avi、.wav等。流 &#xff08;Stream&#xff09;&am…

大语言模型隐私防泄漏:差分隐私、参数高效化

大语言模型隐私防泄漏&#xff1a;差分隐私、参数高效化 写在最前面题目6&#xff1a;大语言模型隐私防泄漏Differentially Private Fine-tuning of Language Models其他初步和之前的基线微调模型1微调模型2通过低秩自适应进行微调&#xff08; 实例化元框架1&#xff09; 在隐…

pta L1-063 吃鱼还是吃肉

L1-063 吃鱼还是吃肉 分数 10 全屏浏览 切换布局 作者 陈越 单位 浙江大学 国家给出了 8 岁男宝宝的标准身高为 130 厘米、标准体重为 27 公斤&#xff1b;8 岁女宝宝的标准身高为 129 厘米、标准体重为 25 公斤。 现在你要根据小宝宝的身高体重&#xff0c;给出补充营养的…

浅谈 刷算法题时遇到运行超时异常 的解决办法

文章目录 一、背景介绍二、解决办法2.1 C/C 语言2.2 Java 语言2.2.1 ACM模式下 Java的I/O原理 三、模板详情 一、背景介绍 最近在牛客、leetcode 刷算法题时发现一个奇怪的问题&#xff0c;明明解题思路、所用算法与题解一致&#xff0c;并且在本地IDE运行是通过的&#xff0c…