第3章-第6节
一、知识点
理解MVC三层模型、理解什么是SpringMVC、理解SpringMVC的工作流程、了解springMVC和Struts2的区别、学会使用SpringMVC封装不同请求、接收参数
二、目标
-
理解MVC三层模型
-
理解什么是SpringMVC
-
理解SpringMVC的工作流程
-
学会使用SpringMVC封装请求
三、内容分析
-
重点
-
理解MVC三层模型
-
理解什么是SpringMVC
-
理解SpringMVC的工作流程
-
学会使用SpringMVC封装请求
-
-
难点
-
理解SpringMVC的工作流程
-
学会使用SpringMVC封装请求
-
四、内容
1、MVC模型
1.1 MVC的概念
MVC全名Model View Controller,模型视图控制器的缩写。是一种用于设计创建Web应用程序表现层的模式。
mvc是一种架构模型,本身并没有新功能,只是对项目的一种规范,方便后期进行维护;mvc架构将模型(M),视图(V)和控制(C)割离开,这么做可以提高代码书写的效率和后期维护;
1.2 MVC详解
-
M:即model(模型)是指模型表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。通常指数据模型,作用一般情况下用于封装数据。
-
V:即View(视图)是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。MVC的好处之一在于它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操作的方式。通常指jsp或者html,用来展示数据的。视图依据模型创建。
-
C:即controller(控制器)是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。处理用户交互部分,用来处理程序逻辑
1.3 MVC的框架(了解即可)
-
struts2
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。
-
SpringMVC
Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet。
一个好的框架要减轻开发者处理复杂问题的负担,内部有良好的扩展,并且有一个支持它的强大用户群体,恰恰 Spring MVC 都做到了。
Spring MVC 角色划分清晰,分工明细。由于 Spring MVC 本身就是 Spring 框架的一部分,可以说和 Spring 框架是无缝集成。性能方面具有先天的优越性,是当今业界最主流的 Web 开发框架,最热门的开发技能。
-
区别
-
Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截, 一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现 restful url,而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url, 而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
-
SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取, 处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的, 但其所有Action变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦, 每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
-
Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map, 供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
-
拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式, 这样导致Struts2的配置文件量还是比SpringMVC大。
-
SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。 以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
-
SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可, 而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去, 使用起来也相对不方便。
-
SpringMVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。
-
SpringMVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高( 当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。
-
SpringMVC开发效率和性能高于Struts2。
-
SpringMVC可以认为已经100%零配置
-
2、SpringMVC
2.1 主要组件
-
前端控制器(DispatcherServlet)
用户请求达到前端控制器,它就相当于mvc模式的c,dispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户请求,dispatcherServlet的存在降低了组件之间的耦合性
-
请求处理器映射(HandlerMapping)
根据用户请求找到Handler,即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
-
处理器适配(HandlerAdapter)
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
-
处理器(Handler)
开发中要编写的具体业务控制器,由DispatcherServlet把用户请求转发到Handler,由Handler对具体的用户请求进行处理
-
视图解析器(ViewResolver)
ViewResolver负责将处理结果生成view视图。首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户
-
视图(View)
SpringMVC提供了很多view视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
2.2 工作流程
-
用户通过浏览器发起 HttpRequest 请求到前端控制器 (DispatcherServlet),前端控制器是所有请求的入口,但前端控制器不能处理业务请求,它只是一个请求的转发。
-
谁来处理业务请求呢?Handler处理器来真正处理业务请求,那么问题来了,前端控制器如何来找到这个Handler处理器呢?处理器映射器记录的就是请求的url和处理的方法之间的映射关系,这个映射关系是怎么建立起来的呢?就是通过@RequestMapping这个注解来建立起来的,这个映射关系就相当于一个Map(key-value这种形式),key就是请求的url,value就是处理的Handler。现在,DispatcherServlet 将用户请求发送给处理器映射器 (HandlerMapping)
-
处理器映射器会根据你请求的url来找对应的处理器,找不到就会报错,如果找到之后,这时,它就会返回一个处理器执行链,这个处理器执行链里面除了有Handler之外,还有拦截器(这儿我们可以开发自己的拦截器),然后返回给前端控制器。
-
前端控制器依然不能处理这个业务请求,它这时做的还有另外一件事情,因为返回Handler,它也不知道这个Handler是什么类型,因为在spring mvc中Handler除了可以是注解形式的之外,其实还可以是非注解形式的(非注解形式我们一般不用),前端控制器并不知道这个Handler到底是什么类型的,那就没办法执行它,那总得找个东西执行,这时它就会把这个事交给另外一个组件来处理,这个组件就叫处理器适配器,这个处理器适配器就是来适配不同类型的Handler。它就会根据你不同类型的Handler来选择不同类型的适配器来执行它。
-
假如当前Handler是注解形式的,那么它就会选择注解形式的处理器适配器来执行这个Handler。Handler就执行了,也就是说我们Controller类中的那个方法就执行了,方法执行之后,里面的业务就处理了。
-
业务处理之后,最后返回一个ModelAndView。处理器适配器拿到这个结果是没有用的,它的作用就是执行这个Handler,把这个Handler执行完之后,它的事就做完了。
-
做完之后,拿到这个返回结果,那么它会原封不动地把这个返回结果扔给前端控制器,这时处理器适配器的事就做完了。
-
前端控制器拿到这个ModelAndView,它还是没有办法处理,它还是不能返回html,这时它要找到相应的jsp,因为ModelAndView即包含模型又包含视图,这个视图指定我们要用谁来渲染这个数据。我们要渲染数据,这时它就要找一个视图解析器来解析这个视图,由于这个视图也有很多种(我们最常见的视图是jsp,除了jsp,其实还有其他的,比如说还可以是报表,还可以是pdf,还可以是freemaker等),它会找不同的视图解析器来处理。因为现在我们最常用的视图是jsp,所以它就找到jsp对应的视图解析器。
-
找到这个视图解析器,它来把这个视图解析,解析完了之后它会返回一个View对象。
-
最后我们再调用这个视图解析器的渲染视图这个过程,渲染视图这个过程其实就是对于我们的jsp来说,就是把这个数据渲染成html。
-
最终渲染成html之后,就响应给用户。
3、SpringMVC的使用
3.1 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
3.2 配置web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 配置spring mvc的核心控制器 -->
<servlet>
<servlet-name>SpringMVCDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,用于读取SpringMVC的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet的对象创建的时间点:应用加载时创建。
如果该元素的值为负数或者没有设置,则容器会当servlet被请求的时候加载。
如果值为正整数时或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,越先被加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 所有的请求都会执行对应的这个方法 -->
<servlet-mapping>
<servlet-name>SpringMVCDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.3 配置springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<!-- 配置创建 spring 容器要扫描的包 -->
<context:component-scan base-package="com.company"></context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
学习后端服务器语言:
1.怎么配置接口路径 √
2.怎么编写请求方法 √
3.怎么获取参数 √
4.怎么响应数据 √
3.4 编写controller
-
@RequestMapping注解
建立请求URL和处理方法之间的对应关系
-
作用到类上:第一级访问路径
-
作用到方法上:第二级访问路径
-
// 当用户请求路径的时候,对应的方法就会被执行
// 路径的匹配方式是一级路径+二级路径
@Controller
@RequestMapping("/user") // 配置一级路径
public class UserController {
@RequestMapping({"/queryAll"}) // 配置二级路径,
public void queryAll() {
System.out.println(getClass().getName() + " queryAll");
}
@RequestMapping("/create")
public void create() {
System.out.println(getClass().getName() + " create");
}
@RequestMapping() // 二级路径也可以不写
public void user() {
System.out.println(getClass().getName() + " user");
}
}
3.5 请求类型设置
3.5.1 GET请求
-
@GetMapping
@GetMapping("/delete")
-
@RequestMapping的method属性(也可以不配置,默认就是GET)
@RequestMapping(value = "/update", method = RequestMethod.GET) public void update() { System.out.println(getClass().getName() + " update"); }
3.5.2 POST请求
-
@PostMapping
@PostMapping("/delete")
-
@RequestMapping的method属性
@RequestMapping(value = "/update", method = RequestMethod.POST) public void update() { System.out.println(getClass().getName() + " update"); }
3.6 获取参数
3.6.1 配置过滤器解决post请求中文乱码 web.xml
<!--配置解决中文乱码过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--初始化参数-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.6.2 通过HttpServletRequest参数获取
@GetMapping
public void query(HttpServletRequest req) {
System.out.println(req.getParameter("name"));
}
3.6.3 直接在方法上定义形参
参数要和前端传的参数名一样
@GetMapping("/create")
public void query(String name, Integer age) {
System.out.println(name);
System.out.println(age);
}
// 也可以手动指定
// 如果@RequestParam指定的参数默认是必须传的,如果没有会报错,需要加上个required=false
@GetMapping("/create")
public void query(String name, @RequestParam(value = "sex", required = false) Integer age) {
System.out.println(name);
System.out.println(age);
}
3.6.4 使用实体类接收
参数名和属性名匹配,会自动赋值
@PostMapping("/update")
public void query(Student s) {
System.out.println(s.getName());
System.out.println(s.getId());
System.out.println(s.getSex());
}
3.6.5 从路径获取
@GetMapping("/delete/{name}") // 表示一个动态的值
public void query(@PathVariable String name) {
System.out.println(name);
}
3.7 Restful风格规范
Restful 一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制
增、删、改、查分别和POST、DELETE、PUT、GET
-
传统写法
增:xxx/user/create post
删:xxx/user/delete get
改:xxx/user/update post
查:xxx/user/query post/get
-
Restful风格
增:xxx/user post
删:xxx/user delete
改:xxx/user put
查:xxx/user get
@GetMapping() public void user() {} @PutMapping() public void update() {} @DeleteMapping() public void delete() {}
4、小结
本章节我们学习了MVC三层模型、理解了什么是SpringMVC、SpringMVC的工作流程、学会使用SpringMVC封装不同请求、接收参数,可以发现使用SpringMVC写一个接口可以使用javaWeb方便多了,所以这也是为什么SSM比较流行的一个原因之一了。
下移章节我们将会对SpringMVC的后续内容继续学习,掌握SpringMVC的开发方式。