Spring MVC初步

前言

MVC模式是一种软件架构模式,他把一个大的软件系统分为三个基本部分:模型(Model),视图(View)和控制器(Controller).这种软件架构模式使得整个系统层次逻辑分明,三个层可以各司其职,如果某一层的需求发生了变化,只需要更改相应层中的代码而不影响到其他层中的代码,有利于开发中的分工.并且在分层后更加有利于工作的分工,后期进行组件的重组时也有很大的优点.Spring MVC就是使用Java技术实现MVC模型后的一个框架.在这里对Spring MVC的学习进行总结

MVC是什么?

如图就是一个MVC的架构

MVC架构分为三层:
1.模型层(Model):在三层架构当中,模型层处于最后一层,他作为程序的主体部分有两个任务,用来表示业务的数据和执行具体业务的逻辑,在具体执行逻辑的时候往往还会通过一个持久层去操作相应的数据库
2.视图层(View):视图层在三层架构中的最上层,他的主要任务是帮助用户实现和程序的交互.视图向用户展示相关数据,并且能够接收数据,他不进行任何实际业务的处理.
3.控制层(Controller):控制层处于三层架构的中间层,他负责接收用户的输入并调用模型和视图去完成用户的需求.一方面,他解释来自视图的输入,将其解释成为系统能够理解的对象,同时他也识别用户动作,并将其解释为对模型特定方法的调用;另一方面,他处理来自于模型的事件和模型逻辑执行的结果,调用适当的视图为用户提供反馈
以上就是三层模型各自的作用
下面在结合上图分析一下如果一个用户进行了一次用户信息查找整个MVC架构的工作流程是怎么样的
假设客户在浏览器端点击了一个查询数据库中人员信息的按钮。
此时,会从浏览器端发送一个http请求,即一个request
① 这个请求会交给转发控制器,转发控制器获取到请求的URL和具体的请求信息后他会进行处理分析,得知这个请求的主要目的后他会去调用专门处理该种请求的具体控制器,例如此时是查询操作他就会去调用查询业务的控制器。
② 查询控制器拿到了具体请求之后他会去模型层调用相应的具体模型。
③ 模型层中的模型就是具体的业务执行代码,他完成主要的逻辑操作,如果不牵扯调用数据库那么在这一层中就可以原路返回执行结果了;如果访问数据库,就需要通过持久层(专门用来访问数据库的操作层)来访问数据库。
④ 从数据库中取出数据之后开始返回,数据先由模型先交给调用该模型层的具体控制器,然后这个控制器将数据在交给转发控制器。
⑤ 此时转发控制器去调用视图层将数据可视化,最终返回一个带有页面的响应给用户
至此一次操作便完成了
注释:
1.转发控制器,业务控制器都属于控制层,转发控制器只能有一个,而控制转发器可以有多个,转发控制器类似于一个调度站,他会给具体的业务控制器分配任务去完成相对应的操作
2.模型层中主要包含了数据信息和具体的业务逻辑实现.数据信息例如JavaBean封装的用户对象,业务逻辑例如具体如何去数据库中查找用户信息
3.持久层:这一层其实已经囊括在了Model层中但他又是一个独立的层次,他的主要任务就是用来访问数据库,例如JDBC就可以作为持久层

Spring MVC

鉴于MVC的通用性以及他的众多优点,Spring框架中便也实现了该种Web构架模型,起名为Spring MVC.但在具体的架构实现过程中,Spring MVC和MVC的形式还有些不同之处,以下开始进入Spring MVC

Spring MVC的架构

Spring MVC架构图

Spring MVC不像标准MVC结构有明确的三层,他使用封装的技术使得模型层不那么直观的体现,但是在控制层上又做了很大的改变

Spring MVC如何工作

如上图,当用户从客户端发送一个请求之后…
①请求最先会交给前端控制器,类似于MVC中的转发控制器,他也是一个核心的调度器.
②此时前端控制器不能够直接去调用具体处理器,而是向处理器映射器发送请求
③处理器映射器收到请求之后会去请求处理器适配器执行处理器
④处理器适配器根据定义规则去让处理器执行
⑤被执行的处理器会返回一个ModelAndView,ModelAndView中分别包含了模型和视图
⑥ModelAndView先返回给处理器适配器,由处理器适配器交还处理器映射器,处理器映射器最终返回到前端控制器
⑦处理器映射器拿到ModelAndView后调用视图解析器
⑧试图解析器会根据逻辑视图名把逻辑视图转换为一个物理视图(jsp..)并返还给前端控制器
⑨前端控制器对物理视图进行渲染并且填充到response域中
⑩前端控制器向用户响应结果(response)
这便是整个Spring MVC的一次工作流程

