前言
Spring MVC是一种常用的Web框架,它可以帮助开发人员快速构建可扩展的Web应用程序。为了提供更好的开发体验和更高的代码效率,Spring MVC提供了各种注解。这些注解可以用于控制器、请求参数、响应类型、表单数据验证、异常处理等方面。在本文中,我们将介绍Spring MVC中常用的注解及使用方式。了解这些注解的作用,可以帮助我们更好地理解Spring MVC框架的工作原理,进而提高我们的开发效率。
文章目录
- 前言
- 1 Spring MVC 简介
- 2 Spring MVC 创建与连接
- 2.1 创建一个 Spring MVC 项目
- 2.2 @RequestMapping 注解
- 2.2.1 @RequestMapping 基本使用
- 2.2.2 GET 请求 还是 POST 请求?
- 2.2.3 @GetMapping 与 @PostMapping
- 3 获取参数
- 3.1 传递单个参数/多个参数
- 3.2 传递对象
- 3.3 后端参数重命名(@RequestParam 参数映射)
- 3.4 @RequestParam 参数必传设置
- 3.5 @RequestBody 接收JSON对象
- 3.6 @PathVariable 获取URL中参数
- 3.7 @RequestPart 上传⽂件
- 3.8 获取Cookie/Session/header
- 4 返回数据
- 4.1 返回静态页面
- 4.2 返回 text/html
- 4.3 返回 JSON 对象
- 4.4 请求重定向与请求转发
- 4.5 组合注解:@RestController
- 写在最后
1 Spring MVC 简介
什么是 MVC?
MVC是一种软件架构模式,它分为三个部分:模型(Model)、视图(View)和控制器(Controller)。它的主要思想是将应用程序分成三个主要的部分:模型(数据和业务逻辑)、视图(用户界面)和控制器(请求处理器),以实现分离关注点和松散耦合。通过这种分层架构,可以更好地维护和扩展应用程序,并且使应用程序更易于测试和设计。
Spring MVC 又是什么?
Spring MVC是一个基于Java的Web框架,用于构建Web应用程序。它是Spring框架的一部分,具有灵活性、可扩展性和强大的可配置性。Spring MVC通过使用MVC(模型-视图-控制器)设计模式来分离应用程序的不同层。
模型层代表数据或业务逻辑,视图层代表UI元素,控制器层充当这两个层之间的中介。这种分离允许更好的模块化和易于维护的代码。Spring MVC还提供了丰富的特性,如表单处理、文件上传、安全性、国际化和验证,可以方便地集成到Web应用程序中。总的来说:
- Spring MVC 是⼀个 Web 框架。
- Spring MVC 是基于 Servlet API 构建的。
如何学 Spring MVC?
对于 Spring MVC 来说,掌握了以下 3 个功能就相当于掌握了 Spring MVC。
- 连接的功能: 将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的
Spring 程序。 - 获取参数的功能: ⽤户访问的时候会带⼀些参数,在程序中要想办法获取到参数。
- 输出数据的功能: 执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤户。
2 Spring MVC 创建与连接
2.1 创建一个 Spring MVC 项目
Spring MVC项目的创建方式不唯一,这里使用基于Spring Boot的方式快速搭建 Spring MVC环境。也就是在创建Spring Boot项目的时候,勾选上Spring Web模块。
2.2 @RequestMapping 注解
@RequestMapping 注解是 Spring MVC 框架中最常用的注解之一,它是⽤来注册接⼝的路由映射的。
路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类的某个⽅法的过程就叫路由映射。
它可以用于类级别和方法级别上。在类级别上,可以设置一个基础 URL 映射,以便在方法级别上定义特定的请求路径。在方法级别上,可以定义处理请求的具体行为和方法参数等。
@RequestMapping
注解有多种参数设置,例如:
- value: 指定该方法处理的请求 URL,可以是一个字符串数组,支持占位符。
- method: 指定该方法处理的请求方法,比如 GET、POST 等。
- params:指定必须包含的参数及其值,用于限定请求的条件。
- headers:指定必须包含的请求头及其值,用于限定请求的条件。
- consumes:指定请求的 Content-Type,用于限定请求的条件。
- produces:指定响应的 Content-Type,用于限定响应的条件。
通过这些参数设置,我们可以更加精确地控制请求的映射和处理,从而实现不同的业务逻辑。
2.2.1 @RequestMapping 基本使用
@RequestMapping 既可以用在类上,也可以用在方法上。当二者都添加上该注解时,访问地址就是 类 + 方法
接下来,我们实现的功能是 访问地址:http://localhost:8080/user/hi,能够打印 “Hello, 黄小黄~” 信息。
创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通,具体实现代码如下:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller // Spring 启动时加载
@ResponseBody // 返回非页面数据
@RequestMapping("/user") // 路由规则注册
public class UserController {
// 路由规则注册
@RequestMapping("/hi")
public String sayHello() {
return "Hello, 黄小黄~";
}
}
2.2.2 GET 请求 还是 POST 请求?
这里直接说结论,默认情况下,@RequestMapping 注解既可以接收 GET请求,又可以接收 POST请求。如果需要指定接收请求方式,则需要对 method 参数进行指定 GET/POST ⽅法类型。
指定接收 POST 请求
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller // Spring 启动时加载
@ResponseBody // 返回非页面数据
@RequestMapping("/user") // 路由规则注册
public class UserController {
// 指定 POST
@RequestMapping(value = "/showPost", method = RequestMethod.POST)
public String showPost() {
return "接收到了 POST 请求~";
}
}
2.2.3 @GetMapping 与 @PostMapping
SpringMVC同时提供了 @GetMapping 与 @PostMapping注解,分别对应接收请求 GET类型 与 POST类型。以下代码演示了指定接收GET请求:
// 指定 GET
@GetMapping("/showGet")
public String showGet() {
return "接收到了 GET 请求~";
}
3 获取参数
3.1 传递单个参数/多个参数
在 Spring MVC 中,可以直接使用方法中的参数列表来实现参数的传递,示例代码如下:
// 传递单个参数
@GetMapping("/method01")
public String method01(int num) {
return "num: " + num;
}
可以看到,参数正常的传递过去了。
但是,对于基本数据类型来说,有坑点! 如果忘记传参数呢?
可以看到,服务器返回500状态码。如何解决呢?我们可以对于所有的基本数据类型,采用包装类的方式传递参数, 示例代码如下:
// 传递单个参数
@GetMapping("/method02")
public String method02(Integer num) {
return "num: " + num;
}
这样,如果前端忘记传递参数,只会返回 null。问题就很清晰:是因为忘记传递 num 值造成的~
如何传递多个参数?
只需要增加方法参数列表的参数即可。当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置是不影响后端获取参数的结果。
3.2 传递对象
Spring MVC中,可以自动实现参数传递的赋值。例如,传递一个 Student 对象:
import lombok.Data;
@Data
public class Student {
private String name;
private String password;
}
传递对象代码实现:
// 传递对象
@GetMapping("/student")
public String showStudent(Student student) {
String name = student.getName();
String password = student.getPassword();
return name + " : " + password;
}
3.3 后端参数重命名(@RequestParam 参数映射)
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致, ⽐如前端传递了⼀个 name 给后端,⽽后端⼜是有 curName 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使⽤ @RequestParam
来重命名前后端的参数值。示例代码如下:
// 参数映射
@GetMapping("/para")
public String showCurName(@RequestParam("name") String curName) {
return "curName = " + curName;
}
这时,即使前端传过来的参数是 name, 也可以正常映射了:
3.4 @RequestParam 参数必传设置
上述例子中,如果传递一个非 name 值,就会出现如下错误:
这是什么原因呢?通过查看 @RequestParam
注解的实现细节就可以发现端倪:
可以看到,required 默认为 true,即不传递该参数会报 400 错误。
设置非必传参数
只需要设置 @RequestParam 中的 required=false 来避免不传递时报错:
// 参数映射
@GetMapping("/para")
public String showCurName(@RequestParam(value = "name", required = false) String curName) {
return "curName = " + curName;
}
3.5 @RequestBody 接收JSON对象
// 传递 JSON
@PostMapping("/set-student")
public String setStudent(@RequestBody Student student) {
System.out.println(student);
return "Student Set Success.";
}
使用 PostMan 构造 JSON 传递给后端:
3.6 @PathVariable 获取URL中参数
有时,参数并不是以 name=xxx&password=xxx 形式传递的。
例如:http://localhost:8080/user/login/黄小黄/123123
其中,黄小黄表示name的值,123123表示password的值。这种情况我们该如何获取参数呢?可以使用 @PathVariable
实现,后端实现代码:
// 获取 URL 中的参数
@GetMapping("/login/{name}/{password}")
public String login(@PathVariable String name, @PathVariable String password) {
return "name = " + name + "<br>" +
"password = " + password + "<br>" +
"Login Success.";
}
3.7 @RequestPart 上传⽂件
@RequestPart 注解可以用于处理multipart/form-data类型的请求,常用于上传文件。可以将该注解与@RequestBody注解合并使用,用于传递文件和其他表单数据。例如:
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
// 处理文件上传的逻辑
return "success";
}
这里@RequestParam(“file”)表示从请求中获取名为"file"的文件,上传的文件将被存储在MultipartFile对象中。我们可以使用MultipartFile对象的方法来处理上传的文件。
案例:上传一个图片到本机的某个目录
// 上传文件Demo
@RequestMapping("/upFile")
public String upFile(@RequestParam("myFile") MultipartFile file) throws IOException {
// 上传的路径根目录
String path = "D:\\info\\";
// 路径+【唯一文件名】
path += UUID.randomUUID().toString().replace("-", "");
// 路径+文件名+【后缀】
path += file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
// 保存文件
file.transferTo(new File(path));
return path + "上传成功!";
}
3.8 获取Cookie/Session/header
传统获取 header/cookie
// 传统获取 header/cookie
@RequestMapping("/method04")
public String method04(HttpServletRequest req, HttpServletResponse resp) {
String name = req.getParameter("name");
// 获取所有 Cookie 信息
Cookie[] cookies = req.getCookies();
// 获取 header 信息
String userAgent = req.getHeader("User-Agent");
return name + " : " + userAgent;
}
@CookieValue 获取 cookie
// @CookieValue 获取 Cookie
@RequestMapping("/cookie")
public String cookie(@CookieValue("name") String name) {
return "cookie: " + name;
}
@RequestHeader 获取 header
// @RequestHeader 获取 header
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent) {
return "User-Agent: " + userAgent;
}
Session 可以使⽤ HttpServletRequest,如下代码所示:
@RequestMapping("/sess1")
public String sess1(HttpServletRequest req) {
// 如果 session 不存在, 不会自动创建
HttpSession session = req.getSession(false);
String username = "默认值";
if (session != null && session.getAttribute("username") != null) {
username = (String) session.getAttribute("username");
}
return username;
}
获取 Session 简洁方式
// 更简洁方式获取 Session
@RequestMapping("/sess2")
public String sess2(@SessionAttribute(value = "username", required = false) String username) {
return username;
}
4 返回数据
4.1 返回静态页面
创建一个静态页面 index.html
创建控制器,并实现相应的方法:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
// 返回静态页面
@RequestMapping("/index")
public Object index() {
// 执行业务
// 返回 View -> index.html
return "/index.html";
}
}
4.2 返回 text/html
// 返回 test/html
@RequestMapping("/method1")
@ResponseBody
public String method1() {
return "<h1>Hello, world!</h1>";
}
4.3 返回 JSON 对象
在下面的示例中,@ResponseBody
注解告诉 SpringMVC 将返回的 Map 对象转换成 JSON 对象,并将其作为 HTTP 响应返回给客户端。
@RequestMapping("/method2")
@ResponseBody
public Map<String, String> method2() {
Map<String, String> map = new HashMap<>();
map.put("黄小黄", "111");
map.put("蒲小七", "777");
return map;
}
4.4 请求重定向与请求转发
return 不但可以返回⼀个视图,还可以实现跳转,跳转的⽅式有两种:
- forward 是请求转发;
- redirect 是请求重定向。
示例代码如下:
// 请求重定向
@RequestMapping("/index1")
public String index1() {
return "redirect:/index.html";
}
// 请求转发
@RequestMapping("/index2")
public String index2() {
return "forward:/index.html";
}
请求转发与请求重定向的区别?
-
请求转发是在服务器内部完成的,客户端浏览器只发出了一次请求,服务器接收到请求后直接将请求转发给另一个资源进行处理, 这个过程对于浏览器来说是透明的;而请求重定向是客户端发出了两次请求,第一次请求得到服务器响应后,服务器会告诉浏览器要转向到新的资源,浏览器收到响应后会再次发起请求。
-
对于请求转发,客户端浏览器地址栏不会改变,仍然是原来的地址;而请求重定向会将地址栏改变为新的地址。
-
请求转发使用的是forward方法,它只能在同一个Web应用程序内部实现;而请求重定向使用的是sendRedirect方法,它可以实现跨域跳转。
-
请求转发是在服务器内部进行的,因此可以共享同一个request域中的数据,而请求重定向是两个完全独立的请求,不能共享request域中的数据。
-
请求重定向与直接访问新地址效果一致,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。
4.5 组合注解:@RestController
@RestController = @Controller + @ResponseBody
- @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端。
- @ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者 json,⽽不是视图。
更多注解:https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html
写在最后
本文被 JavaEE编程之路 收录点击订阅专栏 , 持续更新中。
以上便是本文的全部内容啦!创作不易,如果你有任何问题,欢迎私信,感谢您的支持!