SpringMVC框架

接受请求的框架

SpringMVC概述

什么是SpringMVC

SpringMVC就是一个Spring内置的MVC框架。

MVC框架,它解决WEB开发中常见的问题(参数接收、文件上传、表单验证、国际化等等),而且使用简单,与Spring无缝集成。支持 RESTful风格的URL请求。

采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。

pringMVC的作用

MVC模式(Model-View-Controller):解决页面代码和后台代码的分离。

SpringMVC原理

在没有使用SpringMVC之前我们都是使用Servlet在做Web开发。但是使用Servlet开发在接收请求参数,数据共享,页面跳转等操作相对比较复杂。servlet是java进行web开发的标准,既然springMVC是对servlet的封装,那么很显然SpringMVC底层就是Servlet,SpringMVC就是对Servlet进行深层次的封装。

image-20240312112742805

处理controller,然后将json数据传给前端。

黑马SpringMVC教程全套视频教程,6小时精通spring mvc框架_哔哩哔哩_bilibili

Spring MVC 教程 - spring 中文网 (springdoc.cn)

入门案例

使用Servlet技术开发web程序流程

  1. 创建web工程(Maven结构)
  2. 设置tomcat服务器,加载web工程(tomcat插件)
  3. 导入坐标(Servlet)
  4. 定义处理请求的功能类(UserServlet)
  5. 设置请求映射(配置映射关系)

使用SpringMVC技术开发web程序流程

  1. 创建web工程(Maven结构)
  2. 设置tomcat服务器,加载web工程(tomcat插件)
  3. 导入坐标(SpringMVC+Servlet)
  4. 定义处理请求的功能类(UserController)
  5. 设置请求映射(配置映射关系)
  6. 将SpringMVC设定加载到Tomcat容器中

@Controller

名称 @Controller
类型 类注解
位置 SpringMVC控制器类定义上方
作用 设定SpringMVC的核心控制器bean

@RequestMapping

名称 @RequestMapping
类型 类注解或方法注解
位置 SpringMVC控制器类或方法定义上方
作用 设置当前控制器方法请求访问路径
相关属性 value(默认),请求访问路径

@ResponseBody

名称 @ResponseBody
类型 类注解或方法注解
位置 SpringMVC控制器类或方法定义上方
作用 设置当前控制器方法响应内容为当前返回值,无需解析

启动服务器初始化过程

  1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器

  2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象

    • 该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器

加载SpringMvcConfig配置类

  1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器

  2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象

    • 该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器
  3. 加载SpringMvcConfig配置类

  4. 执行@ComponentScan加载对应的bean扫描指定包下所有类上的注解,如Controller类上的@Controller注解

  5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法

    此时就建立了 /save 和 save方法的对应关系

  6. 执行getServletMappings方法,定义所有的请求都通过SpringMVC。/代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求

单次请求过程

  1. 发送请求localhost/save
  2. web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
    • 因为符合上面第六步设置的请求路径,所以该请求会交给SpringMVC来处理
  3. 解析请求路径/save
  4. 由/save匹配执行对应的方法save()
    • 上面的第五步已经将请求路径和方法建立了对应关系,通过/save就能找到对应的save方法
  5. 执行save()
  6. 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方

bean加载控制

为了防止spring加载到controller里面的bean可以通过加载Spring控制的bean的时候排除掉SpringMVC控制的备案

具体该如何排除,有两种方式来解决:

  • 方式一:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean
  • 方式二:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.itheima.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({"com.itheima.service","com.itheima.dao"})
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value="com.itheima",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}

bean的加载格式

分别加载spring和springMVC框架,指定配置文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}

Spring还提供了一种更简单的配置方式,可以不用再去创建AnnotationConfigWebApplicationContext对象,不用手动register对应的配置类,如何实现?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}

protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}

protected String[] getServletMappings() {
return new String[]{"/"};
}
}

请求与响应

解决冲突

团队多人开发,每人设置不同的请求路径,冲突问题该如何解决?

解决思路:为不同模块设置模块名作为请求路径前置

对于Book模块的save,将其访问路径设置http://localhost/book/save

对于User模块的save,将其访问路径设置http://localhost/user/save

这样在同一个模块中出现命名冲突的情况就比较少了。

优化路径配置

优化方案:

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
@Controller
@RequestMapping("/user")
public class UserController {

@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}

