SpringMVC参数绑定的原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC参数绑定的原理相关的知识,希望对你有一定的参考价值。

参考技术A 1、通过IOC扫描得到所有的Bean
2、针对有Controller注解的Bean,将其方法、Bean、映射的url放到Handler中
3、DispatchServlet中得到请求后,根据url找到对应的方法。
4、最后调用方法的时候需要进行参数绑定,根据参数类型和参数名字对应上方法的名字和方法填充参数数组,最后调用方法即可。

参数绑定的时候可能需要参数的名字,而编译的时候不一定会将参数的名字和行数等信息编译进去,因此我们使用javac的时候需要打开-g:vars或者-parameter选项,用maven编译的时候会自动使用-g选项。参考 Spring MVC - Automatic Parameter Names Discovery

Spring MVC详解(学习总结)

文章是看楠哥的视频做的总结,自己还查阅了一些资料,文章也加了自己的总结,这篇博客可以帮助大家入门,还有一些知识大家如果用到的话可以到时候再去学习一下,我写这篇主要是为了方便后面复习。

一、Sprig MVC简介

1.1介绍

Spring MVC是Spring Framework提供的Web组件,全称是Spring Web MVC,是目前主流的实现MVC设计模式的框架,提供前端路由映射、视图解析等功能

Java Web开发者必须要掌握的技术框架

1.2MVC是什么

MVC是一种软件架构思想,把软件按照模型,视图,控制器来划分
Model:模型层,指工程中的JavaBean,用来处理数据
JavaBean分成两类:

  • 一类称为实体类Bean:专门用来存储业务数据,比如Student,User
  • 一类称为业务处理Bean:指Servlet或Dao对象,专门用来处理业务逻辑和数据访问
    View:视图层,指工程中的html,jsp等页面,作用是和用户进行交互,展示数据
    Controler:控制层,指工程中的Servlet,作用是接收请求和响应浏览器
  • 流程:
    • 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收
    • Controller调用相应的Model层处理请求,处理完毕后结果返回到Controller
    • Controller再根据请求处理的结果找到对应的View视图,渲染数据后最终响应给浏览器

      Spring MVC对这套MVC流程进行封装,帮助开发者屏蔽底层细节,并且开放出相关接口供开发者调用,让MVC开发更简单方便

二、Spring MVC实现原理

2.1核心组件

  • DispatcherServlet:前置控制器,负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块
  • Handler:处理器,完成具体的业务逻辑,相当于Servlet
  • HandlerMapping:DispatcherServlet是通过 HandlerMapping把请求映射到不同的Handler
  • HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要进行一些拦截处理,可以通过实现该接口完成
  • HandlerExecutionChain:处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果有额外拦截处理,可以添加拦截器进行设置)
  • HandlerAdapter:处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型转换、把表单数据封装到POJO等,这些一系列的操作都是由HandlerAdapter完成,DispatcherServlet通过HandlerAdapter执行不同的Handler
  • ModelAndView:封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet
  • ViewResolver:视图解析器,DispatcherServlet通过它把逻辑视图解析为物理视图,最终把渲染的结果响应给客户端

2.2工作流程

  1. 客户端请求被DispatcherServlet接收
  2. 根据HandlerMapping映射到Handler
  3. 生成Handler和HandlerInterceptor
  4. Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet
  5. DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理
  6. 返回一个ModelAndView对象给DispatcherServlet
  7. DispatcherServlet把获取的ModelAndView对象传给ViewResolver视图解析器,把逻辑视图解析成物理视图
  8. ViewResolver返回一个View进行视图渲染(把模型填充到视图中)
  9. DispatcherServlet把渲染后的视图响应给客户端

三、第一个Spring MVC

  1. 创建maven改成工程,pom.xml加入Spring MVC的依赖




    pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>SpringMVC</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>SpringMVC Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.19</version>
    </dependency>

  </dependencies>


</project>

 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.19</version>
        </dependency>
  1. 在web.xml中配置Spring MVC的DispatcherServlet
    首先在项目中创建java和resources的目录

    在resources目录中添加springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

然后在web.xml 配置Spring MVC的DispatcherServlet

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
 <!-- 配置核心控制器 -->
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- springmvc配置文件加载路径
		     1)默认情况下,读取WEB-INF下面的文件
		     2)可以改为加载类路径下(resources目录),加上classpath:
		 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<!--
		   DispatcherServlet对象创建时间问题
		      1)默认情况下,第一次访问该Servlet的创建对象,意味着在这个时间才去加载springMVC.xml
		      2)可以改变为在项目启动时候就创建该Servlet,提高用户访问体验。
		          <load-on-startup>1</load-on-startup>
		                数值越大,对象创建优先级越低! (数值越低,越先创建)
		-->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		 <!--/ 匹配所有的请求;(不包括.jsp)-->
   <!--/* 匹配所有的请求;(包括.jsp)-->
    <!--*.do拦截以do结尾的请求-->
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
  
  
</web-app>

拦截请求其实就是说,只要是符合这个URL的请求都会进入到Spring MVC中去看看有没有对应的Handler./不会拦截.jsp的路径,但是会拦截.html等静态资源

  • DispatcherServlet是Spring MVC提供的核心控制器,这个一个Servlet程序,该Servlet程序会接收所有请求
  • 核心控制器会读取一个springmvc.xml配置,加载Spring MVC的核心配置
  • 配置/代表拦截所有请求
  • 代表在项目启动时实例化DispathcerServlet,如果没有配置,则在第一次访问Servlet时进行实例化

3.springmvc.xml进行配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 配置自动扫包 -->
    <context:component-scan base-package="com.zyh.controller"></context:component-scan>

    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--给逻辑视图加上前缀和后缀 -->
        <!--前缀-->
        <property name="prefix" value="/"></property>
        <!--后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>
  1. 创建Controller控制器Handler,在里面编写接收参数,调用业务方法,返回视图页面等逻辑
@Controller
public class HelloHandler 
    /**
     * 当客户端访问index请求时
     * 直接自动关联到这个方法
     * 执行这个方法后,会返回结果
     * @return
     */
    @RequestMapping("/index")
    public String index()
        System.out.println("接收到了请求");
        //返回逻辑视图 逻辑视图相当于视图的别名 通过这个找到物理视图,也就是真正的视图
        //这里返回的只是页面的名称,不是完整的页面访问路径
        return "index";
    

