🎇前言
学习SpirngMVC首先我们要先知道SpringMVC是什么。SpirngMVC的全名是Spring Web MVC,基于Servlet API构建的原始 Web 框架,从⼀开始就包含在Spring 框架中。它的正式名称Spring Web MVC来自其源模块的名称(Spring-webmvc),在平常我们称它为Spring MVC。
上述最重要的两个关键信息:
1.Spring MVC 是一个 Web 框架
2.Spring MVC 是基于 Servlet API 创建的
Spring MVC 它由两个单词组成(Spring和MVC),Spirng在之前我们看过是什么了(传送门:Spring 核心与设计思想),剩下一个MVC,让我们来看看是什么吧!
1.MVC
1.1 MVC 的定义
MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分
为模型、视图和控制器三个基本部分。
Model(模型): 应用程序中用于处理应用程序数据逻辑的部分;通常模型对象负责在数据库中存取数据
View(视图): 应用程序中处理数据显示的部分;通常视图是依据模型数据创建的。
Controller(控制器): 应用程序中处理用户交互的部分;通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
1.2 MVC 与 Spring MVC的关系
MVC 是一种思想,而 Spring MVC 是对 MVC 思想的具体实现。
总的来说,Spring MVC是一个实现了MVC模式,并继承了Servlet API的Web框架。
2.为嘛要学Spring MVC?
现在绝大部分的 Java 项目都是基于 Spring 或 SpringBoot的,而 Spring 的核心就是 Spring MVC。也就是说 Spring MVC 是 Spring 框架的核心模块,而 SpringBoot 是 Spring 的脚手架,因此我们得出如下结论:现在市面上绝大部分的 Java项目约等于 Spring MVC 项目,这就是我们为啥要学 Spring MVC的原因。
3.如何学习 Spring MVC?
只需熟悉掌握以下三个功能即可:
1.链接功能: 将用户和 Java 程序连接起来,也就是访问一个地址能够调用到 Spring 程序。
2.获取参数的功能: 用户访问的时候会带一些参数,在程序中获取到参数。
3.输出数据的功能: 根据参数执行业务逻辑,把程序执行的结果返回给用户。
对于Spirng MVC来说,掌握了以上3个功能就相当于掌握了Spring MVC来了。
3.1 Spring MVC 创建和连接
Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同(Spring MVC 使⽤ Spring Boot 的方式创建),
在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项目。项目的创建可以参考这篇文章(传送门:Spring MVC项目创建)。
Spring 项目离不开注解,我们连接也需要注解,它就是@RequestMapping
3.1.1 @RequestMapping 注解介绍
@RequestMapping 是 Spring Web 应用程序中最常用到的注解之⼀,它是⽤来注册接⼝的路
由映射的。
路由映射: 路由映射指的是当⽤户访问⼀个 url 时,将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射.
@RequestMapping基本使用方式:
我们实现一个在网页上打印你好 @RequestMapping
。
package com.example.demo.Contronller; 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 sayHi() { String res ="你好 @RequestMapping"; return res; } }
这里说一下为什么使用两个@RequestMapping,用在类上面的我们称为一级路由映射,它是为了能找到这个类(一个文件夹里可能有很多类),加在方法称为二级路由映射,为了能找到这个方法(一个类中可能有很多方法)。其实这就像我们点外卖,我们输入地址的时候先输出小区(一级路由映射),在输入几号楼(二级路由映射)。@RequestMapping 即可修饰类,也可以修饰⽅法,当修饰类和⽅法时,访问的地址是类 + 方法。
当仅修饰方法时:
package com.example.demo.Contronller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller// 让 spring 框架启动时,加载 @ResponseBody// 返回⾮⻚⾯数据 public class UserController { @RequestMapping("/hi")// 路由映射 public String sayHi() { String res ="你好 @RequestMapping"; return res; } }
3.1.2 使用@RequestMapping的参数修改请求方法
Servlet API 中有 GET、POST、DELETE等等一共八种方法。在这里@RequestMapping如何修改方法呢?在@RequestMapping里面有一个参数叫做method,它默认值是空,我们可以调整它的值来确认使用什么方法,如下图:
package com.example.demo.Contronller; 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 @ResponseBody public class UserController { @RequestMapping(value = "/hi",method = RequestMethod.POST) public String sayHi() { String res ="你好 @RequestMapping"; return res; } }
3.1.3 @GetMapping 和 PostMapping
这两个注解就是@RequestMapping
的子类,它们相当于已经指定了方法类型,只需在使用的时候填入路由地址就行了。
//POST方法 @PostMapping("/hi") //GET方法 @GetMapping("/hi")
3.2 获取参数
3.2.1 传递单个参数
在 Spring MVC 中可以直接⽤方法中的参数来实现传参,比如以下代码:
@RequestMapping("/getName") public String getName(String name) { String res ="你好:"+ name; return res; }
我们输入URL:http://127.0.0.1:8080/getName?name=张三,就会看到响应 :
这里有坑的,我们在设置参数类型时,一定要使用包装类,如果没有用包装类我们没有给后端传参的时,他就会报错,如果我们使用的是包装类,那么就算前端没有传参它也不会报错,只是会显示null。
3.2.2 传递对象
我们准备一个类接收前端发过来的数据,Spring MVC 可以自动实现参数对象的赋值,比如 User 对象:
先创建一个User对象
import lombok.Data; @Data class User{ int id; String name; }
在写一个方法接收User对象:
@RequestMapping("/getUser") public String getUser(User user) { return user.toString(); }
输入URL:http://127.0.0.1:8080/getUser?id=1&name=张三
就可以看到它通过对象里面的toStrin()方法输出的user对象了。
3.2.3 表单参数传递/传递多个参数(非对象)
@RequestMapping("/getUser") public String getUser(String name,Integer id) { String res= name +id; return res; }
我们输入URL:http://127.0.0.1:8080/getUser?id=1&name=张三
,就可以得到:
注意: 当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置是不影响后端获取参数的结果。
3.2.4 后端参数重命名(后端参数映射)
在有些情况下,前端传递的参数key和我们后端接收的key可能不一致,比如前端传递了一个time给后端,而后端又是由 createtime字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况的画,我们可以使用@RequestParam
来重命名前后端的参数值。
具体代码如下:
@RequestMapping("/getTime") public String getTime(@RequestParam("time")String createTime) { return createTime; }
我们输入URL:http://127.0.0.1:8080/getTime?time=2023-7-4,就可以得到以下的内容:
这里有一个坑,当我们将参数加上@RequestParam这个注解时,当前端传递参数时,这个被注解的参数不能为空,不然就会报错,这是为啥呢?我们看看这个注解的源码:
可以看出来,它默认的参数是 true,因此必须传输数据,不然就会报400的错误码;如果当传递时想要让他为空并且不报错,这个也很好操作,我们只需将它的值调成false就可以了(@RequestParam(value = "time",required = false))
3.2.5 @RequestBody 接收JSON对象
我们前面也有一个传递对象,但是他个这个JSON对象不一样,这个JSON对象是这么样接收的呢,看下方的代码。
@RequestMapping(value = "/getJSON",method = RequestMethod.POST) public String getJSON(@RequestBody User user) { return user.toString(); }
我们拿JSON对象是在传值的body里面拿的数据,和上方的对象不太一样。
3.2.6 获取URL中参数@PathVariable
代码如下:
@RequestMapping("/getParam/{username}/{password}") public String getParam(@PathVariable String username, @PathVariable String password) { return username +":" +password; }
这里面路由映射中,有两个参数加了花括号,这个表示它两个是动态参数;我们输入URL:http://127.0.0.1:8080/getParam/张三/123123验证是否可以在URL中拿到数据,结果如下:
3.2.7 上传文件@RequestPart
我们举一个简单的例子,我们先传一张照片,代码如下:
@RequestMapping("upfile") public String upFile(@RequestParam("myfile") MultipartFile file) throws IOException { //上传的路径 String path = "F:\\info\\img.png"; file.transferTo(new File(path)); return path+"上传成功"; }
上方代码是传一个照片,传到path参数路径下。我们验证需要配合Postman来完成,使用Postman发送请求:
我们打开我们设置的路径,看看有没有上传的图片,看下图完全没有问题:
虽然上方方法的使用没有问题,但是,我们再次上传图片时,会把上一次上传的图片给覆盖掉,因为我们把上传的路径写死了,这怎么办呢?往下看:
这个问题就很好解决,我们把文件的名字改成随机的,再将它拼接在path上面;只这样还不行,我们还要把它的后缀名给取出来,代码如下:
@RequestMapping("upfile") public String upFile(@RequestParam("myfile") MultipartFile file) throws IOException { //上传的路径 String path = "F:\\info\\"; //路径+【文件名】 path += UUID.randomUUID().toString(); //路径+文件名+【后缀】 path += file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); file.transferTo(new File(path)); return path+"上传成功"; }
我们再用Postman多上传几个图片看看,打开path路径,完全没有问题
3.2.8 获取Cookie/Session/header
🐣获取 Request 和 Response 对象
在SpringMVC中内置了Request对象和Response对象,我们可以直接使用
@RequestMapping("/param1") public String param1(HttpServletResponse response, HttpServletRequest request) { String name =request.getParameter("name"); Cookie[] cookies =request.getCookies(); return name+"你好"; }
🐣传统获取 header/cookie
@RequestMapping("/param10") public String param2(HttpServletResponse response, HttpServletRequest request) { String name = request.getParameter("name"); // 获取所有 cookie 信息 Cookie[] cookies = request.getCookies(); String userAgent = request.getHeader("User-Agent"); return name + ":"+userAgent; }
🐣简洁的获取 Cookie—@CookieValue
@RequestMapping("/cookie") public String cookie(@CookieValue("dabaicai") String bite) { return "cookie:" + bite; }
简洁获取 Header—@RequestHeader
@RequestMapping("/header") public String header(@RequestHeader("User-Agent") String userAgent) { return "userAgent:"+userAgent; }
🐣Session 存储和获取
Session 存储和 Servlet 类似,是使⽤ HttpServletRequest 中获取的,如下代码所示:
@RequestMapping("/setsess") public String setsess(HttpServletRequest request) { // 获取 HttpSession 对象,参数设置为 true 表示如果没有 session 对象就创建⼀个session HttpSession session = request.getSession(true); if(session!=null){ session.setAttribute("username","java"); } return "session 存储成功"; }
🐣获取 Session 可以使⽤ HttpServletRequest,如下代码所示:
@RequestMapping("/sess") public String sess(HttpServletRequest request) { // 如果 session 不存在,不会⾃动创建 HttpSession session = request.getSession(false); String username = "暂⽆"; if(session!=null && session.getAttribute("username")!=null){ username = (String) session.getAttribute("username"); } return "username:"+username; }
🐣获取 Session 更简洁的⽅式:
@RequestMapping("/sess2") public String sess2(@SessionAttribute(value = "username",required = false)String username) { return "username:"+username; }
3.3 返回数据
通过上⾯的学习我们知道,默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图,而现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使⽤@ResponseBody 注解了.
3.3.1 返回静态页面
在目录resources/static/
下创建前端页面 index.html,之后再将它返回给前端:
package com.example.demo.Contronller; 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"; } }
3.3.2 返回 text/html
@RequestMapping("/text") public String text() { return "<h1>Hello,HTML~</h1>"; }
3.3.3 返回 JSON 对象
我们使用Map,将它返回给前端,他会自动解析成JSON对象。
@RequestMapping("getjson") public HashMap<String, String> getJosn() { HashMap<String, String> map = new HashMap<>(); map.put("Java", "Java Value"); map.put("MySQL", "MySQL Value"); map.put("Redis", "Redis Value"); return map; }
3.3.4 请求转发或请求重定向
return 不但可以返回⼀个视图,还可以实现跳转,跳转的⽅式有两种:
- forward 是请求转发;
- redirect:请求重定向
举例说明 forward 和 redirect:
forward(请求转发)和 redirect(请求重定向)的区别:我向吃辣条,我给我儿子说,你去帮我买,这就是 forward 请求转发;如果我想吃辣条,我自己去买,这就是 redirect 重定向。
forward 和 redirect 具体区别如下:
- 1.请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
- 2.请求重定向地址发⽣变化,请求转发地址不发⽣变化。
- 3.请求重定向与直接访问新地址效果⼀直,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问
🎆总结:
在SpringMVC中,我们用的最多的就是注解,这些注解可以让我们可能需要几行,甚至十几行的代码简化成一行代码,因此注释在SpringMVC中很重要,我们上方也仅仅是举出了一些常用的例子,如果需要更多的注解,可以去看下面这个连接里面的注解的解释。