目录
- MVC模式
-
- 视图(View)
- 控制器(Controller)
- 模型(Model)
- [JSP Model1](#JSP Model1)
- [JSP Model2](#JSP Model2)
- MVC的优点
- MVC的缺点
- [Spring MVC架构](#Spring MVC架构)
- SpringMVC环境搭建(在前面Spring整合Mybatis的基础上)
-
- 1.创建控制器Controller
- 2.创建springmvc配置文件,并添加Controller的Bean
- 3.web.xml中配置springmvc.xml的加载(配置前端控制器)
- 4.webapp下创建index.jsp
- 5.配置Tomcat并启动,然后访问接口
- 6.配置视图解析器
- 7.优化Controller:注解驱动控制器
-
- [<context:component-scan />](#<context:component-scan />)
- [<mvc:annotation-driven />](#<mvc:annotation-driven />)
- 代码示例
- 思考:如果另外一个IndexController中也有一个hello接口,会怎样
- 总结:SpringMVC的工作流程
-
- [Spring MVC体系结构](#Spring MVC体系结构)
- 面试题:简述SpringMVC工作流程?
MVC模式
- MVC模式是指Model-View-Controller(模型-视图-控制器)模式,是开发Web应用程序时常用的一种代码分层模式。
- MVC模式是软件工程中的一种架构模式,会强制性地把系统的输入、处理和输出分开,使系统从功能上形成Model-View-Controller三个基本部分。
视图(View)
对应组件:JSP或者HTML文件:负责格式化数据并把它们呈现给用户,包括数据展示、数据验证、界面设计等。
控制器(Controller)
对应组件:Servlet:负责接收并转发请求,对请求进行处理后指派视图并将响应结果发送给客户端。
模型(Model)
对应组件:JavaBean:模型对象拥有最多的处理任务,是应用程序的主体部分,它负责业务逻辑的处理和实现对数据的操作。
JSP Model1
JSP Model2
- Servlet:接受前端请求并调用JavaBean
- JavaBean:处理业务并操作数据库
- JSP:将处理结果响应到浏览器呈现给用户
MVC的优点
- MVC三个模块相互独立,松耦合架构
- 多视图共享一个模型,大大提高代码的可重用性
- 控制器提高了应用程序的灵活性和可配置性
- 有利于软件工程化管理
MVC的缺点
- 增加了系统结构和实现的复杂性,不适合小型规模的项目
- 视图层与模型之间需要控制器做中间的连接控制,所以效率较低
Spring MVC架构
介绍
- Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。
- Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts 2(一般老项目使用)等等。
特点
- 用Controller替换JSP Model2模型中的Servlet
- Controller收到请求后,完成业务处理并用Model模型对象存储处理结果
- Controller调用相应的视图解析器View对处理结果进行视图渲染,最终客户端得到响应信息
SpringMVC环境搭建(在前面Spring整合Mybatis的基础上)
1.创建控制器Controller
java
public class HelloController extends AbstractController {
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("HelloSpringMVC...");
ModelAndView m = new ModelAndView("index.jsp");
return m;
}
}
2.创建springmvc配置文件,并添加Controller的Bean
springmvc-servlet.xml
xml
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean name="/hello" class="cn.smbms.controller.HelloController"/>
</beans>
3.web.xml中配置springmvc.xml的加载(配置前端控制器)
xml
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
4.webapp下创建index.jsp
因为HelloController中的ModelAndView中返回的视图是index.jsp
html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h1>HelloSpringMVC!!!</h1>
<h1>你好,SpringMVC</h1>
</body>
</html>
5.配置Tomcat并启动,然后访问接口
localhost:8080/smbms/hello
6.配置视图解析器
通常情况下,jsp会放在/WEB-INF/下,因此可以配置一个固定的前缀和后缀,这样Controller返回页面时,只需要return逻辑视图名即可
java
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("HelloSpringMVC...");
//ModelAndView m = new ModelAndView("index.jsp");
ModelAndView m = new ModelAndView("index");
return m;
}
xml
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
7.优化Controller:注解驱动控制器
使用继承AbstractController 时,一个类只能表示一个接口,不便于开发,使用注解驱动控制器,可以对每个方法设置接口,提高开发效率,节省编码
<context:component-scan />
- @Controller:标注一个普通的JavaBean成为可以处理请求的控制器
- @RequestMapping:通过请求URL进行映射
<mvc:annotation-driven />
一键式配置,通过注解的方式进行Spring MVC开发
- RequestMappingHandlerMapping
- RequestMappingHandlerAdapter
代码示例
xml
<context:component-scan base-package="cn.smbms.controller"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
java
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "index";
}
@RequestMapping("/welcome")
public String welcome(){
return "welcome";
}
...
}
思考:如果另外一个IndexController中也有一个hello接口,会怎样
java
@Controller
public class IndexController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
-
会报错,因此在一个系统中,不能有两个完全重名的接口
java[ERROR] 2024-04-19 11:04:31,774 org.springframework.web.servlet.DispatcherServlet - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'indexController' method public java.lang.String cn.smbms.controller.IndexController.hello() to { /hello}: There is already 'helloController' bean method
-
开发过程中,不能避免的一个Controller中的接口名与其他各个Controller中的接口名重复
-
因此可以在各自的Controller的类名上加上一个各自的统一前缀
-
如下示例,此时访问IndexController中的hello接口时,访问路径就应该是
/index/hello
了
java
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
总结:SpringMVC的工作流程
Spring MVC体系结构
DispatcherServlet(前端控制器)
- Spring MVC最核心的类
- web.xml中配置
Handler(处理器):对应MVC中C(Controller层)
- 类型:Object
- 作用:实际处理请求
- 标注了@RequestMapping的所有方法都可以看作是一个Handler
ModelAndView
- 逻辑视图名
- 模型对象
核心组件
核心组件
HandlerMapping(处理器映射)
- BeanNameUrlHandlerMapping(默认)
- 将请求URL映射到同名的控制器Bean上
- DefaultAnnotationHandlerMapping
- 将请求映射到标注@RequestMapping注解的控制器和处理方法上
- RequestMappingHandlerMapping
HandlerAdapter(适配器)
- AnnotationMethodHandlerAdapter
- RequestMappingHandlerAdapter
ViewResolver(视图解析器)
- InternalResourceView
面试题:简述SpringMVC工作流程?
- 浏览器发送请求送至前端控制器DispatcherServlet。
- DispatcherServlet收到请求后调用HandlerMapping处理器映射器。
- 处理器映射器找到具体的Handler处理器返回给DispatcherServlet。
- DispatcherServlet调用HandlerAdaptor处理器适配器。
- HandlerAdaptor去调用具体的处理器(Controller)。
- Controller返回一个ModelAndView对象给HandlerAdaptor。
- HandlerAdaptor将接收到的ModelAndView对象返回给DispatcherServlet。
- DispatcherServlet将ModelAndView对象传给ViewResolver视图解析器进行解析。
- ViewResolver视图解析器将解析的结果View返回给DispatcherServlet。
- DispatcherServlet根据View进行渲染视图。
- DispatcherServlet响应浏览器的请求。
组件说明
- DispatcherServlet:前端控制器(由框架提供),作为流程控制的中心,控制其他组件执行,统一调度,能够接受请求、响应结果。
- HandlerMapping:处理器映射器(由框架提供),根据用户请求的url路径找到负责处理的Handler处理器。
- HandlerAdaptor:处理器适配器(由框架提供),根据特定规则去执行Handler。
- Handler:处理器(需要自己开发),作为后端控制器,对具体用户的业务请求进行请求,并将处理的结果封装在ModelAndView对象中,并返回给调用者。
- ViewResolver:视图解析器(由框架提供),主要进行视图解析,根据逻辑视图名解析出真正的视图。