目录

SpringMVC 概述

# SpringMVC 概述

![[Pasted image 20220614164333.png]]

先前学习的MyBatis取代了原有的原生数据层,如今学习的SpringMVC取代了Servlet称为新的表示层

# Servlet和SpringMVC对比

![[Pasted image 20220614164632.png]] ![[Pasted image 20220614164648.png]] 同一种功能,很明显SpringMVC的代码量更加少,这点能加快程序员开发进度

# 安装

# 依赖安装
<dependency>  
  <groupId>javax.servlet</groupId>  
  <artifactId>javax.servlet-api</artifactId>  
  <version>4.0.1</version>
  <scope>provided</scope>  
</dependency>  
<dependency>  
  <groupId>org.springframework</groupId>  
  <artifactId>spring-webmvc</artifactId>  
  <version>5.3.20</version>  
</dependency>
1
2
3
4
5
6
7
8
9
10
11

切记千万不要使用tomcat10,由于更新导致包名变更,因此目前仍未适配到。

# 主类配置

在Spring章节中,当我们打算获取bean时,我们往往需要先获得AnnotationConfigApplicationContext的实例对象,然后才能通过getBean()获取。 在实现该对象时,其实还有个与他类似的同胞类,就是专门用于web的AnnotationConfigWebApplicationContext,而我们SpringMVC就是要实例化这个类~

//config->SContainersInitConfig.java
public class SContainersInitConfig extends AbstractDispatcherServletInitializer {  
    @Override  
    protected WebApplicationContext createServletApplicationContext() {  
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();  
        ctx.register(SpringConfig.class);  
        return ctx;  
    }  
  
    @Override  
    protected String[] getServletMappings() {  
        return new String[]{"/"};  
    }  
  
    @Override  
    protected WebApplicationContext createRootApplicationContext() {  
        return null;  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

从上面代码可知,我们需要让主类配置继承自AbstractDispatcherServletInitializer,该类有三个方法需要实现。

  1. createServletApplicationContext 该方法用于创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围 ![[Pasted image 20220615020916.png]]

  2. getServletMappings 该方法用于设定SpringMVC对应的请求映射路径,设置为/标识拦截所有请求,人已请求都将转交给SpringMVC处理 ![[Pasted image 20220615021016.png]]

  3. createRootApplicationContext 如果创建Servlet容器时需要加载非SpringMVC的bean,则使用当前方法执行,使用方式同createServletApplicationContext

# 表示层逻辑
//controller->UserController.java
@Controller  
public class UserController {  
  
    @RequestMapping("/save")  
    @ResponseBody  
    public String save(){  
        System.out.println("Loading save()...");  
        return "{'module':'springmvc'}";  
    }  
}
1
2
3
4
5
6
7
8
9
10
11

首先,class上面添加了一个新的注释@Controller,该注释用于说明此类是表示层的控制器,这样做方便SpringMVC扫描,下面的save函数上有两注释

  1. @RequestMapping("/save") - 用于匹配用户请求路径
  2. @ResponseBody - 将返回值作为响应体返回
# SpringMVCConfig
//config->SpringMVCConfig.java
@Configuration  
@ComponentScan("com.project.controller")  
public class SpringMVCConfig {  
}
1
2
3
4
5

# 启动流程

![[Pasted image 20220615021553.png]]

# Bean加载

假设我们项目的目录如下 ![[Pasted image 20220615021821.png]]

  • SpringMVC仅加载controller包下的bean
  • Spring需要加载除了controller包以外的bean
# 思想一

手动一个个导入

# 思想二

排除法导入

@Configuration  
@ComponentScan(value = "com.project",  
        excludeFilters = @ComponentScan.Filter(  
                type = FilterType.ANNOTATION,  
                classes = Controller.class  
        ))  
@Import({SpringMVCConfig.class})  
public class SpringConfig {  
}
1
2
3
4
5
6
7
8
9

笔者心态:除非几百个,否则我还是选择思想一吧

如你所见,很麻烦。。。

  • excludeFilters : 排除规则
  • type : 排除的类型
  • classes : 排除的类

上面的例子意思是按照注解类型排除掉注解为Controller的类。

注意:导入的包是org.springframework.stereotype.Controller;

# 小问题

这是当前目录结构: ![[Pasted image 20220615024710.png]]

这是SpringConfig配置:

@Configuration  
@ComponentScan(value = "com.project",  
        excludeFilters = @ComponentScan.Filter(  
                type = FilterType.ANNOTATION,  
                classes = Controller.class  
        ))  
@Import({SpringMVCConfig.class})  
public class SpringConfig {  
}
1
2
3
4
5
6
7
8
9

这是SpringMVCConfig配置:

@Configuration  
@ComponentScan("com.project.controller")  
public class SpringMVCConfig {  
}
1
2
3
4

那么问题来了,SpringConfig把Controller去掉了,但SpringMVCController又把它加上了,忙了一大轮岂不等于没写吗???

你只需要将这两个类移到com.project外即可,这样彼此就不会互相加载了。

# 加载非SpringMVC的bean

上一段我们配置完了传统的Spring配置了,那么现在就能在主类配置中进行设置。 主类设置中还有一个没有使用到的方法createRootApplicationContext就是用来做这件事的。

@Override  
protected WebApplicationContext createRootApplicationContext() {  
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();  
    ctx.register(SpringConfig.class);  
    return ctx;  
}
1
2
3
4
5
6

可以看到,配置和createServletApplicationContext完全一样。

现在类的实现就是这样了: ![[Pasted image 20220615025628.png]]

你能注意到一个严重的问题createServletApplicationContextcreateRootApplicationContext的区别仅在于配置类的类名而已,其余完全一致,那么我们能不能省略到只填写类名呢??

事实上,我们主类配置继承的AbstractDispatcherServletInitializer是继承自AbstractAnnotationConfigDispatcherServletInitializer类,该类可用于更便捷地初始化。现在代码可以简化如下:

public class SContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {  
    @Override  
    protected Class<?>[] getRootConfigClasses() {  
        return new Class[]{SpringConfig.class};  
    }  
  
    @Override  
    protected Class<?>[] getServletConfigClasses() {  
        return new Class[]{SpringMVCConfig.class};  
    }  
  
    @Override  
    protected String[] getServletMappings() {  
        return new String[]{"/"};  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
最近更新
01
基本知识
07-18
02
卷积神经网络识别图像
07-18
03
损失函数
07-18
更多文章>