正确使用@RequestMapping(包含属性详解)

目录

  • 一、基本认知
  • 二、@RequestMapping的基本使用
  • 三、深入学习@RequestMapping
    • 1、@RequestMapping的源码
    • 2、@RequestMapping的属性
      • 2.1 path
      • 2.2 method
      • 2.3 params
      • 2.4 headers
      • 2.5 consumes
      • 2.6 produces
      • 2.7 name

一、基本认知

  • 客户端发起Http请求,会提供一个URL [协议://域名{/path}]。
    在这里插入图片描述
    • 协议通常是https
    • 域名,例如:kimi.moonshot.cn
    • 路径(path),例如:/api/chat/co96gbrdf0j519t5at0g/completion/stream
  • 通过域名和端口(https的默认端口是443)可以定位服务器的进程。
  • 通过路径来确定由进程的哪个方法来处理请求。【这个是本文的重点,也是@RequestMapping发光发热的领域】

二、@RequestMapping的基本使用

  • 示例:
@RestController
@RequestMapping("/api/chat")
public class ChatController {@PostMapping("/{chatId}/completion/stream")public String completionStream(@PathVariable String chatId, @RequestBody ChatInput chatInput) {return "/" + chatId + "/completion/stream : " + chatInput.getPrompt();}
}
curl 'http://127.0.0.1:8080/api/chat/co96gbrdf0j519t5at0g/completion/stream' \
-H 'Content-Type: application/json' \
-d '{"prompt": "你好~"
}'
/co96gbrdf0j519t5at0g/completion/stream : 你好~
  • Http请求的路径(/api/chat/co96gbrdf0j519t5at0g/completion/stream)由ChatController.completionStream方法来处理了。

三、深入学习@RequestMapping

1、@RequestMapping的源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {String name() default "";@AliasFor("path")String[] value() default {};@AliasFor("value")String[] path() default {};RequestMethod[] method() default {};String[] params() default {};String[] headers() default {};String[] consumes() default {};String[] produces() default {};
}

2、@RequestMapping的属性

2.1 path

  • 示例:
@RequestMapping("/api/chat")
public class ChatController {@PostMapping("/{chatId}/completion/stream")public String completionStream(@PathVariable String chatId, @RequestBody ChatInput chatInput) {...}
  • 没有指定属性,直接填属性值。相当于:value=“xxx”。根据@RequestMapping的定义可知,value和path是等价的。(@AliasFor的作用)
  • 我们在类上设定了path(/api/chat),这是完整path的前缀,即:/api/chat/xxx。
  • 我们在方法上设定“xxx”(/{chatId}/completion/stream),如果使用了占位符{a},那么可以在入参中,通过注解@PathVariable来获取。
  • SpringMVC会根据Http请求的URL的路径(/api/chat/co96gbrdf0j519t5at0g/completion/stream)来找到对应的处理方法(ChatController.completionStream)。【path属性的核心作用

2.2 method

  • Http请求,不仅有URL,还有方法,常用的是:GET、POST。
  • 示例:
@RequestMapping("/api/chat")
public class ChatController {...@RequestMapping(path = "/hello", method = RequestMethod.GET)public String sayHello() {return "hello world!";}@RequestMapping(path = "/hello", method = RequestMethod.POST)public String sayHello(@RequestBody ChatInput chatInput) {return "Hello: " + chatInput.getPrompt();}...
}
  • 如果路径都是/api/chat/hello,SpringMVC就搞不清楚到底要映射到哪个Java方法上了。这时候,可以进一步设置method属性。
  • method属性的核心作用:通过设定请求方法,进一步来明确映射到哪个Java方法上。
  • 实际开发中,一般不设定method属性,而是直接用对应的xxxMapping。
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping@GetMapping为例,无非就是指定了method的@RequestMapping而已
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = {RequestMethod.GET}
)
public @interface GetMapping {...
}

2.3 params

  • 我们见过这样的URL:http://127.0.0.1:8080/api/chat/hi?name=Forrest&age=18
    • ?后面的kv对(name=Forrestage=18)便是参数名=参数值,并用&进行连接。
  • 那怎么让SpringMVC识别这种路径,并映射到一个Java方法呢?
  • 这就要用到params属性了,示例:
@GetMapping(path = "/hi", params = "name")
public String sayHi(@RequestParam String name, @RequestParam Integer age) {return "Hi: " + name + "; 刚好" + age + "岁~";
}
  • 咦,咋只涉及name,而没有age?
    • 这个的含义是:路径是/api/chat/hi?xxx,xxx必须包含name,才会映射到sayHi方法。然后这个方法的入参有@RequestParam Integer age,因此,路径中也必须包含age参数。
      在这里插入图片描述
  • params属性的核心作用:根据路径中的参数,进一步来明确映射到哪个Java方法上。
  • 有4种表达方式:
    • params = "chatId":参数中必须包含chatId。
    • params = "!chatId":参数中不包含chatId。
    • params = "manager=Forrest":manager参数等于Forrest
    • params = "manager!=Forrest":manager参数不等于Forrest
  • 示例:
// 用户传了chatId,那就查这个chatId信息
@GetMapping(path = "/chatIds", params = "chatId")
public String gotChatId(@RequestParam String chatId) {return "chatId: " + chatId;
}// 用户没指定某个chatId,那就查所有chatId信息
@GetMapping(path = "/chatIds", params = "!chatId")
public String gotChatId() {return "chatIdList";
}
@GetMapping(path = "/administrator", params = "manager=Forrest")
public String gotManager() {return "manager=Forrest";
}@GetMapping(path = "/administrator", params = "manager!=Forrest")
public String gotEmployee() {return "manager!=Forrest";
}/*
很鸡肋,完全可以接受一个maneger参数,在方法中来做特殊处理。
@GetMapping(path = "/employee")
public String gotEmployee(@RequestParam String name) {if (name != null && name.equals("Forrest")) {// 领导return "leader";} else {// 员工return "employee";}
}*/

2.4 headers

  • headers属性的核心作用:通过Http的请求头,过滤出满足条件的请求。
@GetMapping(path = "/login", headers = "Host=127.0.0.1:8080")
public String login() {return "login";
}

在这里插入图片描述

  • 如果Host不是127.0.0.1:8080,那么Spring MVC就不会让login方法进行处理。

2.5 consumes

  • consumes属性的核心作用:要求请求体必须是某种媒体类型。
  • 示例:
@PostMapping(path = "/stream", consumes = MediaType.APPLICATION_JSON_VALUE)
public String stream(@RequestBody ChatInput chatInput) {return "stream: " + chatInput.getPrompt();
}
  • 如果用户传入的请求体不是json,那么会报错:
{"timestamp": "2024-04-14T09:53:43.430+00:00","status": 415,"error": "Unsupported Media Type","path": "/api/chat/stream"
}
  • 是json格式,才能正常处理:
    在这里插入图片描述
  • 当然了,也可以用!,表示请求体不能是某种类型。
  • 示例:
@PostMapping(path = "/plainStream", consumes = "!" + MediaType.APPLICATION_JSON_VALUE)
public String stream(@RequestBody  String prompt) {return "stream: " + prompt;
}
  • 当请求体为json格式时:
    在这里插入图片描述
  • 当请求体为不是json格式时,可以正常调用:
    在这里插入图片描述

如果没设置consumes,就可以:
在这里插入图片描述

  • 怎么判断请求体的类型呢?–> Content-Type
    在这里插入图片描述

2.6 produces

  • 有些客户端对服务器返回的内容类型有要求,如果不满足这个要求,那也没必要处理了。
  • produces属性的核心作用:通过请求头的Accept,判断是否包含返回的内容类型。包含则处理该请求。
  • 示例:
@GetMapping(path = "/completion", produces = MediaType.APPLICATION_JSON_VALUE)
public ChatOutput completion() {return new ChatOutput("你好啊~");
}@Data
@AllArgsConstructor
public class ChatOutput {private String completion;
}
  • 当客户端发送Http请求,并且请求头的Accept为text/plain时,会报错:
    在这里插入图片描述

服务端报错:Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]

  • 自定义异常处理器,让提示友好点~
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)@ResponseBodypublic ResponseEntity<Map<String, String>> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex) {Map<String, String> responseBody = new HashMap<>();responseBody.put("message", "Unsupported media type. Please accept JSON format.");return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).contentType(MediaType.APPLICATION_JSON).body(responseBody);}
}

在这里插入图片描述

  • 我们将请求头的Accept改为application/json,便能被服务端正常处理了:
    在这里插入图片描述