@RequestMapping("/delete")
@ResponseBody
public String save(){
System.out.println("user delete ...");
return "{'module':'user delete'}";
}
}

@Controller
@RequestMapping("/book")
public class BookController {

@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("book save ...");
return "{'module':'book save'}";
}
}

注意:

  • 当类上和方法上都添加了@RequestMapping注解,前端发送请求的时候,要和两个注解的value值相加匹配才能访问到。
  • @RequestMapping注解value属性前面加不加/都可以

请求参数

请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数?

关于请求参数的传递与接收是和请求方式有关系的,目前比较常见的两种请求方式为:

  • GET
  • POST
1
2
3
4
5
6
7
8
9
10
11
@Controller
public class UserController {

@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name,int age){
System.out.println("普通参数传递 name ==> "+name);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'commonParam'}";
}
}

get和post请求不用修改。

REST风格

  • REST(Representational State Transfer),表现形式状态转换,它是一种软件架构==风格==

    当我们想表示一个网络资源的时候,可以使用两种方式:

    • 传统风格资源描述形式
      • http://localhost/user/getById?id=1 查询id为1的用户信息
      • http://localhost/user/saveUser 保存用户信息
    • REST风格描述形式
      • http://localhost/user/1
      • http://localhost/user

传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作。

查看REST风格的描述,你会发现请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的具体功能

所以REST的优点有:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

但是我们的问题也随之而来了,一个相同的url地址即可以是新增也可以是修改或者查询,那么到底我们该如何区分该请求到底是什么操作呢?

  • 按照REST风格访问资源时使用==行为动作==区分对资源进行了何种操作
    • http://localhost/users 查询全部用户信息 GET(查询)
    • http://localhost/users/1 查询指定用户信息 GET(查询)
    • http://localhost/users 添加用户信息 POST(新增/保存)
    • http://localhost/users 修改用户信息 PUT(修改/更新)
    • http://localhost/users/1 删除用户信息 DELETE(删除)

请求的方式比较多,但是比较常用的就4种,分别是GET,POST,PUT,DELETE

按照不同的请求方式代表不同的操作类型。

  • 发送GET请求是用来做查询
  • 发送POST请求是用来做新增
  • 发送PUT请求是用来做修改
  • 发送DELETE请求是用来做删除

但是==注意==:

  • 上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范
    • REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性
    • REST中规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除,但是我们如果非要用GET请求做删除,这点在程序上运行是可以实现的
    • 但是如果绝大多数人都遵循这种风格,你写的代码让别人读起来就有点莫名其妙了。
  • 描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts……

清楚了什么是REST风格后,我们后期会经常提到一个概念叫RESTful,那什么又是RESTful呢?

  • 根据REST风格对资源进行访问称为RESTful

注解

@RestController

名称 @RestController
类型 ==类注解==
位置 基于SpringMVC的RESTful开发控制器类定义上方
作用 设置当前控制器类为RESTful风格,
等同于@Controller与@ResponseBody两个注解组合功能

@GetMapping @PostMapping @PutMapping @DeleteMapping

名称 @GetMapping @PostMapping @PutMapping @DeleteMapping
类型 ==方法注解==
位置 基于SpringMVC的RESTful开发控制器方法定义上方
作用 设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,
例如@GetMapping对应GET请求
相关属性 value(默认):请求访问路径
  • SpringMVC需要将静态资源进行放行。
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//当访问/pages/????时候,从/pages目录下查找内容
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}

  • 该配置类是在config目录下,SpringMVC扫描的是controller包,所以该配置类还未生效,要想生效需要将SpringMvcConfig配置类进行修改
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}

或者

@Configuration
@ComponentScan("com.itheima")
@EnableWebMvc
public class SpringMvcConfig {
}

SSM整合

SSM整合流程

1.创建工程

2.SSM整合
spring

  • SpringConfig

MyBatis

  • MybatisConfig
  • JdbcConfig
  • jdbc.properties

SpringMVC

  • ServletConfig
  • springMvcConfig

3.功能模块

  • 表与实体类

  • dao(接口+自动代理)

  • service(接口+实现类)

    业务层接口测试(整合JUnit )

  • controller

    表现层接口测试( PostMan )

表现层数据封装

封装数据

封装操作结果到code属性中

封装一条特殊消息到message(msg)