Spring MVC 基础
Spring MVC 基础
仅用作个人学习记录,无逻辑性,仅参考
前置知识
dao(mapper)层:数据访问层
- dao层属于一种比较底层,比较基础的操作,具体到对于某个表的增删改查,也就是说某个DAO一定是和数据库的某一张表一 一对应的,其中封装了增删改查基本操作,建议DAO只做原子操作,增删改查。
- 负责与数据库进行联络的一些任务都封装在此,dao层的设计首先是设计dao层的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可以再模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,dao层的数据源配置,以及有关数据库连接参数都在Spring配置文件中进行配置。
service层:服务层
-
粗略的理解就是对一个或多个DAO进行的再次封装,封装成一个服务,所以这里也就不会是一个原子操作了,需要事物控制。
-
service层主要负责业务模块的应用逻辑应用设计。同样是首先设计接口,再设计其实现类,接着再Spring的配置文件中配置其实现的关联。这样就可以在应用中调用service接口来进行业务处理。
-
service层的业务实,具体要调用已经定义的dao层接口,封装service层业务逻辑有利于通用的业务逻辑的独立性和重复利用性。程序显得非常简洁。
controller层
-
Controler负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。
-
controller层负责具体的业务模块流程的控制,在此层要调用service层的接口来控制业务流程,控制的配置也同样是在Spring的配置文件里进行,针对具体的业务流程,会有不同的控制器。
-
具体的设计过程可以将流程进行抽象归纳,设计出可以重复利用的子单元流程模块。这样不仅使程序结构变得清晰,也大大减少了代码量。
关系
- Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。
Servlet
- Java Servlet 是运行在Web服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
Servlet主要执行以下任务:
- 读取读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
- 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等
- 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
- 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
- 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。
@Bean注解
- Spring的
@Bean
注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理 - @ComponentScan 是 Spring 框架中的一个注解,用于自动扫描并注册带有 @Component、@Service、@Repository 和 @Controller 等注解的类为 Spring Bean。这样可以避免手动在 XML 配置文件中声明 Bean,使配置更加简洁和灵活。
0x01 MVC
- M 是指业务模型(Model):用于封装数据传递的实体类
- V 是指用户界面(View):一般是指前端页面
- C 是控制器(Controller):控制器相当于Servlet的基本功能,处理请求,返回响应
Spring MVC是将三者之间进行解耦,实现职能划分,互不干扰,最后将View和Model进行渲染,得到最终的页面并返回给前端。
0x02 搭建项目
全注解配置形式
使用纯注解开发,可以直接添加一个类,Tomcat会在类路径中查找实现ServletContainerInitializer
接口的类,如果发现就用该类来配置Servlet容器,Spring提供了这个接口的实现类 SpringServletContainerInitializer
,通过@HandlesTypes(WebApplicationInitializer.class)
设置,这个类会反过来查找实现WebApplicationInitializer
的类,并将配置任务交给他们来实现,因此直接实现接口即可:
1 | public class MainInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { |
1 | // WebConfiguration 的实现 |
1 | // Controller |
0x03 Controller控制器
当一个请求经过DispatcherServlet
之后,会先走HandlerMapping
,它会将请求映射为HandlerExecutionChain
,依次经过HandlerInterceptor
,类似于过滤器,在SpringMVC中使用的是拦截器,然后再交给HandlerAdapter
,根据请求的路径选择合适的控制器进行处理,控制器处理完成后,会返回一个ModelAndView
对象,包括数据模型和视图,即页面中的数据和页面本身。
返回ModelAndView
之后,会交给ViewResolver
(视图解析器)进行处理,视图解析器会对整个视图页面进行解析,SpringMVC自带一些视图解析器,也可以使用Thymeleaf作为视图解析器,就可以根据给定的视图名称直接读取HTML编写的页面解析为一个真正的View
解析完成后,需要将页面中的数据全部渲染到View中,最后返回给DispatcherServlet
一个包含所有数据的成形页面,再响应给浏览器,完成整个过程。
配置视图解析器和控制器
首先需要实现最基本的页面解析并返回,第一步就是配置视图解析器(这里使用Thymeleaf
提供视图解析器)
1 | <dependency> |
1 | // 视图解析器配置 |
现在完成了视图解析器的配置,然后创建一个Controller,只需在一个类上添加一个 @Controller
注解即可,它会被Spring扫描并自动注册为Controller类型的Bean,只需在类中编写方法用于处理对应地址的请求即可
1 |
|
1 | <!--对应HTML--> |
此外,页面中可能还会包含一些静态资源,比如js,css。为了让静态资源通过Tomcat提供的默认Servlet进行解析,需要让配置类实现WebMvcConfigurer
接口。
1 | public class WebConfiguration implements WebMvcConfigurer { |
以上代码的项目结构
0x04 注解
4.1 请求映射
@RequestMapping
是将请求和处理请求的方法建立一个映射关系,当收到请求时就可以根据映射关系调用对应的请求处理方法,注解定义如下:
1 |
|
其中最关键的是path
属性(等价于value
),它决定了当前方法处理的请求路径(路径必须全局唯一),任何路径只能有一个方法进行处理,它是一个数组,也即此方法不仅仅可以用于处理某一哦请求路径,可以使用此方法处理多个请求路径。
此外,还可以直接将@RequestMapping
添加到类名上,表示为此类中所有请求添加一个路径前缀,例如:
1 |
|
路径还支持使用通配符进行匹配:
?
:表示任意一个字符,比如@RequestMapping("/index/?")
可以匹配 /index/a 等*
:表示任意0-n个字符,比如@RequestMapping("/index/*")
可以匹配 /index/demo 等**
:表示当前目录或基于当前目录的多级目录,比如@RequestMapping("/index/**")
可以匹配 /index/demo/a 等
设置请求方法:
@RequestMapping(value="/index", method=RequestMethod.POST)
@PostMapping
或@GetMapping
可以使用 params
属性来指定请求必须携带哪些参数
1 |
|
-
可以在参数之前添加
!
表示请求不允许添加此参数1
2
3
4
5
public String index() {
return "index";
}
// 请求参数不能包含 userid -
也可以直接设定不允许一个固定值
1
2
3
4
5
public String index() {
return "index";
}
// 表示请求参数 id 不允许为 0 , 并且 token 必须为 1
header
属性用法与 params
一致,它要求请求头中必须携带什么内容,比如:
1 |
|
consumes
:指定处理请求的提交内容类型(Content-Type
),例如application/json
produces
:指定返回的内容类型,仅当 request 请求头中的(Accept)类型中包含该指定类型才返回
4.2请求参数获取
@RequestParam
和 @RequestHeader
用法基本一致 ,仅演示前者
获取到请求中的参数,只需为方法添加一个形式参数,并在形式参数前面添加@RequestParam
注解即可:
1 |
|
@CookieValue
和 @SessionValue
1 |
|
4.3重定向和请求转发
1 | // 重定向 |
1 | // 请求转发 |
区别:
- 重定向:302跳转到对应的映射
- 请求转发:内部转发请求,交给其他映射处理,浏览器地址不变
4.4 Bean的web作用域
Spring MVC中,Bean的作用域被分为:
- request:对于每次HTTP请求,使用request作用域定义的Bean都将产生一个新实例,请求结束后Bean也消失
- session:对于每一个会话,使用session作用域定义的Bean都将产生一个新实例,会话过期后Bean消失
- global session:。。。
1 |
|
1 |
|
@Data
是 Lombok 库提供的一个非常有用的注解,它可以大大减少样板代码的编写。@Data 注解会自动生成以下内容:
- Getter 和 Setter 方法:为类中的每个字段生成 getter 和 setter 方法。
- toString 方法:生成一个 toString 方法,包含类的所有字段。
- equals 和 hashCode 方法:生成 equals 和 hashCode 方法,基于类的所有字段。
- requiredArgsConstructor:生成一个包含所有 final 字段和 @NonNull 字段的构造函数。
@Autowired
用于自动装配依赖。它可以在字段、构造函数、setter方法或者其他方法上使用,Spring容器会自动将匹配的 Bean 注入到标注了 @Autowired
的地方
1 | // 有一个 UserService 和一个 UserController,UserController 需要使用 UserService: |
- Spring 容器初始化:Spring 容器启动时,会扫描带有
@Component
,@Service
,@Controller
等注解的类,并创建相应的 Bean - 创建 UserService 实例:Spring 容器根据 @Service 注解创建 UserService 实例
- 创建 UserController 实例:Spring 容器根据
@Controller
注解创建 UserController 实例 - 自动装配 UserService 到 UserController:Spring 容器通过
@Autowired
注解将 UserService 实例注入到 UserController 中 - 结束:完成所有 Bean 的创建和依赖注入,Spring 容器准备就绪,可以处理请求
4.5 RestFul风格
一种设计风格,主要作用时充分并正确利用HTTP协议的特定,规范资源获取的URI路径。RESTful风格的设计允许将参数通过URL拼接传到服务端,目的是让URL看起来更简洁实用,并且让我们充分实用多种HTTP请求方式,来执行相同请求地址的不同操作类型
这种风格的链接,可以直接从请求路径中读取参数:
1 | http://localhost:8080/mvc/index/123 |
可以直接将 index 的下一级路径作为请求参数进行处理,即现在的请求参数包含在了请求路径中:
1 |
|
0x05 Interceptor拦截器
拦截器在Servlet与RequestMapping之间,相当于DispatcherServlet在将请求交给对应Controller中的方法之前进行拦截处理,它只会拦截所有Controller中定义的请求映射对应的请求(不会拦截静态资源)
1 | public class MainInterceptor implements HandlerInterceptor { |
1 | // 注册拦截器 |
拦截器处理前和处理后,包含了真正的请求映射的处理,在整个流程结束后还执行了一次afterCompletion
方法。
多级拦截器和 类 的处理方式类似,也可用 .order(Int)
来控制拦截器 优先级。
0x06 自定义异常处理
当请求映射方法中出现异常时,会直接展示在前端页面,这是因为Spring MVC提供了默认的异常处理页面,当出现异常时,请求会被直接转交给专门用于异常处理的控制器进行处理。
可以自定义异常处理器,一旦出现指定异常,就会直接转接到此控制器执行。
1 | public class ErrorController { |
0x07 Axios请求
前端异步请求,因为网页是动态的,点击按钮、跳转新的页面、更新页面数据都是通过JS完成异步请求实现。
前端异步请求是指在前端中发送请求至服务器或其他资源,并不阻塞用户界面或其他操作。在传统的同步请求中,当发送请求时,浏览器会等待服务器响应,期间用户无法进行其他操作。异步请求通过将请求发送到后台,等待响应时,允许用户进行其他操作。这种机制能够提升用户体验,并且允许页面进行实时更新。
常见的前端异步请求方式包括实用HMLHttpRequest对象,Fetch API以及实用jQuery中的AJAX方法以及目前最常用的Axios框架