正确使用@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

相关文章

Redis 的 SUBSCRIBE命令详解

《Redis的SUBSCRIBE命令详解》Redis的SUBSCRIBE命令用于订阅一个或多个频道,以便接收发送到这些频道的消息,本文给大家介绍Redis的SUBSCRIBE命令,感兴趣的朋友跟随... 目录基本语法工作原理示例消息格式相关命令python 示例Redis 的 SUBSCRIBE 命令用于订

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完