SpringMVC注解

7162 字
18 分钟

坚强不是面对悲伤不流一滴泪,而是擦干眼泪后微笑着面对以后的生活。

——《风之谷》

MVC 模式原理(Model-View-Controller)

MVC模式(Model-View-Controller,模型-视图-控制器) 是一种软件架构模式,被广泛用于Web开发和桌面应用开发中。它通过将应用程序分为三部分,使得代码结构清晰,易于维护和扩展。

MVC 的三大核心组成

1. Model(模型)

  • 定义 :负责应用程序的数据和业务逻辑。
  • 职责 :管理数据、规则、逻辑和功能。例如:数据库操作、数据校验、业务处理。
  • 示例 :Java Bean、POJO、数据库实体类、业务逻辑类。

2. View(视图)

  • 定义 :负责数据的展示(UI 层)。
  • 职责 :将 Model 的数据以用户友好的形式展示出来,不包含业务逻辑。
  • 示例 :网页页面(HTML、JSP、Thymeleaf)、App 界面、前端框架页面(Vue/React)。

3. Controller(控制)

  • 定义 :负责接收用户请求并调用相应的业务逻辑,返回结果给视图。
  • 职责 :协调 Model 和 View 之间的交互,处理用户输入。
  • 示例 :Spring MVC 的 Controller、Servlet、Action 类。

MVC的工作流程

用户请求 --> Controller --> Model --> Controller --> View --> 用户界面

SpringMVC

SpringMVC是MVC架构在JAVA语言中的实际应用。SpringMVC中的核心组件由MVC理论中的3层扩充为7大核心组件。每个组件都是为了实现MVC架构而设计。

组件说明
DispatcherServlet 前端控制器,负责接收请求并协调各个组件完成请求处理
HandlerMapping处理器映射器,根据请求URL查找对应的Controller方法
HandlerAdapter处理器适配器,调用Controller的方法执行
Controller处理器,业务逻辑处理单元
ModelAndViewController返回的数据和视图名
ViewResolver视图解析器,根据视图名找到具体的视图
View视图,用于渲染页面(如 JSP、Thymeleaf)

SpringMVC请求处理按照组件从上到下,完成调用Controller,执行Model,返回View的整个流程。

前后端分离架构

前后端分离架构(Architectural Pattern)

  • 前端(Vue3):负责界面展示、用户交互、路由控制
  • 后端(Spring Boot):负责业务逻辑处理、数据库操作、提供 API(通常是 RESTful)

✅ 优点:前后解耦、并行开发、跨平台、灵活性高

现在常用的前后端分离的设计模式(Frontend-Backend Separation Architecture)中,传统后端的MVC架构中的View被前端取代了-------SpringBoot只负责返回JSON数据(API),视图渲染全部由Vue等前端框架完成。

RESTful API架构风格

REST 软件架构

REST把系统中的所有对象都抽象成资源,每个资源用URL唯一标识,并通过HTTP方法进行操作。

1. 资源

资源是系统的对象,比如用户、商品、订单等。

  • 用户资源:/users
  • 单个用户:/users/123
  • 某个用户的订单:/user/123/orders
2. 标准HTTP方法
HTTP 方法含义说明
GET查询获取资源(不会改变数据)
POST创建创建一个新的资源
PUT更新更新资源的全部内容
PATCH局部更新更新资源的部分内容
DELETE删除删除资源
3. URL要具有语义化

非REST:/getUserById?id=123

REST:GET /users/123

✅ 示例:用户管理的 RESTful API

操作URL方法描述
获取用户列表/usersGET查询所有用户
获取指定用户/users/123GET查询 id 为 123 的用户
创建新用户/usersPOST提交用户数据创建新用户
更新用户/users/123PUT替换 id 为 123 的用户
删除用户/users/123DELETE删除用户

使用SpringMVC

如果通过SpringBoot启动一个Spring项目,大多数情况下我们无需额外配置SpringMVC,也不需要编写web.xml配置文件。

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

