【Spring MVC】Spring MVC程序开发教程:常见的注解及使用方式详情

前言

 Spring MVC是一种常用的Web框架,它可以帮助开发人员快速构建可扩展的Web应用程序。为了提供更好的开发体验和更高的代码效率,Spring MVC提供了各种注解。这些注解可以用于控制器、请求参数、响应类型、表单数据验证、异常处理等方面。在本文中,我们将介绍Spring MVC中常用的注解及使用方式。了解这些注解的作用,可以帮助我们更好地理解Spring MVC框架的工作原理,进而提高我们的开发效率。
表情包



1 Spring MVC 简介

什么是 MVC?
MVC是一种软件架构模式,它分为三个部分:模型(Model)、视图(View)和控制器(Controller)。它的主要思想是将应用程序分成三个主要的部分:模型(数据和业务逻辑)、视图(用户界面)和控制器(请求处理器),以实现分离关注点和松散耦合。通过这种分层架构,可以更好地维护和扩展应用程序,并且使应用程序更易于测试和设计。
MVC设计模式

Spring MVC 又是什么?
Spring MVC是一个基于Java的Web框架,用于构建Web应用程序。它是Spring框架的一部分,具有灵活性、可扩展性和强大的可配置性。Spring MVC通过使用MVC(模型-视图-控制器)设计模式来分离应用程序的不同层。
模型层代表数据或业务逻辑,视图层代表UI元素,控制器层充当这两个层之间的中介。这种分离允许更好的模块化和易于维护的代码。Spring MVC还提供了丰富的特性,如表单处理、文件上传、安全性、国际化和验证,可以方便地集成到Web应用程序中。总的来说:

  1. Spring MVC 是⼀个 Web 框架。
  2. Spring MVC 是基于 Servlet API 构建的。

SpringMVC
如何学 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模块。
创建 Spring MVC 项目

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, 黄小黄~";
    }
}

实现结果01

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.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;
} 

实现结果3
可以看到,参数正常的传递过去了。
但是,对于基本数据类型来说,有坑点! 如果忘记传参数呢?
实现结果4
可以看到,服务器返回500状态码。如何解决呢?我们可以对于所有的基本数据类型,采用包装类的方式传递参数, 示例代码如下:

// 传递单个参数
@GetMapping("/method02")
public String method02(Integer num) {
    
    
    return "num: " + num;
}

这样,如果前端忘记传递参数,只会返回 null。问题就很清晰:是因为忘记传递 num 值造成的~
结果5

如何传递多个参数?
只需要增加方法参数列表的参数即可。当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置是不影响后端获取参数的结果。

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;
}

结果6

3.3 后端参数重命名(@RequestParam 参数映射)

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致, ⽐如前端传递了⼀个 name 给后端,⽽后端⼜是有 curName 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值。示例代码如下:

// 参数映射
@GetMapping("/para")
public String showCurName(@RequestParam("name") String curName) {
    
    
    return "curName = " + curName;
}

这时,即使前端传过来的参数是 name, 也可以正常映射了:
结果7

3.4 @RequestParam 参数必传设置

上述例子中,如果传递一个非 name 值,就会出现如下错误:
结果7
这是什么原因呢?通过查看 @RequestParam 注解的实现细节就可以发现端倪:
实现细节
可以看到,required 默认为 true,即不传递该参数会报 400 错误。

设置非必传参数
只需要设置 @RequestParam 中的 required=false 来避免不传递时报错:

// 参数映射
@GetMapping("/para")
public String showCurName(@RequestParam(value = "name", required = false) String curName) {
    
    
    return "curName = " + curName;
}

结果8

3.5 @RequestBody 接收JSON对象

// 传递 JSON
@PostMapping("/set-student")
public String setStudent(@RequestBody Student student) {
    
    
    System.out.println(student);
    return "Student Set Success.";
}

使用 PostMan 构造 JSON 传递给后端:
结果9

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.";
}

结果10

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 + "上传成功!";
}

结果11

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";
    }
}

结果12

4.2 返回 text/html

 // 返回 test/html
 @RequestMapping("/method1")
 @ResponseBody
 public String method1() {
    
    
     return "<h1>Hello, world!</h1>";
 }

结果13

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;
}

结果14

4.4 请求重定向与请求转发

return 不但可以返回⼀个视图,还可以实现跳转,跳转的⽅式有两种:

  • forward 是请求转发;
  • redirect 是请求重定向。

示例代码如下:

// 请求重定向
@RequestMapping("/index1")
public String index1() {
    
    
    return "redirect:/index.html";
}
// 请求转发
@RequestMapping("/index2")
public String index2() {
    
    
    return "forward:/index.html";
}

请求转发与请求重定向的区别?

  1. 请求转发是在服务器内部完成的,客户端浏览器只发出了一次请求,服务器接收到请求后直接将请求转发给另一个资源进行处理, 这个过程对于浏览器来说是透明的;而请求重定向是客户端发出了两次请求,第一次请求得到服务器响应后,服务器会告诉浏览器要转向到新的资源,浏览器收到响应后会再次发起请求。

  2. 对于请求转发,客户端浏览器地址栏不会改变,仍然是原来的地址;而请求重定向会将地址栏改变为新的地址。

  3. 请求转发使用的是forward方法,它只能在同一个Web应用程序内部实现;而请求重定向使用的是sendRedirect方法,它可以实现跨域跳转。

  4. 请求转发是在服务器内部进行的,因此可以共享同一个request域中的数据,而请求重定向是两个完全独立的请求,不能共享request域中的数据。

  5. 请求重定向与直接访问新地址效果一致,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。

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编程之路 收录点击订阅专栏 , 持续更新中。
 以上便是本文的全部内容啦!创作不易,如果你有任何问题,欢迎私信,感谢您的支持!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_60353039/article/details/131566413