SpringMVC

SpringMVC

Spring MVC概述

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建WEB应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现一般不用),Struts 2(一般老项目使用)等等。

image

Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称 Spring Web MVC 来⾃其源模块的名称Spring-webmvc,但它通常被称为 Spring MVC。

那么什么是Servet呢?为什么不直接使用Servet?

Servlet 是 Java 语言编写的服务器端程序,用于处理客户端发送的请求并生成响应。Servlet 运行在支持 Java Servlet 规范的 Web 服务器中,如 Apache Tomcat、Jetty 等。Servlet 提供了一种在 Web 服务器上动态生成 Web 内容的方式,可以处理各种类型的请求,如 HTTP 请求。尽管 Servlet 可以实现 Web 应用程序的各种功能,但它们通常是在较低级别上操作 HTTP 请求和响应的。使用 Servlet 编写应用程序需要处理很多底层细节,例如解析请求参数、处理会话管理、管理状态等。这些工作可以在开发 Web 应用程序时变得繁琐和重复。

MVC 是⼀种架构设计模式,,也⼀种思想(这种思想很早就有了,在Spring MVC之前可以通过其他的方式来实现), 而 Spring MVC 是对 MVC 思想的具体实现.。除此之外,SpringMVC还是⼀个Web框架。总结来说,Spring MVC 是⼀个实现了 MVC 模式的 Web 框架.

  • M (Model) :模型层,DAO封装,是应⽤程序的主体部分,用来处理程序中数据逻辑的部分。

  • V (View) :视图层,指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展示数据的资源,如vue/html/css/js/jsp等。

  • C (Controller) :控制层,Servlet封装,可以理解为⼀个分发器,⽤来决定对于视图发来的请求,需要⽤哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。

SpringMVC请求流程

image

核心架构的具体流程步骤如下:

  1. 首先用户发送请求 -> DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行 处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet -> HandlerMapping, HandlerMapping 将会把请求映射为 HandlerExecutionChain 对象(包含一 个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新 的映射策略;
  3. DispatcherServlet -> HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器, 即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter -> 处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处 理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
  5. ModelAndView 的逻辑视图名 -> ViewResolver,ViewResolver 将把逻辑视图名解析为具体的View,通过这种策 略模式,很容易更换其他视图技术;
  6. View -> 渲染,View 会根据传进来的Model 模型数据进行渲染,此处的Model 实际是一个Map 数据结构,因此 很容易支持其他视图技术;
  7. 返回控制权给DispatcherServlet,由DispatcherServlet 返回响应给用户,到此一个流程结束。

SpringMVC用例

Maven包引入

主要引入spring-webmvc包(spring-webmvc包中已经包含了Spring Core Container相关的包),以及servlet和jstl(JSP中使用jstl)的包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?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">
<parent>
<artifactId>tech-pdai-spring-demos</artifactId>
<groupId>tech.pdai</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>011-spring-framework-demo-springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>5.3.9</spring.version>
<servlet.version>4.0.1</servlet.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>

</project>

业务代码的编写

  • User

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    package tech.pdai.springframework.springmvc.entity;

    /**
    * @author pdai
    */
    public class User {

    /**
    * user's name.
    */
    private String name;

    /**
    * user's age.
    */
    private int age;

    /**
    * init.
    *
    * @param name name
    * @param age age
    */
    public User(String name, int age) {
    this.name = name;
    this.age = age;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }
    }

  • Dao

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package tech.pdai.springframework.springmvc.dao;

    import org.springframework.stereotype.Repository;
    import tech.pdai.springframework.springmvc.entity.User;

    import java.util.Collections;
    import java.util.List;

    /**
    * @author pdai
    */
    @Repository
    public class UserDaoImpl {

    /**
    * mocked to find user list.
    *
    * @return user list
    */
    public List<User> findUserList() {
    return Collections.singletonList(new User("pdai", 18));
    }
    }

  • Service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package tech.pdai.springframework.springmvc.service;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import tech.pdai.springframework.springmvc.dao.UserDaoImpl;
    import tech.pdai.springframework.springmvc.entity.User;

    import java.util.List;

    /**
    * @author pdai
    */
    @Service
    public class UserServiceImpl {

    /**
    * user dao impl.
    */
    @Autowired
    private UserDaoImpl userDao;

    /**
    * find user list.
    *
    * @return user list
    */
    public List<User> findUserList() {
    return userDao.findUserList();
    }

    }

  • Controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package tech.pdai.springframework.springmvc.controller;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.servlet.ModelAndView;
    import tech.pdai.springframework.springmvc.service.UserServiceImpl;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Date;

    /**
    * User Controller.
    *
    * @author pdai
    */
    @Controller
    public class UserController {

    @Autowired
    private UserServiceImpl userService;

    /**
    * find user list.
    *
    * @param request request
    * @param response response
    * @return model and view
    */
    @RequestMapping("/user")
    public ModelAndView list(HttpServletRequest request, HttpServletResponse response) {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("dateTime", new Date());
    modelAndView.addObject("userList", userService.findUserList());
    modelAndView.setViewName("userList"); // views目录下userList.jsp
    return modelAndView;
    }
    }

web.xml

webapp下的web.xml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

<display-name>SpringFramework - SpringMVC Demo @pdai</display-name>

<servlet>
<servlet-name>springmvc-demo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>springmvc-demo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

springmvc.xml

web.xml中我们配置初始化参数contextConfigLocation,路径是classpath:springmvc.xml

1
2
3
4
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>

在resources目录下创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- 扫描注解 -->
<context:component-scan base-package="tech.pdai.springframework.springmvc"/>

<!-- 静态资源处理 -->
<mvc:default-servlet-handler/>

<!-- 开启注解 -->
<mvc:annotation-driven/>

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

</beans>

JSP视图

创建userList.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>User List</title>

<!-- Bootstrap -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">

</head>
<body>
<div class="container">
<c:if test="${!empty userList}">
<table class="table table-bordered table-striped">
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.name}</td>
<td>${user.age}</td>
</tr>
</c:forEach>
</table>
</c:if>
</div>
</body>
</html>

部署测试

我们通过IDEA的tomcat插件来进行测试

下载Tomcat:tomcat地址在新窗口打开

下载后给tomcat/bin执行文件赋权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pdai@MacBook-Pro pdai % cd apache-tomcat-9.0.62 
pdai@MacBook-Pro apache-tomcat-9.0.62 % cd bin
pdai@MacBook-Pro bin % ls
bootstrap.jar makebase.sh
catalina-tasks.xml setclasspath.bat
catalina.bat setclasspath.sh
catalina.sh shutdown.bat
ciphers.bat shutdown.sh
ciphers.sh startup.bat
commons-daemon-native.tar.gz startup.sh
commons-daemon.jar tomcat-juli.jar
configtest.bat tomcat-native.tar.gz
configtest.sh tool-wrapper.bat
daemon.sh tool-wrapper.sh
digest.bat version.bat
digest.sh version.sh
makebase.bat
pdai@MacBook-Pro bin % chmod 777 *.sh
pdai@MacBook-Pro bin %

配置Run Congfiuration

image

添加Tomcat Server - Local

image

将我们下载的Tomcat和Tomcat Server - Local关联

image

在Deploy中添加我们的项目

image

运行和管理Tomcat Sever(注意context路径)

image

运行后访问我们的web程序页面(注意context路径)

image

参考资料

转自SpringMVC请求流程和案例