文章目录
- [1. SpringMVC简介](#1. SpringMVC简介)
- [2. SpringMVC入门案例](#2. SpringMVC入门案例)
- [3. 入门案例工作流程分析](#3. 入门案例工作流程分析)
- [4. bean的加载与控制](#4. bean的加载与控制)
1. SpringMVC简介
数据层框架: MyBatis
表现层框架: Servlet->SpringMVC (即SpringMVC属于一种表现层框架)
简介: SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
优点:
- 使用简单,开发便捷(相比于Servlet)
- 灵活性强
2. SpringMVC入门案例
文件结构
第一步:坐标导入
pom.xml文件中添加一些依赖,这些依赖版本之间是相互联系的,如果配错或配太低都不行
xml
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springmvc_01_test</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<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>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
<version>10.1.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
第二步:创建SpringMVC容器的控制器类
控制器类来指定对应的访问网址什么的,@Controller
标明这是一个bean,@RequestMapping
指定访问路径,@ResponseBody
指定返回不做任何解析和处理
java
package com.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("User save...");
return "{'module': 'springmvc'}";
}
}
第三步:初始化SpringMVC环境,设定Spring加载对应的bean
类似于Spring的配置,通过@Configuration
指定为配置类,通过@ComponentScan
来指定扫描的控制器范围
java
package com.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.demo.controller")
public class SpringMvcConfig {
}
第四步:初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术请求的处理
这里相当于是一些固定的写法
java
package com.demo.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
// 加载SpringMVC容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
// 设置哪些请求归属SpringMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
// 加载Spring配置
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
测试
配置Run Configurations
然后启动,在浏览器里输入http://localhost/save
可看到结果:
总结:使用到的一些注解及入门程序开发总结
@Controller
:类注解,放在SpringMVC控制器上方,作用是设定SpringMVC的核心控制器bean
@RequestMapping
:方法注解,放在SpringMVC控制器方法定义上方,作用是设置当前控制器方法的请求路径
@ResponseBody
:方法注解, 放在SpringMVC控制器方法定义上方,作用是设置当前控制器方法相应内容为当前返回值,无需解析
3. 入门案例工作流程分析
启动服务器初始化过程
- 服务器启动,执行
ServletContainerInitConfig
类,初始化Web容器 - 执行
createServletApplicationContext
方法,创建了WebApplicationContext
对象 - 加载
SpringMVCConfig
- 执行
@ComponentScan
对应的bean - 加载
UserController
(也就是加载扫描包下注释了@Controller
的那些类),每个@RequestMapping
的名称都对应一个具体的方法(注意:如图中/save->save()
的映射实际上并不是放在每一个bean中管理的,而是由SpringMVC放在统一的地方进行管理的) - 执行
getServletMappings
方法,定义所有的请求都通过SpringMVC
单次请求过程
- 发送请求
localhost/save
- web容器发现所有的请求都经过SpringMVC(上面的6,定义了所有的请求都经过SpringMVC),将请求交给SpringMVC处理
- 解析请求路径
/save
- 由
/save
匹配执行对应的方法save()
- 执行
save()
- 检测到有
@ResponseBody
,直接将save()
方法的返回值作为响应请求体返回给请求方
4. bean的加载与控制
SpringMVC相关的bean是表现层的bean:
- SpringMVC加载的bean对应的包均在
com.xx.controller
包内
Spring控制的bean:
- 业务bean(Service)
- 功能bean(DataSource等)
- 方式一:Spring加载的bean设定扫描范围为
com.xx
,排除掉controller
包内的bean - 方式二:Spring加载的bean设定扫描范围为精准范围,例如
service, dao
包等 - 方式三:不区分Spring和SpringMVC的环境,加载到同一个环境中
方式一:
指定大的扫描类型,在其中通过excludeFilters
排除掉一些东西,具体写法如下,我们需要再excludeFilters
里边指定清楚过滤的规则
java
package com.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
@ComponentScan(value = "com.demo",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
执行一下测试,看能否再拿到注释了@Controller
的UserController
类(注意,在测试之前要注释掉SpringMvcConfig上的@Configuration
):
java
package com.demo;
import com.demo.config.SpringConfig;
import com.demo.controller.UserController;
import com.demo.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
UserController userController = ctx.getBean(UserController.class);
System.out.println(userController);
}
}
执行测试代码会报错:
如果取消掉这个过滤规则,再执行测试代码会发现不会报错,而是会打印拿到的实例信息。通过测试说明使用excludeFilters
这种方法是可以过滤包的
解释一下为什么要注释掉SpringMvcConfig上的@Configuration
:因为我们在SpringConfig
中扫描了com.demo
下的所有包 ,在SpringMvcConfig
上我们使用@Configuration
注解了它是一个配置类,那么这个配置就会被扫描,它所包括的所有bean也会被加载进来,如果将SpringMvcConfig
放到com.demo
下而不注释也可以解决这个问题(老师在视频里是这么讲的,但是我自己试了一下好像把SpringMvcConfig
放到com.demo
下,不注释也会被加载进来,不知道是不是我的问题)
方式二:
我们使用mybatis
技术来进行开发,这里的com.demo.dao
是可以不写的,因为mybatis
通过自动代理的技术可以扫到com.demo.dao
下的bean(在Mybatis的MapperScannerConfigurer
中有设置msc.setPackage("...")
)
但是假如我们使用JDBC的技术来进行开发,我们就必须扫描com.demo.dao
下的包,否则我们就没有数据层的bean,Spring下JDBC的开发可以看一下这篇文章:Spring jdbc数据库管理,所以对于com.demo.dao
的扫描还是建议写,这样通用性比较好,如果不写的话通用性就会比较差
java
package com.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({"com.demo.service", "com.demo.dao"})
public class SpringConfig {
}
将Spring下的bean也加载到Servlet容器中
修改ServletContainersInitConfig
类中的内容,加上加载Spring配置的内容:
java
package com.demo.config;
import com.demo.controller.SpringConfig;
import com.demo.controller.SpringMvcConfig;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
// 加载SpringMVC容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
// 设置哪些请求归属SpringMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
// 加载Spring配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}
在Servlet容器中加载SpringMVC和Spring配置还有一个简化的类及写法,以下是以上的简化开发:
java
package com.demo.config;
import com.demo.controller.SpringConfig;
import com.demo.controller.SpringMvcConfig;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContainerInitConfig 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[]{"/"};
}
}