默认情况下:请求头的Accept为*/*

  • 还可以指定编码方式:@GetMapping(path = "/completion", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

public static final String APPLICATION_JSON_UTF8_VALUE = “application/json;charset=UTF-8”;

2.7 name

为啥把这个属性放到最后?并不是last but not least,而是这个属性真不重要。

  • 相当于对方法的注释。
  • 但实际开发中,一般用的是swagger提供的注解 @ApiOperation

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

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

相关文章

做一个后台项目的架构

后台架构的11个维度 架构1&#xff1a;团队协助基础工具链的选型和培训架构2&#xff1a;搭建微服务开发基础设施架构3&#xff1a;选择合适的RPC框架架构4&#xff1a;选择和搭建高可用的注册中心架构5&#xff1a;选择和搭建高可用的配置中心架构6&#xff1a;选择和搭建高性…

Qt快速入门(MV架构之TableView + QStandardItemModel + 自定义代理小案例)

Qt快速入门&#xff08;MV架构之TableView QStandardItemModel 自定义代理小案例&#xff09; 关于MV架构的简单介绍 在Qt框架中&#xff0c;代理&#xff08;Delegate&#xff09;、模型&#xff08;Model&#xff09;和视图&#xff08;View&#xff09;之间的关系构成了…

Kafka 架构深入探索

目录 一、Kafka 工作流程及文件存储机制 二、数据可靠性保证 三 、数据一致性问题 3.1follower 故障 3.2leader 故障 四、ack 应答机制 五、部署FilebeatKafkaELK 5.1环境准备 5.2部署ELK 5.2.1部署 Elasticsearch 软件 5.2.1.1修改elasticsearch主配置文件 5.2…

OpenHarmony实战开发-FaultLoggerd组件。

简介 Faultloggerd部件是OpenHarmony中C/C运行时崩溃临时日志的生成及管理模块。面向基于 Rust 开发的部件&#xff0c;Faultloggerd 提供了Rust Panic故障日志生成能力。系统开发者可以在预设的路径下找到故障日志&#xff0c;定位相关问题。 架构 Native InnerKits 接口Sig…

Node.js 并发控制

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;它使得 JavaScript 可以脱离浏览器在服务器端运行。由于 Node.js 采用单线程异步非阻塞 I/O 模型&#xff0c;它的并发处理能力也是非常强大的。本文将详细介绍 Node.js 的并发原理、概念、图解、解决方案…

Android 车载应用开发概述

前言 介绍 Android 车载应用开发 文章目录 前言一、Android Automotive OS 概述二、Android Automotive OS 架构三、常见的车载应用1、系统应用1&#xff09;SystemUI是什么开发工作 2&#xff09;Launcher是什么开发工作 3&#xff09;Settings是什么开发工作 4&#xff09;多…

AI克隆语音(基于GPT-SoVITS)

概述 使用GPT-SoVITS训练声音模型&#xff0c;实现文本转语音功能。可以模拟出语气&#xff0c;语速。如果数据质量足够高&#xff0c;可以达到非常相似的结果。相比于So-VITS-SVC需要的显卡配置更低&#xff0c;数据集更小&#xff08;我的笔记本NVIDIA GeForce RTX 4050 Lap…

Android Gradle 开发与应用 (七) : 实现打包自动复制文件插件

1. 前言 项目中遇到了一个问题 : 其中一个模块MyLibrary的assets文件夹中,需要存放很多文件(每个文件对应一个功能)。 这样导致的问题是MyLibrary打出的这个aar包体积特别大。 如果把MyLibrary严谨地拆解成若干个Module又比较费时,对于现在业务现状来说也显得没那么必要。…

ruoyi单体+react+antdesign

基于ruoyi vue和Ruoyi-React实现的快速开发工具。 源码地址&#xff1a;GitHub - hebian1994/ruoyi-react-single: use ruoyi to generage java backend code and reacr front end code 前端&#xff1a;基于ant-design-pro 后端&#xff1a;单体springboot项目(非cloud)mysq…

shell 调用钉钉通知

使用场景&#xff1a;机器能访问互联网&#xff0c;运行时间任务后通知使用 钉钉建立单人群 手机操作&#xff0c;只能通过手机方式建立单人群 电脑端 2. 配置脚本 #!/bin/bash set -e## 上图中 access_token字段 TOKEN KEYWORDhello # 前文中设置的关键字 function call_…

【GD32】AD9833模块 DDS模块 提供测试程序 正弦波/方波/三角波信号发生器

2.45 AD9833 DDS模块 2.45.1 模块来源 采购链接&#xff1a; AD9833模块 DDS模块 提供测试程序 正弦波/方波/三角波信号发生器 资料下载&#xff1a; https://pan.baidu.com/s/1JZ0ga4uTyXUq5u-Or9BVlg?pwdGOOD 提取码&#xff1a;GOOD 2.45.2 规格参数 工作电压&#xff1…

大模型面试准备(十八):使用 Pytorch 从零实现 Transformer 模型

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何备战、面试常考点分享等热门话题进行了深入的讨论。 合集在这…