• [Spring] SpringMVC 简介(一)


    目录

    一、SpringMVC 简介

    1、什么是 MVC

    2、什么是 SpringMVC

    3、SpringMVC 实现原理

    4、SpringMVC 的特点

    二、简单案例

    1、引入依赖

    2、在 web.xml 中配置前端控制器 DispatcherServlet

    3、创建 SpringMVC 的配置文件

     4、创建请求控制器

    5、测试页面

    6、访问不到 Controller

    7、修改项目结构

    三、@RequestMapping

    1、@RequestMapping 注解的功能

    2、@RequestMapping 注解的位置

    3、@RequestMapping 的 value 属性

    4、@RequestMapping 的 method 属性

    5、SpringMVC 支持 ant 风格的路径

    6、@RequestMapping 中的占位符(@PathVariable 重点)

    四、SpringMVC 获取请求参数

    1、通过 ServletAPI 获取

    2、通过设置方法形参名与请求参数名一致

    3、通过 POJO 获取请求参数

    4、解决中文乱码


    一、SpringMVC 简介

    1、什么是 MVC

    记住一句话:SpringMVC 封装了 Servlet

    (1)MVC

    M:Model,模型层,指工程中的JavaBean,作用是处理数据

    JavaBean分为两类:

    • 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
    • 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

    V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

    C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

    (2)工作流程

    用户通过视图层发送请求到服务器,在服务器中请求被 Controller 接收,Controller 调用相应的 Model 层处理请求,处理完毕将结果返回到 Controller,Controller 再根据请求处理的结果找到相应的 View 视图,渲染数据后最终响应给浏览器。

    2、什么是 SpringMVC

    (1)三层架构

    我们通过浏览器访问前端页面,前端页面通过异步提交的方式,发送请求到后端服务器,后端服务器采用 web层(servlet)、业务层(service)、数据层(dao)的三层架构形式进行开发,其中数据的交互使用 json 来传输。

    • 我们最开始在数据层使用的是 Jdbc 技术,而 MyBatis 就是对 Jdbc 技术的又一层封装,也可以称之为数据层框架。
    • 现在所讲的 SpringMVC,在 web 层中与 servlet 的关系,就好比 Jdbc 与 MyBatis 的关系,也就是一个表现层的框架。

    (2)SpringMVC 是一种基于 Java 实现 MVC 模型的轻量级 Web 框架

    • 框架:半成品软件,加速开发过程。
    • 相比较 Servlet,使用更简单,开发更便捷,更灵活

    3、SpringMVC 实现原理

    (1)用户发送请求到前端控制器 DispatcherServlet

    • DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心

    (2)DispatcherServlet 收到请求后调用处理器映射器 HandlerMapping

    • 处理器映射器 HandlerMapping 找到 Controller 的具体方法(可以根据 xml 配置或注解进行查找),并将该方法返回给 DispatcherServlet;

    (3)DispatcherServlet 调用处理器适配器 HandlerAdapter

    (3-1)HandlerAdapter 经过适配调用具体的 Controller 的方法;(Controller--> service --> Dao --> 数据库)

    • Controller 执行完成后返回 ModelAndView;
    • Model:模型数据,即 Controller 处理的结果,是一个 Map
    • View:逻辑视图名,即 负责展示结果的 html 页面的名字

    (3-2)HandlerAdapter 将 Controller 执行的结果 ModelAndView 返回给 DispatcherServlet

    (4)DispatcherServlet 将执行的结果 ModelAndView 传给视图解析器 ViewReslover

    • 视图解析器 ViewReslover 根据逻辑视图 View 解析后返回具体 html 页面

    (5)DispatcherServlet 根据 Model 对 View 进行渲染(将模型数据填充至视图中)

    • DispatcherServlet 将填充了数据的网页响应给用户

    4、SpringMVC 的特点

    • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
    • 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理(不在需要自己编写 Servlet 处理请求)
    • 代码清新简洁,大幅度提升开发效率
    • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
    • 性能卓著,尤其适合现代大型、超大型互联网项目要求

    二、简单案例

    1、引入依赖

    即将使用 Thymeleaf 视图模板技术,因此引入了相关依赖。

    1. <dependencies>
    2. <dependency>
    3. <groupId>javax.servletgroupId>
    4. <artifactId>javax.servlet-apiartifactId>
    5. <version>3.1.0version>
    6. <scope>providedscope>
    7. dependency>
    8. <dependency>
    9. <groupId>org.springframeworkgroupId>
    10. <artifactId>spring-webmvcartifactId>
    11. <version>5.3.1version>
    12. dependency>
    13. <dependency>
    14. <groupId>org.thymeleafgroupId>
    15. <artifactId>thymeleaf-spring5artifactId>
    16. <version>3.0.12.RELEASEversion>
    17. dependency>
    18. dependencies>

    2、在 web.xml 中配置前端控制器 DispatcherServlet

    1. <servlet>
    2. <servlet-name>DispatcherServletservlet-name>
    3. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    4. servlet>
    5. <servlet-mapping>
    6. <servlet-name>DispatcherServletservlet-name>
    7. <url-pattern>/url-pattern>
    8. servlet-mapping>

    (1)标签中使用 / 和 /* 的区别

    • /:匹配浏览器向服务器发送的所有请求,不包括 jsp;
    • /*:匹配浏览器向服务器发送的所有请求,包括 jsp;

    JSP 是通过 Tomcat 的 JspServlet 来处理的,然后 JspServlet 将响应结果回传给页面,所以 DispatcherServlet 处理不了 jsp 页面。

    • 因此 DispatcherServlet 要使用 /,而不能用 /*。
    • 在使用过滤器时,若需要对所有请求进行过滤,就需要使用 /* 的写法。

    3、创建 SpringMVC 的配置文件

    (1)SpringMVC 的配置文件的默认地址和名称:

    • 地址:在 WEB-INF 目录下;
    • 名称:-servlet.xml;( 是 web.xml 内 DispatcherServlet 的值,比如 DispatcherServlet-servlet.xml)

    实际开发中,通常将 SpringMVC 的配置文件放在 resource 目录下

    (2)Thymeleaf 模板文件路径

    • 物理视图:视图前缀 + 逻辑视图 + 视图后缀;
    • 逻辑视图:把物理视图中的视图前缀和视图后缀去掉,得到的就是逻辑视图;

    我们通常在 WEB-INF 目录下建立一个 templates 目录,用来存放视图模板。而访问 WEB-INF 目录下的资源,需要服务器端进行请求转发,所以逻辑视图就被用上了。 

    (3)配置文件

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    5. <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    6. <property name="order" value="1"/>
    7. <property name="characterEncoding" value="UTF-8"/>
    8. <property name="templateEngine">
    9. <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
    10. <property name="templateResolver">
    11. <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    12. <property name="prefix" value="/WEB-INF/templates/"/>
    13. <property name="suffix" value=".html"/>
    14. <property name="templateMode" value="HTML5"/>
    15. <property name="characterEncoding" value="UTF-8" />
    16. bean>
    17. property>
    18. bean>
    19. property>
    20. bean>
    21. beans>

     4、创建请求控制器

    (1)@Controller

    由于 DispatcherServlet 已经对浏览器发送的请求进行了统一的处理,所以我们不需要自己创建 Servlet 去处理请求。

    但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器

    1. package com.demo.controller;
    2. import org.springframework.stereotype.Controller;
    3. @Controller
    4. public class HelloController {
    5. }

    SpringMVC 的控制器由一个 POJO(普通的Java类)担任,因此需要通过 @Controller 注解将其标识为一个控制层组件,交给 Spring 的 IOC 容器管理,此时 SpringMVC 才能够识别控制器的存在。

    (2)@RequestMapping

    请求映射:把浏览器发送的请求,映射到具体方法去处理。

    (2-1)其中的 value 属性值,填写的是方法的路径:

    • /:代表该路径为绝对路径;
    • / 由服务器解析:代表 http://ip:port/工程名;
    • / 由浏览器解析:代表当前服务器路径,http://ip:port;

    当 value 的值,与浏览器发送的请求路径是一样的,说明这个方法就是用来处理该请求的方法。

    (2-2)方法返回值

    前面我们说到,服务器端进行请求转发需要用到逻辑视图,那么怎么用呢?

    其实我们返回的字符串,就是所谓的逻辑视图。紧接着 web.xml 中配置的视图解析器,就会将这个返回值用视图前缀和视图后缀组装起来,最终形成了请求转发的地址。

    1. package com.demo.controller;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.RequestMapping;
    4. @Controller
    5. public class HelloController {
    6. @RequestMapping("/")
    7. public String index() {
    8. System.out.println("index");
    9. // 返回逻辑视图
    10. return "index";
    11. }
    12. @RequestMapping("/hello")
    13. public String hello() {
    14. return "hello";
    15. }
    16. }

    5、测试页面

    注意:测试页面使用了 Thymeleaf 的语法。

    (1)index.html

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <h1> index 页面 h1>
    9. <a th:href="@{/hello}"> 测试 SpringMVC a>
    10. <br/>
    11. <a href="/hello"> 测试绝对路径a>
    12. body>
    13. html>

    (2)hello.html

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <h1> hello h1>
    9. body>
    10. html>

    (3)项目结构

    6、访问不到 Controller

    SpringMVC 访问不到 Controller,网上有很多解决方法,如果再尝试之后都没有办法解决(比如我),那么可以尝试删除当前工件,新建一个该项目的工件。

    有关更多项目结构问题,可以查看:https://www.bilibili.com/video/BV1Ry4y1574R?p=15 

    按照其中的步骤,设置 web 目录即可。

    7、修改项目结构

    将 DispatcherServlet-servlet.xml 文件,放到 resource 目录下,然后在 web.xml 文件中作如下修改:

    1. <servlet>
    2. <servlet-name>DispatcherServletservlet-name>
    3. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    4. <init-param>
    5. <param-name>contextConfigLocationparam-name>
    6. <param-value>classpath:SpringMVC.xmlparam-value>
    7. init-param>
    8. <load-on-startup>1load-on-startup>
    9. servlet>
    10. <servlet-mapping>
    11. <servlet-name>DispatcherServletservlet-name>
    12. <url-pattern>/url-pattern>
    13. servlet-mapping>

    (1)contextConfigLocation

    这是正常项目中 Spring 配置文件放置在 resource 目录下的写法。

    (2)

    由于 DispatcherServlet 需要初始化的内容非常地多,因此将其放在服务器启动期间去初始化,可以节省页面访问的时间。

    三、@RequestMapping

    1、@RequestMapping 注解的功能

    • @RequestMapping 注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
    • SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。

    2、@RequestMapping 注解的位置

    • @RequestMapping 仅仅标识了方法,那么可以直接访问到这个方法;
    • @RequestMapping 标识了类,那么想要访问方法,请求路径就必须添加标识类上面写的路径;

    如下面代码所示:

    1. @Controller
    2. @RequestMapping("/manager")
    3. public class ManagerController {
    4. @RequestMapping("/user")
    5. public String user() {
    6. return "user";
    7. }
    8. }

    请求路径为:

    http://ip:port/工程路径/manager/user
    • 而如果在两个不同的 Controller 里面有相同的 @RequestMapping,那么会直接报错。
    • 但是对于同一个资源,只要请求路径不同,那么就不会报错,比如:/manager/hello 和 /hello,都可以访问到 hello.html。

    3、@RequestMapping 的 value 属性

    一个 Servlet 可以处理多个请求(在 url-pattern 中设置),同样的,value 属性值为数组的时候,就可以接收多个请求。

    1. @Controller
    2. @RequestMapping("/manager")
    3. public class ManagerController {
    4. @RequestMapping({"/hello", "/also_hello"})
    5. public String hello() {
    6. return "hello";
    7. }
    8. }

    4、@RequestMapping 的 method 属性

    • method 属性通过请求的请求方式(get 或 post)匹配请求映射。
    • method 属性是一个 RequestMethod 类型的数组,表示该请求映射能够匹配多种请求方式的请求。

    若当前请求的请求地址满足请求映射的 value 属性,但是请求方式不满足 method 属性,则浏览器报错 405。

    1. @RequestMapping(
    2. value = {"/hello"},
    3. method = {RequestMethod.GET, RequestMethod.POST}
    4. )
    5. public String hello() {
    6. return "hello";
    7. }

    (1)对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解

    • 处理get请求的映射–>@GetMapping
    • 处理post请求的映射–>@PostMapping
    • 处理put请求的映射–>@PutMapping
    • 处理delete请求的映射–>@DeleteMapping

    (2)常用的请求方式有get,post,put,delete

    • 但是目前浏览器只支持 get 和 post,若在 form 表单提交时,为 method 设置了其他请求方式的字符串(put 或 delete),则按照默认的请求方式 get 处理
    • 若要发送 put 和 delete 请求,则需要通过 spring 提供的过滤器 HiddenHttpMethodFilter,在 RESTful 部分会讲到

    5、SpringMVC 支持 ant 风格的路径

    ant 风格的路径是指:

    • ?:表示任意的单个字符
    • *:表示任意的0个或多个字符
    • **:表示任意的一层或多层目录

    在 @RequestMapping 中,value 属性值可以包含上面三种格式。

    1. @RequestMapping("/a?a/test/ant")
    2. public String testAnt() {
    3. return "hello";
    4. }
    5. @RequestMapping("/a?a/*/ant")
    6. public String testAnt2() {
    7. return "hello";
    8. }
    9. @RequestMapping("**ant")
    10. public String testAnt3() {
    11. return "hello";
    12. }

    以上代码,下面三种请求路径都能访问到 hello.html: 

    6、@RequestMapping 中的占位符(@PathVariable 重点)

    @RequestMapping 修饰的方法想要使用请求参数的方法有很多,其中一种就是在 @RequestMapping 的 value 属性中使用“占位符{ }”。

    (1)书写格式

    假设请求路径 /func 可以访问到目标方法,通常我们添加参数,请求路径会这么写:

    /func?id=1&name=admin

    而如果使用 @RequestMapping,那么应该这么写:

    /func/1/admin

    (2)对应地,在代码中要怎么获取到这两个参数呢?

    1. @RequestMapping("/func/{id}/{name}")
    2. public String func(@PathVariable("id") String id, @PathVariable("name") String name) {
    3. System.out.println("id: " + id);
    4. System.out.println("name: " + name);
    5. return "index";
    6. }

    (3)请求路径:

    (4)输出结果:

    四、SpringMVC 获取请求参数

    1、通过 ServletAPI 获取

    如果要使用 servlet 相关的方法,那么给方法的参数列表添加 request 等参数即可。

    (1)测试代码

    (1-1)controller(success.html 可以自己写)

    1. @RequestMapping("/login")
    2. public String login(HttpServletRequest req) {
    3. System.out.println("username: " + req.getParameter("username"));
    4. System.out.println("password: " + req.getParameter("password"));
    5. return "success"; // return 相当于请求转发
    6. }

    (1-2)index.html

    1. <form th:action="@{/login}" method="post">
    2. <input type="text" name="username"/> <br/>
    3. <input type="password" name="password"/> <br/>
    4. <input type="submit" value="submit"/>
    5. form>

     (2)输出结果

    2、通过设置方法形参名与请求参数名一致

    在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参。

    (1)测试代码

    (1-1)controller

    1. @RequestMapping("/login/param")
    2. public String loginParam(String username, String password) {
    3. System.out.println("username: " + username);
    4. System.out.println("password: " + password);
    5. return "success";
    6. }

    (1-2)index.html(改了 action)

    1. <form th:action="@{/login/param}" method="post">
    2. <input type="text" name="username"/> <br/>
    3. <input type="password" name="password"/> <br/>
    4. <input type="submit" value="submit"/>
    5. form>

    (2)输出结果

     (3)@RequestParam

    • 如果在请求参数名方法参数名不一致,那么就会导致方法获取不到值,值为 null。

    为了保证一定能获取到对应值,可以使用 @RequestParam:

    public String loginParam(@RequestParam(value = "username", required = true) String username, String password)
    • value = "userName":设置从 userName 请求参数获取值,并且方法参数名不再需要与请求参数名一致
    • required = true:设置没有该请求参数,则不能发送请求;(默认就是 true)
    • required = false:设置可以不传该请求参数,若不传递,则值为 null
    • defaultValue:设置未传递参数时的默认值;(与 required 无关)

    (4)@RequestHeader

    • 将请求头信息与控制器方法的参数进行绑定,当为方法参数加上 @RequestHeader,那么该参数就不再对应请求参数,而是对应请求头信息。

    用法与 @RequestParam 一致。

    1. @RequestMapping("/login/param")
    2. public String loginParam(@RequestParam(value = "username") String name,
    3. String password,
    4. @RequestHeader(value = "referer") String refer) {
    5. System.out.println("username: " + name);
    6. System.out.println("password: " + password);
    7. System.out.println("referer: " + refer);
    8. return "success";
    9. }

    (5)@CookieValue

    • 将 cookie 数据与控制器方法的参数进行绑定,因为一开始还没有 JSESSIONID 的 cookie,因此需要先调用一次 request.getSession() 来创建 JSESSIONID 的 cookie。

    用法与 @RequestParam 一致。

    1. @RequestMapping("/login")
    2. public String login(HttpServletRequest req) {
    3. HttpSession session = req.getSession();
    4. System.out.println("创建 JSESSIONID: " + session.getId());
    5. return "index"; // return 相当于请求转发
    6. }
    7. @RequestMapping("/login/param")
    8. public String loginParam(@RequestParam(value = "username") String name,
    9. String password,
    10. @RequestHeader(value = "referer") String refer,
    11. @CookieValue(value = "JSESSIONID") String sessionId) {
    12. System.out.println("username: " + name);
    13. System.out.println("password: " + password);
    14. System.out.println("referer: " + refer);
    15. System.out.println("JSESSIONID: " + sessionId);
    16. return "success";
    17. }

    (5-1)先访问 /login,使服务器创建 JSESSIONID

    (5-2)输入 username、password,点击登录,观察控制台输出

    3、通过 POJO 获取请求参数

    通常情况下,我们会有非常多的方法参数需要设置/获取请求参数值,如果都用 @RequestParam 这几个注解来获取,也非常麻烦。

    (1)解决方法

    • 我们可以用一个 pojo 类当作方法的参数,让这个 pojo 类的成员变量名,与请求参数名一致,就可以将请求参数值,封装到 pojo 类的成员变量。
    1. @RequestMapping("/login/pojo")
    2. public String pojo(User user) {
    3. System.out.println(user);
    4. return "success";
    5. }

    (2) 输出结果

    4、解决中文乱码

    因为没有 request 和 response,所以无法用这两个变量设置。

    并且就算使用 request 和 response,其实也无法设置,因为其他参数都是已经从请求中获取到了,再设置也没有用了。

    注意:

    • Tomcat 7.0 的 get 和 post 请求都有乱码;Tomcat 8.0 以上 get 请求没有乱码,post 请求会乱码。

    (1)解决方法

    解决获取请求参数的乱码问题,可以使用 SpringMVC 提供的编码过滤器 CharacterEncodingFilter,再所有 servlet 处理之前,拦截所有请求,然后设置编码。

    需要注意的是,CharacterEncodingFilter 必须在 web.xml 中进行注册:

    • init-param 设置 encoding = utf-8,相当于 request.CharacterSetEncoding("UTF-8");
    • init-param 设置 forceEncoding = true,会把 request 和 response 都设置成 encoding(前面那个);

    (2)web.xml 配置文件

    1. <filter>
    2. <filter-name>CharacterEncodingFilterfilter-name>
    3. <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    4. <init-param>
    5. <param-name>encodingparam-name>
    6. <param-value>UTF-8param-value>
    7. init-param>
    8. <init-param>
    9. <param-name>forceResponseEncodingparam-name>
    10. <param-value>trueparam-value>
    11. init-param>
    12. filter>
    13. <filter-mapping>
    14. <filter-name>CharacterEncodingFilterfilter-name>
    15. <url-pattern>/*url-pattern>
    16. filter-mapping>

    (3)输出结果

  • 相关阅读:
    Windows 10 读取bitlocker加密的硬盘出现参数错误怎么解决?
    hadoop生态圈面试精华之zookeeper(一)
    competed中访问ref为undefined
    基础架构之Redis
    气传导耳机什么意思?备受好评的气传导耳机推荐
    2022-08-26 第六小组 瞒春 学习笔记
    Spire.OCR for .NET 1.9.0 Crack
    什么是CRM系统,它如何支持客户营销管理?
    TIDB--JMETER测试报告
    OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合
  • 原文地址:https://blog.csdn.net/joyride_run/article/details/133635596