【大家好,我是爱干饭的猿,本文重点介绍SpringMVC 工作流程、Spring MVC的主要组件、Spring MVC 如何连接、如何获取参数、如何输出数据的。
后续会继续分享MyBatis、Spring AOP及其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】
上一篇文章:《【web】HTTP(s)协议详解(重点:HTTPS 的加密过程&浏览器中输入网址后,发生了什么?)》
🤞目录🤞
1.3 Spring 、Spring Boot、Spring MVC有什么区别?
3. @RequestMapping 是 post 还是 get 请求?
🎨1.什么是 Spring MVC?
- Spring MVC 是一个 Web 框架。
- Spring MVC 是基于 Servlet API 构建的。
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 框架。既然是 Web 框 架,那么当用户在浏览器中输入了 url 之后,我们的 Spring MVC 项目就可以感知到用户的请求。
1.3 Spring 、Spring Boot、Spring MVC有什么区别?
spring是一个IOC容器,用来管理Bean,使用依赖注入实现控制反转,可以很方便的整合各种框架,提供AOP机制弥补OOP的代码重复问题、更方便将不同类不同方法中的共同处理抽取成切面、自动注入给方法执行,比如日志、异常等。
springboot是spring提供的一个快速开发工具包,让程序员能更方便、更快速的开发spring+springmvc 应用,简化了配置(约定了默认配置),整合了一系列的解决方案(starter机制)、redis、 mongodb、es。
springmvc是spring对web框架的一个解决方案,提供了一个总的前端控制器Servlet,用来接收请求,然后定义了一套路由策略(url到handle的映射)及适配执行handle,将handle结果使用视图解析技术生成视图展现给前端。
1.4 Spring MVC的主要组件
- Handler:也就是处理器。它直接应对着MVC中的C也就是Controller层,它的具体表现形式有很多,可以是类,也可以是方法。在Controller层中@RequestMapping标注的所有方法都可以看成是一个 Handler,只要可以实际处理请求就可以是Handler
- HandlerMapping initHandlerMappings(context),处理器映射器,根据用户请求的资源uri来查找Handler的。在 SpringMVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个 Handler进行,这就是HandlerMapping需要做的事。
- HandlerAdapter initHandlerAdapters(context),适配器。因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就ok,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情。 Handler是用来干活的工具;HandlerMapping用于根据需要干的活找到相应的工具;HandlerAdapter 是使用工具干活的人。
- HandlerExceptionResolver initHandlerExceptionResolvers(context), 其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?这就需要有一个专门的角色对异常情况进行处理,在SpringMVC中就是 HandlerExceptionResolver。具体来说,此组件的作用是根据异常设置ModelAndView,之后再交给 render方法进行渲染。
- ViewResolver initViewResolvers(context),ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。这里就有两个关键问题:使用哪个模板?用什么技术(规则)填入参数?这其实是ViewResolver 主要要做的工作,ViewResolver需要找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染,具体的渲染过程则交由不同的视图自己完成。
- RequestToViewNameTranslator initRequestToViewNameTranslator(context),ViewResolver是根据ViewName查找View,但有的 Handler处理完后并没有设置View也没有设置ViewName,这时就需要从request获取ViewName了,如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。RequestToViewNameTranslator在Spring MVC容器里只可以配置一个,所以所有request到 ViewName的转换规则都要在一个Translator里面全部实现。
- LocaleResolver initLocaleResolver(context), 解析视图需要两个参数:一是视图名,另一个是Locale。视图名是处理器返回的,Locale是从哪里来的?这就是LocaleResolver要做的事情。LocaleResolver用于从request 解析出Locale,Locale就是zh-cn之类,表示一个区域,有了这个就可以对不同区域的用户显示不同的结果。SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
- ThemeResolver initThemeResolver(context),用于解析主题。SpringMVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、如图片、css样式等。SpringMVC的主题也支持国际化,同一个主 题不同区域也可以显示不同的风格。SpringMVC中跟主题相关的类有 ThemeResolver、ThemeSource 和Theme。主题是通过一系列资源来具体体现的,要得到一个主题的资源,首先要得到资源的名称,这是ThemeResolver的工作。然后通过主题名称找到对应的主题(可以理解为一个配置)文件,这是 ThemeSource的工作。 后从主题中获取资源就可以了。
- MultipartResolver initMultipartResolver(context),用于处理上传请求。处理方法是将普通的request包装成 MultipartHttpServletRequest,后者可以直接调用getFile方法获取File,如果上传多个文件,还可以调用getFileMap得到FileName->File结构的Map。此组件中一共有三个方法,作用分别是判断是不是上传请求,将request包装成MultipartHttpServletRequest、处理完后清理上传过程中产生的临时资源。
- FlashMapManager initFlashMapManager(context),用来管理FlashMap的,FlashMap主要用在redirect中传递参数。
-- 源自 陈橘又青的博客
1.5 SpringMVC 工作流程***
编辑
- 用户发送请求至前端控制器 DispatcherServlet。
- DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
- 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器及处理器拦截器 (如果有则生成)一并返回给 DispatcherServlet。
- DispatcherServlet 调用 HandlerAdapter 处理器适配器。
- HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller 执行完成返回 ModelAndView。
- HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet。8) DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器。
- ViewReslover 解析后返回具体 View。
- DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet 响应用户。
🎨2. Spring MVC 的使用
学习 Spring MVC 我们只需要掌握以下 3 个功能:
- 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的 Spring 程序。
- 获取参数的功能:用户访问的时候会带一些参数,在程序中要想办法获取到参数。
- 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。
2.1 Spring MVC 的连接
Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作用。
1. 创建 Spring MVC 项目
Spring MVC 项目创建和 Spring Boot 创建项目相同(Spring MVC 使用 Spring Boot 的方式创建),在 创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项目。
创建一个 Test1类,实现用户到 Spring 程序的互联互通:
@Slf4j @ResponseBody // 返回一个 text/html 信息(响应体) @Controller @RequestMapping("/test1") public class Test1 { @RequestMapping("/hello") public String sayWord(){ log.info("hello"); return "word"; } }
2. @RequestMapping 注解介绍
@RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的。
@RequestMapping 即可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类 + 方法。
上面代码的访问地址就是 127.0.0.1:8080/test1/hello
3. @RequestMapping 是 post 还是 get 请求?
@RequestMapping 默认是 get 方式的请求,可以使用 Apipost6进行测试。
编辑
如何接收 post 请求? 我们可以显示的指定 @RequestMapping 来接收 POST 的情况
@RequestMapping(value = "/hi",method= RequestMethod.POST)
4. @GetMapping 和 PostMapping
get 请求的 3 种写法:
// 方法一: @RequestMapping("/hello") // 方法二: @RequestMapping(value = "/hello", method = RequestMethod.GET) // 方法三: @GetMapping("/hello")
post 请求的 2 种写法:
// 方法一: @RequestMapping(value = "/hello", method = RequestMethod.POST) // 方法二: @PostMapping("/hello")
2.2 获取参数
1. 传递单个参数
@RequestMapping("/method1") @ResponseBody public String method1(String name){ System.out.println("请求参数:" + name); return name; }
编辑
2. 传递对象
@Data class Person{ public String name; public String gender; } @RequestMapping("/method2") @ResponseBody public String method2(Person person){ System.out.println("请求对象:" + person); return person.name + " " +person.gender; }
3. 表单参数传递/传递多个参数(非对象)
@RequestMapping("/method3") @ResponseBody public String method3(String name, String gender){ System.out.println(name + " " + gender); return name + " " + gender; }
4. 参数重命名
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 字段 key 可以不一致,可以使用 @RequestParam 来重命名前后端的参数值。
@RequestMapping("/method4") @ResponseBody public String method4(@RequestParam("time") String getTime){ System.out.println(getTime); return getTime; }
5. 设置参数必传
@RequestParam 上面的列子,如果我们是前端传递一个非 time 的参数,就会出现程序报错的情况。
非必传参数设置
如果我们的实际业务前端的参数是一个非必传的参数,我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错,具体实现如下:
@RequestMapping("/method5") @ResponseBody public String method5(@RequestParam(value = "time", required = false) String getTime){ System.out.println(getTime); return getTime; }
6. @RequestBody 接收JSON对象
@RequestMapping(value = "/method6", method = RequestMethod.POST) public Object method6(@RequestBody Person person) { System.out.println("Person:" + person); return "redirect:/index.html"; }
7. 获取URL中参数@PathVariable
@PostMapping("/method7/{name}/{password}") @ResponseBody public String method7(@PathVariable String name, @PathVariable String password){ System.out.println(name + " " + password); return name + " " + password; }
8. 上传文件@RequestPart
@RequestMapping("/method8") public String method7(String name, @RequestPart("myfile") MultipartFile file) throws IOException { // 获取文件后缀名 String fileName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") ); // 文件保存地址 String filePath = ClassUtils.getDefaultClassLoader().getResource("static").getPath() + "/" + UUID.randomUUID() + fileName; // 保存文件 file.transferTo(new File(filePath)); return filePath + " 上传成功."; }
9. 获取Cookie/Session/header
@RequestMapping("/method9") @ResponseBody() public String method9( HttpServletRequest req, HttpServletResponse res, HttpSession session) { //... return "..."; }
2.3 返回数据
1. 返回静态页面
@RequestMapping("/index") public Object index(){ return "/index.html"; }
2. 返回 text/html
@RequestMapping("/method10") @ResponseBody public String method10(){ return "hello word"; }
3. 返回 JSON 对象
@RequestMapping("/method11") @ResponseBody public Map<Integer, Integer> method11(){ Map<Integer, Integer> map = new HashMap<>(); map.put(1, 1); map.put(2, 2); map.put(3, 3); return map; }
4. 请求转发或请求重定向(两者区别)
// 请求重定向 @RequestMapping("/index2") public String index2(){ return "redirect:/index.html"; } // 请求转发 @RequestMapping("/index3") public String index3(){ return "forward:/index.html"; }
forward 和 redirect 具体区别:
- 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
- 请求重定向地址发生变化,请求转发地址不发生变化。
- 请求重定向与直接访问新地址效果一直,不存在原来的外部资源不能访问;请求转发服务器端转发 有可能造成原外部资源不能访问。
5. @ResponseBody
说明 @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端。
@ResponseBody 可以用来修饰方法或者是修饰类,修饰类表示类中的所有方法都会返回 html 或者 json,而不是视图。
6. 组合注解:@RestController
@RestController = @Controller + @ResponseBody
分享到此,感谢大家观看!!!
如果你喜欢这篇文章,请点赞加关注吧,或者如果你对文章有什么困惑,可以私信我。
🏓🏓🏓