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

2024-04-15 10:36

本文主要是介绍正确使用@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

这篇关于正确使用@RequestMapping(包含属性详解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/905575

相关文章

Linux线程同步/互斥过程详解

《Linux线程同步/互斥过程详解》文章讲解多线程并发访问导致竞态条件,需通过互斥锁、原子操作和条件变量实现线程安全与同步,分析死锁条件及避免方法,并介绍RAII封装技术提升资源管理效率... 目录01. 资源共享问题1.1 多线程并发访问1.2 临界区与临界资源1.3 锁的引入02. 多线程案例2.1 为

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

全面解析Golang 中的 Gorilla CORS 中间件正确用法

《全面解析Golang中的GorillaCORS中间件正确用法》Golang中使用gorilla/mux路由器配合rs/cors中间件库可以优雅地解决这个问题,然而,很多人刚开始使用时会遇到配... 目录如何让 golang 中的 Gorilla CORS 中间件正确工作一、基础依赖二、错误用法(很多人一开

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件