Spring MVC执行原理与杂七杂八记录文

Spring MVC执行原理

总的来说,Spring MVC框架在之前的基础上增加了一层 DispatcherServlet(调度Servlet)。而它的作用是将请求分发到各个不同的处理器(Servlet)。
下图是整个执行过程,实现为spring自动实现的操作,虚线是我们手动。
640.png

当我们获得一个请求的时候会进入DispatcherServlet,首先通过HandlerMaping去寻找我们对应servlet的映射,其次进入HandlerExecution中查找这个控制器,然后返回到DispatcherServlet。

之后通过HandlerAdapter去适配这个控制器,通过这个适配器去执行我们编写的controller。

假设我们请求到 “/hello” ,Spring会寻找一个maping未 “/hello” 的映射器,然后再找到这个映射对应的“业务类”。而这个业务类会获取两个数据 “Model And View”,很显然,model是指要返回的数据,而view是指要返回的对应界面。

值得注意的是,我们现在都提倡前后端分离,所以一般情况下我们并不会按照这个逻辑进行返回view。

当controller执行完毕后,会通过适配器再返回到DispatcherServlet,再由它向ViewResolver进行解析model和view,最后拼合成一个完整的视图,

再由DispatcherServlet返回给用户。

通过以上流程一步步走,很显然,如果我们要编写Spring MVC,我们只需要创建一个Servlet调度器——DispatcherServlet,Controller,ViewResolver,三个东西就可以实现开发~

创建DispatcherServlet

首先,我们就需要在web.xml中加入以下代码。我们值得注意的是,我们需要在DispatcherServlet中配置它。所以需要另外创建一个配置文件springmvc-servlet.xml

我们的所有配置其实都是基于DispatcherServlet。需要配置:ViewResolver视图解析器、注解支持..


<servlet>
    <servlet-name>SringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>SringMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

springmvc-servlet.xml配置

值得注意的是,这个名字是自定的。
首先,contex:component-scan,这个之前在spring记录文中有记录,即扫描该包名下的注解。
第二个的含义是让spring mvc不处理静态资源。如果不适用这个,当用户请求一个静态资源的时候,spring mvc也会按照上面那个流程走...

其次是让mvc的注解生效,后面我们会学到mvc中独有的几个注解。

再之后便是配置视图解析器,这里先不做记录。

<context:component-scan base-package="com.kum.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>

<!-- 视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

自此,配置完毕。

controller

当配置完毕后,我们就需要编写一个控制器,我们只需要在一个类的标题上写上 @controller注解,便可以声明这是一个控制器。

在控制器中使用 @RequestMapping("h1") 便是对 “/hi” 这个请求进行处理。
可以说RequestMapping注解就是绑定一个请求地址。

在之前我们说过,controller会返回 model and view,我们直接加入一个Model的参数进行添加即可。它是一个键值对的结构。

之后返回的一个string,其实含义是指 /WEB-INF/jsp/ 文件夹下的 hello.jsp 文件。
此时返回到视图解析器配置文件中,是不是就突然懂了? 这样方便我们进行编写~

@RequestMapping("h1")
public String hello(Model model){
    model.addAttribute("msg","Hello spring mav controller");
    return "hello";

}

但视图解析器是需要将model放到hello.jsp之中的,很显然有一个key叫“msg”的数据,我们只需要在jsp中加入 “${msg}” 即可将“Hello spring mav controller"放置jsp其中。

自此便结束。

使用Json数据格式进行相应

前面说了,目前在一个前后端分离的趋势之中,后端其实只需要编写一个接口交给前端进行使用,而不再操控view层,这样降低很多的耦合性。

所以我们将抛弃视图解析器,直接返回一个字符串(Json也是一个字符串,只不过按照一个格式~)。
我们需要在@RequestMapping注解的基础上增加一个 @ResponseBody() 注解,这样就说明我们的方法直接返回一个数据。

@ResponseBody()
@RequestMapping("h2")
public String hello1(){
    return "2333";
}

如上,当请求”/h2“的时候,只会返回一个 ”2333“ 这样的字符串。

我们都知道,实际上json只不过是一种有结构层次的字符串。很显然,只需要使用某个库转换一下就ok了。这里使用fastjson.

User user = new User("阿萨斯", 20, "男");
String str = JSON.toJSONString(user);
return str;

user类

@Data
@AllArgsConstructor
@NoArgsConstructor

public class User {
    private String name;
    private int age;
    private String sex;

}

最终在界面中呈现的数据:

{"name":"阿萨斯","age":20,"sex":"男"}