使用 @SpringBootApplication ,springBoot会自动注册 DispatcherServletContextLoaderListener 等,无需手动配置。

控制器(Controller)

1. @Controller

作用:

  • 用于标注一个类是控制器组件(Controller),由SpringMVC扫描并注册到容器中,用来接收和处理前端请求。

示例:

@Controller
public class UserController {
    @RequestMapping("/hello")
    public String sayHello() {
        return "hello";  // 返回视图名
    }
}

视图:常用的视图文件有 .html ,在SpringBoot中存储路径为:resources/templates/,当你返回 hello时,实际会将hello.html返回。

注:如果以HTML作为视图,需要在pom.xml中添加依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2. @RequestMapping

作用:

  • 用于定义请求路径的映射,可用在类或方法上,支持GET、POST等请求方式的映射。

示例:

@RequestMapping("/user")	//类控制器前缀
public class UserController {
  
    @RequestMapping("/login")	//实际路径为/user/login
    public String loginPage() {
        return "login";
    }
}

常用参数:

  • value:路径
  • method:请求方式(GET 、PUST)
  • params:参数条件
  • headers:请求头条件
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(
        value = "/login",                          // 1. 请求路径
        method = RequestMethod.POST,              // 2. 请求方法:POST
        params = {"username", "password"},        // 3. 必须包含这两个请求参数
        headers = "Content-Type=application/x-www-form-urlencoded" // 4. 必须包含这个头并且值相等,其他头不做限制
    )
    public String login(
        @RequestParam String username,
        @RequestParam String password
    ) {
        // 登录逻辑
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        return "loginSuccess";  // 返回视图名
    }
}

接受多种请求方式:

@RequestMapping(value = "/example", method = {RequestMethod.GET, RequestMethod.POST})

异常

  1. 有多个RequestMapping 相等时(相等指value,params,headers等参数完全相等)
    • Spring会在启动时,报错 Ambiguous mapping
  2. 如果它们的映射信息有任何差别(即使在运行时某个请求同时满足了两个映射条件),Spring 也会先注册成功,然后在运行时再根据“最具体(narrowest)”原则去选一个最优映射执行——如果仍然无法区分,就抛出运行时 ServletException。同时返回500给客户端。

3. @GetMapping / @PostMapping / @PutMapping / @DeleteMapping

作用:

  • @RequestMapping 的快捷方式,用于简化代码(Spring 4.3+ 推荐使用)。
@GetMapping("/user/list")
public String listUsers() {
    return "userList";
}

@PostMapping("/user/add")
public String addUser() {
    return "success";
}

@GetMapping@PostMapping@PutMapping@DeleteMapping 等复合注解本质上就是带了默认 method@RequestMapping,它们完全继承@RequestMapping 的其它属性:value,params,headers…。

推荐的方法

  • 在你需要使用精细匹配时,一律使用 RequestMapping
  • 在不需要精细匹配时,使用 GetMapping等尽可能简化代码。

4. @RequestParam

作用:

  • 用于获取请求参数(通常是URL查询参数或表单参数)

示例:

@GetMapping("/search")
public String search(@RequestParam("keyword") String keyword) {
    System.out.println("搜索关键词:" + keyword);
    return "result";
}

使用Get请求时,传参附在路径后面如:/search?keyword=ulna

POST请求时,@RequestParam 适用于接收表单提交(application/x-www-form-urlencoded)或URL查询,而不是json请求体。

常用参数:

  • value:String,请求参数名称,将前端请求参数名绑定到方法参数。
  • required:boolean,是否必须有该参数,默认为 true,缺少参数时会返回400错误
  • defaultValue:String,默认值,若请求未带参数则用此值,设置后 required自动为 false

在前端请求参数名和方法参数名称相同时,可以省略value参数

简化的直接写为 @RequestParam String keyword

有时你需要手动开启 -parameters 编译参数

5. @PathVariable

作用:

  • 用于获取URL路径中的变量(RESTful 风格)

示例:

@GetMapping("/{year}/{month}/{day}/{filename}/")
    public Message returnBlogByPath(
        @PathVariable int year,
        @PathVariable int month,
        @PathVariable int day,
        @PathVariable String filename)

6. @RequestBody

作用:

  • 将请求体中的JSON数据绑定到Java对象(常用于POST请求)

示例:

  • 请求体:

    {
      "username": "Alice",
      "age": 25,
      "address": {
        "city": "Shanghai",
        "zip": "200000"
      }
    }
  • 对应Java实体类

    public class User {
        private String username;
        private int age;
        private Address address;
    }
    
    public class Address {
        private String city;
        private String zip;
    }
  • Controller实例:

    import org.springframework.web.bind.annotation.*;
    
    @RestController
    public class UserController {
        @PostMapping("/addUser")
        public String addUser(@RequestBody User user) {
            return "用户:" + user.getUsername() + ",年龄:" + user.getAge();
        }
    }

7. @ResponseBody

作用:

  • 将返回值直接写入HTTP响应体(通常用于JSON数据结构),而不是视图名
@GetMapping("/api/user")
@ResponseBody
public User getUser() {
    return new User("张三", 18);
}

会自动将java类转化为JSON数据。

8. @RestController

作用:

  • @Controller + @ResponseBody的组合,简化RESTful 风格的API 开发。

示例:

@RestController
@RequestMapping("/api/user")
public class UserRestController {

    @GetMapping("/{id}")
    public User getUser(@PathVariable int id) {
        return new User("张三", 18);
    }
}

9. @ModelAttribute

作用:

  • 用于将请求的参数直接绑定到对象
  • 用于在请求处理前设置模型属性

示例:

  • 表单如下:
<form action="/register" method="post">
    用户名:<input name="username" /><br>
    密码:<input name="password" type="password" /><br>
    年龄:<input name="age" /><br>
    <input type="submit" value="注册" />
</form>
  • 表单对应数据的类如下:
public class User {
    private String username;
    private String password;
    private Integer age;
    // getter/setter 省略
}
  • Controller如下:

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.*;
    
    @Controller
    public class RegisterController {
    
        // 预置应用名,每个页面都能访问到
        @ModelAttribute
        public void addCommonInfo(Model model) {
            model.addAttribute("appName", "SpringMVC Demo 应用");
        }
    
        // 处理注册页面表单提交,自动把表单参数封装到 User 对象
        @PostMapping("/register")
        public String register(@ModelAttribute User user, Model model) {
            // 这里 user 会自动绑定表单参数
            // 可进行保存、校验等操作
            model.addAttribute("msg", "注册成功,欢迎:" + user.getUsername());
            return "result"; // 跳转到 result 视图页面
        }
    }

前端提交表单后,因为 @ModelAttribute 注解,Spring会自动生成一个新的User对象,并将参数自动绑定进去。

10. Model/ModelMap/ModelAndView

作用:

  • 向视图传递数据。

Model

org.springframework.ui.Model是一个接口,SpringMVC推荐使用的模型数据传送方式。

示例:

@GetMapping("/hello")
public String hello(Model model) {
    model.addAttribute("msg", "Hello, SpringMVC!");
    return "hello"; // 返回视图名
}

在hello视图中msg的变量会被替换显示为:Hello,SpringMVC!

在视图中存在,但是未被设置具体value的key不会视图中显示。

ModelMap

org.springframework.ui.ModelMap 是Model的一个实现类,继承自LinkedHashMap,具有Map的全部功能。

示例:

@GetMapping("/hello")
public String hello(ModelMap modelMap) {
    modelMap.addAttribute("msg", "Hello, ModelMap!");
    // modelMap.put("msg", "Hello, ModelMap!") 也可以
    return "hello";
}

ModelAndView

org.springframework.web.servlet.ModelAndView 既可以携带模型数据,也可以指定返回的视图。

示例:

@GetMapping("/hello")
public ModelAndView hello() {
    ModelAndView mav = new ModelAndView();
    mav.addObject("msg", "Hello, ModelAndView!");
    mav.setViewName("hello");
    return mav;
}