@Controller注解是为了让Spring IOC容器初始化时自动扫描到该Controller类;@RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/;方法返回的结果是视图的名称index,该名称不是完整页面路径,最终会经过视图解析器解析为完整页面路径并跳转。
配置Tomcat


5. 测试



流程梳理

  1. DispatcherServlet接收到URL请求index,结合@RequestMapping(“/index”)注解把该请求交给index业务方法进行处理
  2. 执行index业务方法,控制台打印日志,并且返回"index"字符串(逻辑视图).
  3. 结合springmvc.xml中的视图解析器配置,找到目标资源:/index.jsp,即根目录下的index.jsp文件,把该JSP资源返回给客户端完成响应。

Spring MVC搭建成功

四、常用注解

@RequestMapping

Spring MVC通过@RequestMapping注解把URL请求和业务方法进行映射,在控制器的类定义处以及方法定义处都可以添加@RequestMapping,在类定义处添加相当于多了一层访问路径

@RequestMapping常用参数

  • value:指定URL请求的实际地址,是@RequestMapping的默认值
  • method:指定请求的method类型,包括GET、POST、PUT、DELETE等
   @RequestMapping(value = "/index",method = RequestMethod.POST)
    public String index()
        System.out.println("接收到了请求");
        //返回逻辑视图 逻辑视图相当于视图的别名 通过这个找到物理视图,也就是真正的视图
        //注意:这里返回的只是页面名称,不是完整的页面访问路径
        return "index";
    

上述代码表示只有POST请求可以访问该方法,如果使用其他请求访问的话,直接抛出异常,比如GET请求

  • params:指定request请求中必须包含的参数值,如果不包含的话,就无法调用该方法

五、参数绑定

5.1URL风格参数绑定

params是对URL请求参数进行限制,不满足条件的URL无法访问该方法,需要在业务方法中获取URL的参数值。

  1. 在业务方法定义时声明参数列表
  2. 给参数列表添加@RequestParam注解进行绑定



Spring MVC可以自动完成数据类型转换,该工作是由HandlerAdapter来完成的

5.2RESTful风格的URL参数获取

  • 传统的URL:localhost:8080/hello/index?id=1&name=tom
  • RESTful URL:localhost:8080/hello/index/1/tom
 @RequestMapping("/restful/id/name")
    public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name)
        System.out.println(num+"-"+name);
        return "index";
    

5.3映射Cookie

  @RequestMapping("/cookie")
    public String getCookie(@CookieValue("JSESSIONID") String sessionId)
        System.out.println(sessionId);
        return "index";
    

5.4使用POJO绑定参数

Spring MVC会根据请求参数名和POJO属性名进行匹配,自动为该对象填充属性值,并且支持属性级联
首先创建实体类

为了方便测试,写一个addUser.jsp页面

<%--
  Created by IntelliJ IDEA.
  User: 17614
  Date: 2022-07-04
  Time: 21:01
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/hello/add" method="post">
    <table>
        <tr>
            <td>编号:</td>
            <td>
                <input type="text" name="id">
            </td>
        </tr>
        <tr>
            <td>姓名:</td>
            <td>
                <input type="text" name="name">
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="提交">
            </td>
        </tr>
    </table>


</form>

</body>
</html>

然后在Handler中,编写相关方法

启动Tomcat服务器

结果发现出现乱码问题

为了解决这个问题,我们只需要在web.xml配置文件中配置过滤器就可以了

  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


接下来看看属性级联是如何操作

addUser.jsp

<%--
  Created by IntelliJ IDEA.
  User: 17614
  Date: 2022-07-04
  Time: 21:01
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/hello/add" method="post">
    <table>
        <tr>
            <td>编号:</td>
            <td>
                <input type="text" name="id">
            </td>
        </tr>
        <tr>
            <td>姓名:</td>
            <td>
                <input type="text" name="name">
            </td>
        </tr>
        <tr>
            <td>地址编号:</td>
            <td>
                <input type="text" name="address.code">
            </td>

        </tr>
        <tr>
            <td>地址信息:</td>
            <td>
                <input type="text" name="address.value">
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="提交">
            </td>
        </tr>
    </table>


</form>

</body>
</html>

JavaSpringMVC:核心源码映射规则参数绑定

springmvc学习笔记(11)-springmvc注解开发之简单参数绑定

springmvc学习笔记(13)-springmvc注解开发之集合类型参数绑定

SpringMVC详解------参数绑定

SpringMVC请求参数的绑定

SpringMVC学习——SpringMVC高级参数绑定与@RequestMapping注解