• 2023.11.20 关于 Spring MVC 详解


    目录

    MVC

    工作流程

    Spring MVC 

    掌握三个功能

    创建 Spring MVC 项目 

    推荐安装插件 EditStarters

    安装步骤

    使用方法

    实现连接功能

    基础注解

     @RequestMapping

    指定 GET 和 POST 方法类型

    @ResponseBody

    获取参数 

    传递 单个 或 多个参数

    参数重命名 @RequestParam

    接收 JSON 对象 @RequestBody

    获取 URL 中参数 @PathVariable

    上传文件 @RequestPart

    获取 Cookie 数据

    传统方式

     使用 @CookieValue 注解方式

    读取 Session 数据

    传统方式

     使用 @SessionAttribute 注解方式

    返回静态页面

    返回 JSON 对象


    MVC

    • MVC 是一种 软件设计模式
    • 将应用代码组织成三个互相交织的部分:模型、视图、控制器

    模型(Model)

    • 业务流程 或 状态的处理以及业务规则的制定者
    • 与数据库交互的逻辑

    视图(View)

    • 视图代码用户交互界面
    • 对于Web应用来说,可以大致概括为 HTML 页面
    • 视图是用户接口和交互

    控制器(Controller)

    • 控制器可以理解为从用户接收请求,将模型与视图匹配在一起,共同完成用户的请求
    • 是视图和数据库之间的中介

    工作流程

    1. 客户端向服务器发起 HTTP 请求
    2. 控制器(Controller)接收 HTTP 请求并向 模型(Model)请求信息
    3. 模型(Model)对象 在数据库中进行相应数据的存取,完成后将响应信息返回给 控制器(Controller)
    4. 控制器(Controller)收到响应信息后,又将其交给 视图(View)渲染结果,展示给用户,即通过 视图(View)将 HTTP 响应传递给用户

    Spring MVC 

    • MVC 是一种思想,Spring MVC 是对 MVC 思想的实现
    • Spring MVC 是一个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架
    • 常说的 SSM 项目就等于 Spring Boot + Spring MVC + MyBatis

    掌握三个功能

    连接功能

    • 将用户(浏览器)和 Java 程序连接起来
    • 即可以访问一个能够调用 Spring 程序的地址

    获取参数功能

    • 用户访问时会带一些参数,如 query string
    • 在程序中能够获得该参数

    输出数据功能

    • 根据请求计算响应,将响应结果返回给用户

    创建 Spring MVC 项目 

     建议点击下方链接 详细了解创建过程

    Spring Boot 的创建及使用


    • 创建 Spring MVC 项目的关键为 添加 Spring Web 依赖
    • 该依赖包含了 MVC


    推荐安装插件 EditStarters

    • 该插件可以方便地设置 Spring Boot 项目的依赖

    安装步骤

    注意:

    • 安装完该插件后最好重启 IDEA

    使用方法

    • 在 pom.xml 页面中,按快捷键 Alt + Insert,点击 Edit Starters

    • 选择需要添加依赖


    实现连接功能

    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.ResponseBody;
    4. @Controller //让 Spring 项目启动时,将这个注解下的类加载到容器中
    5. @ResponseBody //使其返回的响应是数据,而非页面
    6. @RequestMapping("/test") //注册路由
    7. public class TestController {
    8. @RequestMapping("/hi") //注册路由
    9. public String sayHi() {
    10. return "hi Spring MVC!";
    11. }
    12. }

    运行结果:

    • 在浏览器的 URL 输入框中 输入相对应的 URL

    基础注解

     @RequestMapping

    • 可以用来修饰 类 或 方法
    • 用来将 HTTP 请求路径映射到对应的处理方法上

    实例理解

    指定 GET 和 POST 方法类型

    • GET 请求的三种写法
    1. // 写法一
    2. @RequestMapping("/index")
    3. // 写法二
    4. @RequestMapping(value = "/index",method = RequestMethod.GET)
    5. // 写法三
    6. @GetMapping("/index")
    • POST 请求的两种写法

    1. // 写法一
    2. @RequestMapping(value = "/index",method = RequestMethod.POST)
    3. // 写法二
    4. @PostMapping("/index")


    @ResponseBody

    • @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端
    • @ResponseBody 可以用来修饰方法 或 类,修饰类表示类中所有的方法都遵循上条规定,而不是返回 静态页面

    阅读下面文章之前 建议点击下方链接了解 Postman 的使用

    Postman 的使用

    根据链接文章目录寻找对应 Postman 内容


    获取参数 

    • Spring MVC 中可以直接通过方法中的参数来传参
    • 注意以下两点

    参数名称匹配

    • 在 Spring MVC 中,当有多个参数进行参数匹配时,是按照参数的名称进行匹配的,而不是参数的位置
    • 这意味着,无论你在方法中如何排列参数,只要参数的名称与前端传递的参数名称相匹配,就可以正确的获取到参数值

    包装类类型参数

    • 在Spring MVC 中,建议方法的参数使用包装类类型,而非基础类类型
    • 如果方法的参数为基础类型(int、double 等),当前端忘记传递参数时,程序会报 500 错误
    • 因为基础类型不能为 null
    • 而如果参数类型为包装类类型(Integer、Double等),即使前端忘记传递参数,参数值也只会为 null,不会引发报错

    传递 单个 或 多个参数

    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.*;
    3. @Controller
    4. @ResponseBody
    5. @RequestMapping("/user")
    6. public class UserController {
    7. @RequestMapping("/message")
    8. public void getUserMessage(String name,String age) {
    9. System.out.println("name" + name);
    10. System.out.println("age" + age);
    11. }
    12. }
    • 上述代码中的方法参数与 URL 中 query string 的 key 值相对应

    测试结果

    • 此处我们使用 Postman 来构造 HTTP 请求 来访问 getUserMessage 方法

    • 点击 send 发送构造好的 HTTP 请求,随后观察控制台的打印


    参数重命名 @RequestParam

    • @RequestParam 注解有三个属性

    value

    • 请求参数名(必须配置)
    • 如果想重命名参数,可以在 value 属性中指定新的参数名

    required

    • 默认为 true,即 请求中必须包含该参数,如果未包含将直接抛出异常
    • 设置为 false ,表示该参数为 非必传参数

    defaultValue

    • 表示参数的默认值
    • 如果设置了 defaultValue,则无论是否配置了 required,required 都将被自动设置为 false

    实例理解

    • 当前端传递的参数 key 为 t1
    • 此时后端便可以用 @RequestParam 注解 来重命名后端的参数名为 startTime
    • 即用 startTime 来接收前端传来的 参数名为 t1 的值
    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.*;
    3. @Controller
    4. @ResponseBody
    5. @RequestMapping("/user")
    6. public class UserController {
    7. @RequestMapping("/time")
    8. public void getTime(@RequestParam(value = "t1", required = false) String startTime,
    9. @RequestParam(value = "t2", required = true, defaultValue = "2023.12.30") String endTime) {
    10. System.out.println("起始时间:" + startTime);
    11. System.out.println("结束时间:" + endTime);
    12. }
    13. }
    • 该段代码将 t1 重命名为 startTime,将 t2 重命名为 endTime
    • 此时 startTime 被设置为 非必传参数
    • endTime 的 required 被设置为 true ,表示前端发送的请求中必须包含 t2 字段
    • 但是 endTime 又被设置了 defaultValue,表示其默认值为 "2023.12.30" 
    • 所以即使 endTime 的 required 被设置为了 true,但是又因为 defaultValue 的设置,从而导致 endTime 的 required 又被自动设置为了 false

    验证结果:

    • 运行结果正如我们所期望的一样
    • 虽然请求中未包含 t2 字段,但并未抛出异常,正常接收到了 请求中的参数值

    接收 JSON 对象 @RequestBody

    实例理解

    • 此时前端想发送的请求如下图所示

    • 首先我们先创建一个 User 实例类,与请求的 JSON 相对应
    1. import lombok.Data;
    2. import org.springframework.stereotype.Component;
    3. @Component
    4. @Data
    5. public class User {
    6. private int id;
    7. private String name;
    8. private int age;
    9. }
    • 然后我们再使用 @RequestBody 来接收 JSON 对象,并打印出来
    1. import com.example.demo.model.User;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.*;
    4. @Controller
    5. @ResponseBody
    6. @RequestMapping("/user")
    7. public class UserController {
    8. @RequestMapping("/message")
    9. public void getUserMessage(@RequestBody User user) {
    10. System.out.println(user.toString());
    11. }
    12. }

    运行结果:


    获取 URL 中参数 @PathVariable

    实例理解

    • 此时前端想发送的请求如下图所示

    • 我们使用 @POSTMapping 注解来接收 URL 中的参数值
    1. import com.example.demo.model.User;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.*;
    4. @Controller
    5. @ResponseBody
    6. @RequestMapping("/user")
    7. public class UserController {
    8. @PostMapping("/urlValue/{name}/{age}")
    9. public String getUrlValue(@PathVariable(value = "name") String name,
    10. @PathVariable(value = "age",required = false) String age) {
    11. return "name:" + name + ", age:" + age;
    12. }
    13. }

    注意:

    • 此处的参数 name 为必传参数,age 为非必传参数

    运行结果:

    • 一般来说清晰、有意义的URL结构可以提高你的网站在搜索引擎中的排名
    • 使用路径变量(如 "/user/{id}") ,而不是查询字符串(如 "/user?id=123")可以使URL 看起来更加整洁和易于理解,这有可能帮助提高 SEO 效果
    • SEO 全称为 Serch Engine Optimization,译为 搜索引擎优化
    • SEO 是一种利用引擎的规则提高网站在有关搜索引擎内的自然排名
    • 目的是让其在行业占据领先地位,获得品牌效益

    上传文件 @RequestPart

    实例理解

    • 此时前端通过 from 表单将文件传给后端
    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.RequestPart;
    4. import org.springframework.web.bind.annotation.ResponseBody;
    5. import org.springframework.web.multipart.MultipartFile;
    6. import java.io.File;
    7. import java.io.IOException;
    8. @Controller
    9. @ResponseBody
    10. @RequestMapping("/file")
    11. public class FileController {
    12. @RequestMapping("/up-file")
    13. public String upFile(@RequestPart("myfile")MultipartFile file) throws IOException {
    14. String path = "E://photo.jpg";
    15. // 将传来的文件存放到对应的目录下
    16. file.transferTo(new File(path));
    17. return "文件保存到 " + path;
    18. }
    19. }
    • 通过 Postman 来构造 from 表单来给后端传输文件

    获取 Cookie 数据

    •  Spring MVC 基于 Servlet 实现
    • 所以获取 Cooike 数据也是通过 HttpServletResponse 的 getCookie 方法

    传统方式

    实例理解

    • 此处通过打印日志信息,来方便结果的观察
    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.RequestMapping;
    4. import org.springframework.web.bind.annotation.ResponseBody;
    5. import javax.servlet.http.Cookie;
    6. import javax.servlet.http.HttpServletRequest;
    7. @Controller
    8. @ResponseBody
    9. @RequestMapping("/cookie")
    10. @Slf4j
    11. public class CookieController {
    12. @RequestMapping("/get-cookie")
    13. public String getCookie(HttpServletRequest request) {
    14. Cookie[] cookies = request.getCookies();
    15. for (Cookie cookie : cookies) {
    16. log.error("key:" + cookie.getName() + ",value" + cookie.getValue());
    17. }
    18. return "get Cookie Success!";
    19. }
    20. }
    • 在浏览器中自定义测试 cookie 

    • 在浏览器的 URL 地址框中输入相对应地址

    • 在控制台中观察 Spring MVC 拿到的 cookie 信息


     使用 @CookieValue 注解方式

    实例理解

    • 通过使用 @Cookievalue 注解来直接获取 cookie 所对应 name 为 "xiaolin" 的 value 值
    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.CookieValue;
    3. import org.springframework.web.bind.annotation.RequestMapping;
    4. import org.springframework.web.bind.annotation.ResponseBody;
    5. @Controller
    6. @ResponseBody
    7. @RequestMapping("/easy-cookie")
    8. public class EasyCookieController {
    9. @RequestMapping("/easy-get")
    10. public String easyGetCookie(@CookieValue("xiaolin") String value) {
    11. return "cookie: " + value;
    12. }
    13. }
    • 在浏览器的 URL 地址框中输入相对应地址

    读取 Session 数据

    •  Spring MVC 基于 Servlet 实现
    • 所以读取 Session 数据也是通过 HttpServletResponse 的 getSession 方法

    • 首先为了能够读取到 Session 数据,我们得先自己设置 session 对象的属性

    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.ResponseBody;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpSession;
    6. @Controller
    7. @ResponseBody
    8. @RequestMapping("session")
    9. public class SessionController {
    10. @RequestMapping("set-session")
    11. public String setSession(HttpServletRequest request) {
    12. HttpSession session = request.getSession(true);
    13. session.setAttribute("MasterMao","hello");
    14. return "set Session Success";
    15. }
    16. }
    • 在浏览器的 URL 地址框中输入相对应地址,来通过该请求调用到 setSession 方法

    传统方式

    实例理解

    • 此处使用 getSession 来读取 Session 数据
    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.ResponseBody;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpSession;
    6. @Controller
    7. @ResponseBody
    8. @RequestMapping("session")
    9. public class SessionController {
    10. @RequestMapping("read-session")
    11. public String readSession(HttpServletRequest request) {
    12. HttpSession session = request.getSession(false);
    13. String value = (String) session.getAttribute("MasterMao");
    14. if (value == null) {
    15. return "session error!";
    16. }
    17. return "get Session Success! value = " + value;
    18. }
    19. }
    • 在浏览器的 URL 地址框中输入相对应地址,来读取到 Session 数据


     使用 @SessionAttribute 注解方式

    实例理解

    • 通过使用 @SessionAttribute 注解来直接获取 session 属性名为 "MasterMao" 所对应的属性
    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.ResponseBody;
    4. import org.springframework.web.bind.annotation.SessionAttribute;
    5. @Controller
    6. @RequestMapping("easy-session")
    7. @ResponseBody
    8. public class EasySessionController {
    9. @RequestMapping("easy-read")
    10. public String easyReadSession(@SessionAttribute(value = "MasterMao", required = false) String value) {
    11. return "easy read session success! value =" + value;
    12. }
    13. }
    • 在浏览器的 URL 地址框中输入相对应地址,来读取到 Session 数据

    返回静态页面

    • Spring MVC 默认情况下返回的是 View 视图(xxx.html)
    • 而上文中我们通过添加 @ResponseBody 注解,修改成了 后端返回给前端的是数据,而非页面
    • 此时我们不加 @ResponseBody 注解,就让后端返回一个静态页面给前端

    实例理解

    • 首先我们需在对应目录下创建一个前端页面,如下图所示

    • 然后编写 index.html 页面内容
    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>测试页面title>
    8. head>
    9. <body>
    10. <h3>Hello Spring MVC!h3>
    11. body>
    12. html>
    • 后端编写如下代码,返回 index.html 页面给前端
    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. @Controller
    4. @RequestMapping("/html")
    5. public class IndexController {
    6. @RequestMapping("/index")
    7. public String respIndex() {
    8. // 编写业务逻辑代码
    9. return "/index.html";
    10. }
    11. }
    • 启动程序,在浏览器中输入对应的 URL 地址

    注意:

    • 当程序启动后,浏览器可直接直接访问 static 目录下的前端页面

    • 一个 URL 地址为 localhost:8080/html/index
    • 该地址表示向程序中发送请求,根据 URL 的路径对应到程序中相应的控制器方法上
    • 此处对应的控制器方法为 respIndex 方法,然后执行该方法中业务逻辑,处理该请求
    • 又由于 Spring MVC 默认情况下返回的是页面,此处我们也未添加 @ResponseBody 注解
    • 即 respIndex 方法返回的字符串,被 Spring MVC 转变为相对应的页面,返回给了前端
    • 另一个 URL 地址为 localhost:8080/index.html
    • 该 URL 地址直接指向静态 HTML 文件
    • 即服务器将直接返回 index.html 文件的内容,不经过任何控制器方法

    返回 JSON 对象

    • 在 SpringMVC 中返回 HashMap 对象,实际上就是返回 JSON 对象给前端

    实例理解

    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. import org.springframework.web.bind.annotation.ResponseBody;
    4. import java.util.HashMap;
    5. @Controller
    6. @RequestMapping("/json")
    7. @ResponseBody
    8. public class JsonController {
    9. @RequestMapping("/get-json")
    10. public HashMap respJson() {
    11. HashMap map = new HashMap<>();
    12. map.put("xiaolin", 1);
    13. map.put("maolin", 2);
    14. map.put("xiaomei", 3);
    15. return map;
    16. }
    17. }

    运行结果:

  • 相关阅读:
    nginx浏览器缓存和上流缓存expires指令_nginx配置HTTPS
    python对dataframe中series的json格式解析
    使用SimPowerSystems并网光伏阵列研究(Simulink实现)
    Java开发中常见的坑
    100天精通Python(数据分析篇)——第56天:Pandas读写txt和csv文件(read_csv、to_csv)
    SonarQube安装、出现启动出错并解决记录、配合idea配置使用,gradle项目配置
    Ubuntu20.04搭建RISC-V和qemu环境
    Sonatype Nexus 如何把多仓库合并在一起
    spacemacs auto-complete 自动补全功能
    代码随想录训练营第27天|LeetCode 39. 组合总和、40.组合总和II、 131.分割回文串
  • 原文地址:https://blog.csdn.net/weixin_63888301/article/details/134518248