Spring MVC中每一个关键组件的作用

[前端控制器]:接收客户端的请求URL,请求HandlerMapping,最终接收返回的ModelAndView,再调用视图解析器获得真正的视图View,后对View进行渲染,响应客户端
[处理器映射器]:接收前端处理器的请求,调用处理器适配器,得到处理器适配器返回的ModelAndView,并返回ModelAndView给前端控制器
[处理器适配器]:接收处理器映射器的请求,定义规则去执行处理器,并返回ModelAndView给处理器映射器
[处理器]:按照处理器适配器的规则执行,生成ModelAndView并返回给处理器适配器
[视图解析器]:将逻辑视图转换为物理视图
[视图]:视图就是jsp,php,doc..等

Spring MVC具体使用

Spring MVC有两种使用方式,一种是配置文件配置使用,另一种是使用注解的方式,下面将分别介绍
首先我们的工程要有一个正确的目录结构,并且导入所有依赖的jar包

必须如上图是一个正确的web工程的目录结构,在我的这个结构中handler包中放的是自己实现的处理器,po包中放JavaBean等数据对象
导入所需的jar包

假如我们有如下简单需求:客户端发起请求给服务器,然后在网页上显示一个商品表.下面就用Spring MVC来实现一个这个需求

采用配置的方式来实现Spring MVC

从处理器开始往上逆向配置各个组件

处理器

在Spring MVC中,视图和处理器需要我们自己来实现.处理器的作用就是做具体的业务处理,在本例中我们就是要模拟几个商品,把他们保存在List中,在将list通过ModedAndView带回到前端处理器交给视图解析器将数据保存在视图中最终由响应带回给客户端
具体处理器逻辑工作的实现(继承自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
//自定义处理器
public class ItemsHandler implements Controller {

@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {

List<Items> list = new ArrayList<>();

Items items1 = new Items();
items1.setName("Nike");
items1.setCreatetime(new Date());
items1.setPrice("1200");
items1.setDetail("Nike运动鞋很舒服");

Items items2 = new Items();
items2.setName("LiNing");
items2.setCreatetime(new Date());
items2.setPrice("1000");
items2.setDetail("LiNing运动鞋很舒服");

list.add(items1);
list.add(items2);

ModelAndView modelAndView = new ModelAndView();

//相当于 request.setAttribute("key",value)
modelAndView.addObject("itemslistKey",list);

//设置逻辑视图名
modelAndView.setViewName("/jsp/items.jsp");

return modelAndView;

}
}

写好处理器的具体逻辑之后要通过配置文件(resources下的applicationContext.xml)将处理器注册到spring

1
2
<!--处理器-->
<bean id="itemHandler1" name="/my.action" class="io.github.seevae.handler.ItemsHandler"/>

处理器适配器

处理器适配器会接收处理器映射器的请求并按照一定的规则去调用处理器,处理器适配器是Spring MVC提供给我们的组件不需要自己去实现,只要在appliacationContext.xml进行注册直接使用就好

1
2
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

处理器映射器

前端控制器拿到客户端的请求之后就会去找前端控制器.前端控制器会接收控制器的请求并截取URL,转发给不同处理器,这个组件也不需要我们自己写,只需注册在appliacationContext.xml中

1
2
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

前端控制器

这是整个Spring MVC中的核心,当一个请求发送后他是最先拿到请求的,前端控制器的配置是写在web.xml文件中的,因为当一个web工程开始进行,该文件是最先被服务器读取的

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
<!--配置前端控制器DispatcherServlet
作用: 1.接收所有的请求
2.截取请求的URL
3.转发到相应的业务逻辑控制器(处理器)
-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--默认的文件名称是: servlet-name-servlet.xml springmvc-servlet.xml-->
<param-name>contextConfigLocation</param-name>
<!--下面这句话将其他组件和前端控制器关联起来-->
<param-value>classpath*:applicationContext.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
三种请求方式:
1.*.action: 所有以action结尾的请求都会被发送至Spring的前端控制器DispatcherServlet
2./ : 所有的请求都会被发至spring的前端控制器DispatcherServlet.可以配置成RestFul风格
3./* : 错误的,别出现
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>

至此,Spring MVC的所有组件就都有了,接下来就是运行了

首先开启服务器,进入首页

在首页里模拟了一个用户需求的连接,实际就是我们的测试页面 –>/jsp/ceshi.jsp

点击买商品结账,这个是一个以.action结尾的请求路径,也就是我们自定义处理器的映射路径,进去后就是程序运行的结果

当然,如果直接请求my.action也可以拿到响应,如下

结果也相同

客户端发送一个请求给服务器最终服务器返回响应在程序中到底是怎么运行的呢?
首先在前端控制器中我们配置的是以.action结尾的请求都会交给前端控制器,所以当我们输入/my.action,这个请求就会交给前端控制器,前端控制器去applicationConext.xml中找处理器映射器,处理器映射器又找处理器适配器,处理器适配器又根据我们设置的映射路径找到具体的处理器(至此都是发生在applicationContext.xml中的),处理器执行逻辑,返回ModelAanView给前端控制器,这时前端控制器调用视图解析器,将我们ModelAndView中设置的逻辑视图名中的逻辑视图解析为物理视图并封装在response中响应给客户端
这就是一次请求在程序中的执行过程

适配器到底适配的是什么?

在Spring MVC中只有一个前端控制器,并且只能是这个org.springframework.web.servlet.DispatcherServlet,但处理器,处理器映射器和处理器适配器其实是有两套的,上面的例子中我们使用的是:处理器继承自接口Controller,此时处理器映射器要使用org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,对应的处理器适配器使用org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
但处理器还有一种实现方法,那就是实现HttpRequestHandler接口,实现这个接口并不会返回一个ModelAndView,直接使用请求转发就可以传递响应了
举个栗子,还是上述相同的业务,此时这样实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ItemsHandler2 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Items> list = new ArrayList<>();

Items items1 = new Items();
items1.setName("Nike");
items1.setCreatetime(new Date());
items1.setPrice("1200");
items1.setDetail("Nike运动鞋很舒服");

Items items2 = new Items();
items2.setName("LiNing");
items2.setCreatetime(new Date());
items2.setPrice("1000");
items2.setDetail("LiNing运动鞋很舒服");

list.add(items1);
list.add(items2);

request.setAttribute("itemslistKey",list);
request.getRequestDispatcher("/jsp/items.jsp").forward(request,response);
}
}

对于这种处理器,我们需要使用不同的映射器和适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--处理器-->
<bean id="itemHandler2" class="io.github.seevae.handler.ItemsHandler2"/>

<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/myy.action">itemHandler2</prop>
<prop key="/my.action">itemHandler1</prop>
</props>
</property>
</bean>

要注意对比,两种不同的处理器对应的处理器映射器和处理器适配器都是不同的!

采用注解的方式实现Spring MVC

1.首先写好处理器并加入注解

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
@Controller
public class ItemsHandler3 {

@RequestMapping(value = "/xiaozhang.action")
public ModelAndView getModelAndView(){
List<Items> list = new ArrayList<>();

Items items1 = new Items();
items1.setName("Nike");
items1.setCreatetime(new Date());
items1.setPrice("1200");
items1.setDetail("Nike运动鞋很舒服");

Items items2 = new Items();
items2.setName("LiNing");
items2.setCreatetime(new Date());
items2.setPrice("1000");
items2.setDetail("LiNing运动鞋很舒服");

list.add(items1);
list.add(items2);

ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemslistKey",list);
modelAndView.setViewName("/jsp/items.jsp");
return modelAndView;
}

}

第一个注解: 说明这个类是一个处理器,没有注解的话他就是一个普通的类
第二个注解: 设置处理器的映射路径(最终我们要访问的地址的路径)
如上便配置好了处理器
2.在applicationContext中配置映射器,适配器,只需要一句话

1
<mvc:annotation-driven/>

3.配置组件扫描器,扫描一个包中当前业务需要使用的处理器

1
<context:component-scan base-package="io.github.seevae.handler"/>

仅仅只需上述几步,就代替了配置的方式使用MVC的所有步骤,运行后结果相同

注意路径: 是处理器的映射路径
以上就是Spring MVC初步认识和基本使用